4646#include <miscadmin.h>
4747#include <access/genam.h>
4848#include <access/htup.h>
49+ #include <access/htup_details.h>
4950#include <access/sysattr.h>
5051#include <catalog/namespace.h>
5152#include <catalog/pg_type.h>
6667#include <utils/fmgroids.h>
6768#include <utils/guc.h>
6869
69- #if PG_VERSION_NUM >= 90300
70- # include <access/htup_details.h>
71- #endif
7270
7371#if PG_VERSION_NUM >= 100000
7472# include <utils/varlena.h>
@@ -243,7 +241,9 @@ http_progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl
243241
244242#endif /* 7.39.0 */
245243
246- #undef HTTP_MEM_CALLBACKS
244+ //#undef HTTP_MEM_CALLBACKS
245+ //xxxxxx
246+ #define HTTP_MEM_CALLBACKS
247247#ifdef HTTP_MEM_CALLBACKS
248248static void *
249249http_calloc (size_t a , size_t b )
@@ -947,13 +947,35 @@ set_curlopt(CURL* handle, const http_curlopt *opt)
947947 return true;
948948}
949949
950+ static void
951+ http_close_handle (CURL * handle )
952+ {
953+ if (handle != g_http_handle )
954+ elog (ERROR ,
955+ "%s called with invalid curl handle, g_http_handle(%p) != handle(%p)" ,
956+ __func__ , g_http_handle , handle );
957+ curl_easy_cleanup (handle );
958+ g_http_handle = NULL ;
959+ }
960+
961+ static void
962+ http_reset_handle (CURL * handle )
963+ {
964+ MemoryContext oldcontext ;
965+ if (!handle ) return ;
966+ oldcontext = MemoryContextSwitchTo (TopMemoryContext );
967+ curl_easy_reset (handle );
968+ MemoryContextSwitchTo (oldcontext );
969+ }
970+
950971/* Check/create the global CURL* handle */
951972static CURL *
952- http_get_handle ()
973+ http_open_handle ()
953974{
954975 CURL * handle = g_http_handle ;
955976 http_curlopt * opt = settable_curlopts ;
956977
978+ MemoryContext oldcontext = MemoryContextSwitchTo (TopMemoryContext );
957979 /* Initialize the global handle if needed */
958980 if (!handle )
959981 {
@@ -965,6 +987,7 @@ http_get_handle()
965987 {
966988 curl_easy_reset (handle );
967989 }
990+ MemoryContextSwitchTo (oldcontext );
968991
969992 /* Always want a default fast (1 second) connection timeout */
970993 /* User can over-ride with http_set_curlopt() if they wish */
@@ -1000,8 +1023,8 @@ Datum http_reset_curlopt(PG_FUNCTION_ARGS)
10001023{
10011024 http_curlopt * opt = settable_curlopts ;
10021025 /* Set up global HTTP handle */
1003- CURL * handle = http_get_handle ();
1004- curl_easy_reset (handle );
1026+ CURL * handle = http_open_handle ();
1027+ http_reset_handle (handle );
10051028
10061029 /* Clean out the settable_curlopts global cache */
10071030 while (opt -> curlopt )
@@ -1089,7 +1112,7 @@ Datum http_set_curlopt(PG_FUNCTION_ARGS)
10891112 PG_RETURN_BOOL (false);
10901113
10911114 /* Set up global HTTP handle */
1092- handle = http_get_handle ();
1115+ handle = http_open_handle ();
10931116
10941117 /* Read arguments */
10951118 curlopt_txt = PG_GETARG_TEXT_P (0 );
@@ -1136,6 +1159,7 @@ Datum http_request(PG_FUNCTION_ARGS)
11361159 http_method method ;
11371160
11381161 /* Processing */
1162+ CURL * handle ;
11391163 CURLcode err ;
11401164 char http_error_buffer [CURL_ERROR_SIZE ] = "\0" ;
11411165
@@ -1204,58 +1228,58 @@ Datum http_request(PG_FUNCTION_ARGS)
12041228 elog (DEBUG2 , "pgsql-http: method_str: '%s', method: %d" , method_str , method );
12051229
12061230 /* Set up global HTTP handle */
1207- g_http_handle = http_get_handle ();
1231+ handle = http_open_handle ();
12081232
12091233 /* Set up the error buffer */
1210- CURL_SETOPT (g_http_handle , CURLOPT_ERRORBUFFER , http_error_buffer );
1234+ CURL_SETOPT (handle , CURLOPT_ERRORBUFFER , http_error_buffer );
12111235
12121236 /* Set the target URL */
1213- CURL_SETOPT (g_http_handle , CURLOPT_URL , uri );
1237+ CURL_SETOPT (handle , CURLOPT_URL , uri );
12141238
12151239
12161240 /* Restrict to just http/https. Leaving unrestricted */
12171241 /* opens possibility of users requesting file:/// urls */
12181242 /* locally */
12191243#if LIBCURL_VERSION_NUM >= 0x075400 /* 7.84.0 */
1220- CURL_SETOPT (g_http_handle , CURLOPT_PROTOCOLS_STR , "http,https" );
1244+ CURL_SETOPT (handle , CURLOPT_PROTOCOLS_STR , "http,https" );
12211245#else
1222- CURL_SETOPT (g_http_handle , CURLOPT_PROTOCOLS , CURLPROTO_HTTP | CURLPROTO_HTTPS );
1246+ CURL_SETOPT (handle , CURLOPT_PROTOCOLS , CURLPROTO_HTTP | CURLPROTO_HTTPS );
12231247#endif
12241248
12251249 if ( curlopt_is_set (CURLOPT_TCP_KEEPALIVE ) )
12261250 {
12271251 /* Keep sockets held open */
1228- CURL_SETOPT (g_http_handle , CURLOPT_FORBID_REUSE , 0 );
1252+ CURL_SETOPT (handle , CURLOPT_FORBID_REUSE , 0 );
12291253 }
12301254 else
12311255 {
12321256 /* Keep sockets from being held open */
1233- CURL_SETOPT (g_http_handle , CURLOPT_FORBID_REUSE , 1 );
1257+ CURL_SETOPT (handle , CURLOPT_FORBID_REUSE , 1 );
12341258 }
12351259
12361260 /* Set up the write-back function */
1237- CURL_SETOPT (g_http_handle , CURLOPT_WRITEFUNCTION , http_writeback );
1261+ CURL_SETOPT (handle , CURLOPT_WRITEFUNCTION , http_writeback );
12381262
12391263 /* Set up the write-back buffer */
12401264 initStringInfo (& si_data );
12411265 initStringInfo (& si_headers );
1242- CURL_SETOPT (g_http_handle , CURLOPT_WRITEDATA , (void * )(& si_data ));
1243- CURL_SETOPT (g_http_handle , CURLOPT_WRITEHEADER , (void * )(& si_headers ));
1266+ CURL_SETOPT (handle , CURLOPT_WRITEDATA , (void * )(& si_data ));
1267+ CURL_SETOPT (handle , CURLOPT_WRITEHEADER , (void * )(& si_headers ));
12441268
12451269#if LIBCURL_VERSION_NUM >= 0x072700 /* 7.39.0 */
12461270 /* Connect the progress callback for interrupt support */
1247- CURL_SETOPT (g_http_handle , CURLOPT_XFERINFOFUNCTION , http_progress_callback );
1248- CURL_SETOPT (g_http_handle , CURLOPT_NOPROGRESS , 0 );
1271+ CURL_SETOPT (handle , CURLOPT_XFERINFOFUNCTION , http_progress_callback );
1272+ CURL_SETOPT (handle , CURLOPT_NOPROGRESS , 0 );
12491273#endif
12501274
12511275 /* Set the HTTP content encoding to all curl supports */
1252- CURL_SETOPT (g_http_handle , CURLOPT_ACCEPT_ENCODING , "" );
1276+ CURL_SETOPT (handle , CURLOPT_ACCEPT_ENCODING , "" );
12531277
12541278 if ( method != HTTP_HEAD )
12551279 {
12561280 /* Follow redirects, as many as 5 */
1257- CURL_SETOPT (g_http_handle , CURLOPT_FOLLOWLOCATION , 1 );
1258- CURL_SETOPT (g_http_handle , CURLOPT_MAXREDIRS , 5 );
1281+ CURL_SETOPT (handle , CURLOPT_FOLLOWLOCATION , 1 );
1282+ CURL_SETOPT (handle , CURLOPT_MAXREDIRS , 5 );
12591283 }
12601284
12611285 if ( curlopt_is_set (CURLOPT_TCP_KEEPALIVE ) )
@@ -1304,36 +1328,36 @@ Datum http_request(PG_FUNCTION_ARGS)
13041328 if ( method == HTTP_GET || method == HTTP_POST || method == HTTP_DELETE )
13051329 {
13061330 /* Add the content to the payload */
1307- CURL_SETOPT (g_http_handle , CURLOPT_POST , 1 );
1331+ CURL_SETOPT (handle , CURLOPT_POST , 1 );
13081332 if ( method == HTTP_GET )
13091333 {
13101334 /* Force the verb to be GET */
1311- CURL_SETOPT (g_http_handle , CURLOPT_CUSTOMREQUEST , "GET" );
1335+ CURL_SETOPT (handle , CURLOPT_CUSTOMREQUEST , "GET" );
13121336 }
13131337 else if ( method == HTTP_DELETE )
13141338 {
13151339 /* Force the verb to be DELETE */
1316- CURL_SETOPT (g_http_handle , CURLOPT_CUSTOMREQUEST , "DELETE" );
1340+ CURL_SETOPT (handle , CURLOPT_CUSTOMREQUEST , "DELETE" );
13171341 }
13181342
1319- CURL_SETOPT (g_http_handle , CURLOPT_POSTFIELDS , (char * )(VARDATA (content_text )));
1320- CURL_SETOPT (g_http_handle , CURLOPT_POSTFIELDSIZE , content_size );
1343+ CURL_SETOPT (handle , CURLOPT_POSTFIELDS , (char * )(VARDATA (content_text )));
1344+ CURL_SETOPT (handle , CURLOPT_POSTFIELDSIZE , content_size );
13211345 }
13221346 else if ( method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_UNKNOWN )
13231347 {
13241348 if ( method == HTTP_PATCH )
1325- CURL_SETOPT (g_http_handle , CURLOPT_CUSTOMREQUEST , "PATCH" );
1349+ CURL_SETOPT (handle , CURLOPT_CUSTOMREQUEST , "PATCH" );
13261350
13271351 /* Assume the user knows what they are doing and pass unchanged */
13281352 if ( method == HTTP_UNKNOWN )
1329- CURL_SETOPT (g_http_handle , CURLOPT_CUSTOMREQUEST , method_str );
1353+ CURL_SETOPT (handle , CURLOPT_CUSTOMREQUEST , method_str );
13301354
13311355 initStringInfo (& si_read );
13321356 appendBinaryStringInfo (& si_read , VARDATA (content_text ), content_size );
1333- CURL_SETOPT (g_http_handle , CURLOPT_UPLOAD , 1 );
1334- CURL_SETOPT (g_http_handle , CURLOPT_READFUNCTION , http_readback );
1335- CURL_SETOPT (g_http_handle , CURLOPT_READDATA , & si_read );
1336- CURL_SETOPT (g_http_handle , CURLOPT_INFILESIZE , content_size );
1357+ CURL_SETOPT (handle , CURLOPT_UPLOAD , 1 );
1358+ CURL_SETOPT (handle , CURLOPT_READFUNCTION , http_readback );
1359+ CURL_SETOPT (handle , CURLOPT_READDATA , & si_read );
1360+ CURL_SETOPT (handle , CURLOPT_INFILESIZE , content_size );
13371361 }
13381362 else
13391363 {
@@ -1343,11 +1367,11 @@ Datum http_request(PG_FUNCTION_ARGS)
13431367 }
13441368 else if ( method == HTTP_DELETE )
13451369 {
1346- CURL_SETOPT (g_http_handle , CURLOPT_CUSTOMREQUEST , "DELETE" );
1370+ CURL_SETOPT (handle , CURLOPT_CUSTOMREQUEST , "DELETE" );
13471371 }
13481372 else if ( method == HTTP_HEAD )
13491373 {
1350- CURL_SETOPT (g_http_handle , CURLOPT_NOBODY , 1 );
1374+ CURL_SETOPT (handle , CURLOPT_NOBODY , 1 );
13511375 }
13521376 else if ( method == HTTP_PUT || method == HTTP_POST )
13531377 {
@@ -1356,17 +1380,17 @@ Datum http_request(PG_FUNCTION_ARGS)
13561380 }
13571381 else if ( method == HTTP_UNKNOWN ){
13581382 /* Assume the user knows what they are doing and pass unchanged */
1359- CURL_SETOPT (g_http_handle , CURLOPT_CUSTOMREQUEST , method_str );
1383+ CURL_SETOPT (handle , CURLOPT_CUSTOMREQUEST , method_str );
13601384 }
13611385
13621386 pfree (method_str );
13631387 /* Set the headers */
1364- CURL_SETOPT (g_http_handle , CURLOPT_HTTPHEADER , headers );
1388+ CURL_SETOPT (handle , CURLOPT_HTTPHEADER , headers );
13651389
13661390 /*************************************************************************
13671391 * PERFORM THE REQUEST!
13681392 **************************************************************************/
1369- http_return = curl_easy_perform (g_http_handle );
1393+ http_return = curl_easy_perform (handle );
13701394 elog (DEBUG2 , "pgsql-http: queried '%s'" , uri );
13711395 elog (DEBUG2 , "pgsql-http: http_return '%d'" , http_return );
13721396
@@ -1383,8 +1407,7 @@ Datum http_request(PG_FUNCTION_ARGS)
13831407 if ( http_return != CURLE_OK )
13841408 {
13851409 curl_slist_free_all (headers );
1386- curl_easy_cleanup (g_http_handle );
1387- g_http_handle = NULL ;
1410+ http_close_handle (handle );
13881411
13891412#if LIBCURL_VERSION_NUM >= 0x072700 /* 7.39.0 */
13901413 /*
@@ -1399,12 +1422,11 @@ Datum http_request(PG_FUNCTION_ARGS)
13991422 }
14001423
14011424 /* Read the metadata from the handle directly */
1402- if ( (CURLE_OK != curl_easy_getinfo (g_http_handle , CURLINFO_RESPONSE_CODE , & long_status )) ||
1403- (CURLE_OK != curl_easy_getinfo (g_http_handle , CURLINFO_CONTENT_TYPE , & content_type )) )
1425+ if ( (CURLE_OK != curl_easy_getinfo (handle , CURLINFO_RESPONSE_CODE , & long_status )) ||
1426+ (CURLE_OK != curl_easy_getinfo (handle , CURLINFO_CONTENT_TYPE , & content_type )) )
14041427 {
14051428 curl_slist_free_all (headers );
1406- curl_easy_cleanup (g_http_handle );
1407- g_http_handle = NULL ;
1429+ http_close_handle (handle );
14081430 ereport (ERROR , (errmsg ("CURL: Error in curl_easy_getinfo" )));
14091431 }
14101432
@@ -1507,8 +1529,7 @@ Datum http_request(PG_FUNCTION_ARGS)
15071529 ReleaseTupleDesc (tup_desc );
15081530 if ( ! curlopt_is_set (CURLOPT_TCP_KEEPALIVE ) )
15091531 {
1510- curl_easy_cleanup (g_http_handle );
1511- g_http_handle = NULL ;
1532+ http_close_handle (handle );
15121533 }
15131534 curl_slist_free_all (headers );
15141535 pfree (si_headers .data );
0 commit comments