Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ Select [CURL options](https://curl.se/libcurl/c/curl_easy_setopt.html) are avail
* [CURLOPT_CONNECTTIMEOUT](https://curl.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html)
* [CURLOPT_CONNECTTIMEOUT_MS](https://curl.se/libcurl/c/CURLOPT_CONNECTTIMEOUT_MS.html)
* [CURLOPT_DNS_SERVERS](https://curl.se/libcurl/c/CURLOPT_DNS_SERVERS.html)
* [CURLOPT_HTTPAUTH](https://curl.se/libcurl/c/CURLOPT_HTTPAUTH.html)
* [CURLOPT_PRE_PROXY](https://curl.se/libcurl/c/CURLOPT_PRE_PROXY.html)
* [CURLOPT_PROXY](https://curl.se/libcurl/c/CURLOPT_PROXY.html)
* [CURLOPT_PROXYPASSWORD](https://curl.se/libcurl/c/CURLOPT_PROXYPASSWORD.html)
Expand Down
27 changes: 27 additions & 0 deletions expected/http.out
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,30 @@ SELECT round(extract(epoch FROM now() - start) * 10) AS m
(1 row)

DROP TABLE timer;
SELECT http_set_curlopt('CURLOPT_HTTPAUTH', 'CURLAUTH_NEGOTIATE');
http_set_curlopt
------------------
t
(1 row)

SHOW http.CURLOPT_HTTPAUTH;
http.curlopt_httpauth
-----------------------
CURLAUTH_NEGOTIATE
(1 row)

RESET http.CURLOPT_HTTPAUTH;
SHOW http.CURLOPT_HTTPAUTH;
http.curlopt_httpauth
-----------------------

(1 row)

SELECT http_set_curlopt('CURLOPT_HTTPAUTH', 'DOES_NOT_EXIST');
ERROR: curl httpauth option 'DOES_NOT_EXIST' invalid
SHOW http.CURLOPT_HTTPAUTH;
http.curlopt_httpauth
-----------------------

(1 row)

93 changes: 91 additions & 2 deletions http.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,42 @@ typedef enum {
typedef enum {
CURLOPT_STRING,
CURLOPT_LONG,
CURLOPT_BLOB
CURLOPT_BLOB,
CURLOPT_LONG_BITMASK
} http_curlopt_type;

/* CURLOPT_HTTPAUTH string/enum value mapping */
typedef struct {
char *str;
unsigned long val;
} http_curlopt_auth;

/* CURLOPT_HTTPAUTH values we allow user to set at run-time */
static http_curlopt_auth settable_curlopts_auth[] = {
{ "CURLAUTH_BASIC", CURLAUTH_BASIC },
{ "CURLAUTH_DIGEST", CURLAUTH_DIGEST },
{ "CURLAUTH_NEGOTIATE", CURLAUTH_NEGOTIATE },
{ "CURLAUTH_NTLM", CURLAUTH_NTLM },
{ "CURLAUTH_ANY", CURLAUTH_ANY },
{ "CURLAUTH_ANYSAFE", CURLAUTH_ANYSAFE },
#if LIBCURL_VERSION_NUM >= 0x071303 /* 7.19.3 */
{ "CURLAUTH_DIGEST_IE", CURLAUTH_DIGEST_IE },
#endif
#if LIBCURL_VERSION_NUM >= 0x071503 /* 7.21.3 */
{ "CURLAUTH_ONLY", CURLAUTH_ONLY },
#endif
#if LIBCURL_VERSION_NUM >= 0x071600 /* 7.22.0 */
{ "CURLAUTH_NTLM_WB", CURLAUTH_NTLM_WB },
#endif
#if LIBCURL_VERSION_NUM >= 0x073D00 /* 7.61.0 */
{ "CURLAUTH_BEARER", CURLAUTH_BEARER },
#endif
#if LIBCURL_VERSION_NUM >= 0x074a00 /* 7.74.0 */
{ "CURLAUTH_AWS_SIGV4", CURLAUTH_AWS_SIGV4 },
#endif
{ NULL, 0 },
};

/* CURLOPT string/enum value mapping */
typedef struct {
CURLoption curlopt;
Expand All @@ -156,7 +189,6 @@ typedef struct {
char *curlopt_guc;
} http_curlopt;


/* CURLOPT values we allow user to set at run-time */
/* Be careful adding these, as they can be a security risk */
static http_curlopt settable_curlopts[] = {
Expand All @@ -171,6 +203,9 @@ static http_curlopt settable_curlopts[] = {
#if LIBCURL_VERSION_NUM >= 0x070903 /* 7.9.3 */
{ CURLOPT_SSLCERTTYPE, CURLOPT_STRING, false, "CURLOPT_SSLCERTTYPE", NULL, NULL },
#endif
#if LIBCURL_VERSION_NUM >= 0x070a06 /* 7.10.6 */
{ CURLOPT_HTTPAUTH, CURLOPT_LONG_BITMASK, false, "CURLOPT_HTTPAUTH", NULL, NULL },
#endif
#if LIBCURL_VERSION_NUM >= 0x070e01 /* 7.14.1 */
{ CURLOPT_PROXY, CURLOPT_STRING, false, "CURLOPT_PROXY", NULL, NULL },
{ CURLOPT_PROXYPORT, CURLOPT_LONG, false, "CURLOPT_PROXYPORT", NULL, NULL },
Expand Down Expand Up @@ -957,6 +992,39 @@ set_curlopt(CURL* handle, const http_curlopt *opt)
err = curl_easy_setopt(handle, opt->curlopt, &blob);
elog(DEBUG2, "pgsql-http: set '%s' to value '%s', return value = %d", opt->curlopt_guc, opt->curlopt_val, err);
}
#endif
#if LIBCURL_VERSION_NUM >= 0x070a06 /* 7.10.6 */
/* Only used for CURLOPT_HTTPAUTH */
else if (opt->curlopt_type == CURLOPT_LONG_BITMASK)
{
if (opt->curlopt == CURLOPT_HTTPAUTH)
{
http_curlopt_auth *opt_auth = settable_curlopts_auth;
bool curlopt_httpauth_found = false;
while (opt_auth->str)
{
if (strcasecmp(opt_auth->str, opt->curlopt_val) == 0)
{

err = curl_easy_setopt(handle, opt->curlopt, opt_auth->val);
curlopt_httpauth_found = true;
break;
}

opt_auth++;
}
if (!curlopt_httpauth_found)
{
elog(ERROR, "invalid curl httpauth option, '%s'", opt->curlopt_val);
return false;
}
}
else
{
/* Never get here */
elog(ERROR, "curl option '%d' is not available for run-time configuration", opt->curlopt);
}
}
#endif
else
{
Expand Down Expand Up @@ -1123,6 +1191,27 @@ Datum http_set_curlopt(PG_FUNCTION_ARGS)
{
if (strcasecmp(opt->curlopt_str, curlopt) == 0)
{
if (opt->curlopt == CURLOPT_HTTPAUTH)
{
http_curlopt_auth *opt_auth = settable_curlopts_auth;
bool curlopt_httpauth_found = false;
while (opt_auth->str)
{
if (strcasecmp(opt_auth->str, value) == 0)
{
curlopt_httpauth_found = true;
break;
}
opt_auth++;
}
if (!curlopt_httpauth_found)
{
elog(ERROR, "curl httpauth option '%s' invalid", value);
PG_RETURN_BOOL(false);
}

}

if (opt->curlopt_val) guc_free(opt->curlopt_val);
opt->curlopt_val = guc_strdup(ERROR, value);
PG_RETURN_BOOL(set_curlopt(handle, opt));
Expand Down
12 changes: 12 additions & 0 deletions sql/http.sql
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,15 @@ SELECT *
SELECT round(extract(epoch FROM now() - start) * 10) AS m
FROM timer;
DROP TABLE timer;

SELECT http_set_curlopt('CURLOPT_HTTPAUTH', 'CURLAUTH_NEGOTIATE');

SHOW http.CURLOPT_HTTPAUTH;

RESET http.CURLOPT_HTTPAUTH;

SHOW http.CURLOPT_HTTPAUTH;

SELECT http_set_curlopt('CURLOPT_HTTPAUTH', 'DOES_NOT_EXIST');

SHOW http.CURLOPT_HTTPAUTH;