Skip to content

Commit 8558e5f

Browse files
committed
feat: omit content-type and support headers
1 parent 6ecba6a commit 8558e5f

File tree

2 files changed

+52
-36
lines changed

2 files changed

+52
-36
lines changed

sql/pg_net--0.1.sql

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ create table net.http_request_queue(
1414
url text not null,
1515
params jsonb not null,
1616
headers jsonb not null,
17-
content_type text,
1817
body bytea,
1918
timeout_milliseconds int not null,
2019
-- Available for delete after this date
@@ -91,8 +90,8 @@ declare
9190
request_id bigint;
9291
begin
9392
-- Add to the request queue
94-
insert into net.http_request_queue(method, url, params, headers, content_type, body, timeout_milliseconds, delete_after)
95-
values ('GET', url, params, headers, null, null, timeout_milliseconds, timezone('utc', now()) + ttl)
93+
insert into net.http_request_queue(method, url, params, headers, timeout_milliseconds, delete_after)
94+
values ('GET', url, params, headers, timeout_milliseconds, timezone('utc', now()) + ttl)
9695
returning id
9796
into request_id;
9897

@@ -105,20 +104,17 @@ $$;
105104
create or replace function net.http_post(
106105
-- url for the request
107106
url text,
108-
-- ContentType of the POST request
109-
content_type text,
110107
-- body of the POST request
111108
body bytea,
112109
-- key/value pairs to be url encoded and appended to the `url`
113110
params jsonb DEFAULT '{}'::jsonb,
114111
-- key/values to be included in request headers
112+
-- by default curl uses "Content-Type: application/x-www-form-urlencoded"
115113
headers jsonb DEFAULT '{}'::jsonb,
116114
-- the maximum number of milliseconds the request may take before being cancelled
117115
timeout_milliseconds int DEFAULT 1000,
118116
-- the minimum amount of time the response should be persisted
119-
ttl interval default '3 days',
120-
-- when `true`, return immediately. when `false` wait for the request to complete before returning
121-
async bool default true
117+
ttl interval default '3 days'
122118
)
123119
-- request_id reference
124120
returns bigint
@@ -129,21 +125,13 @@ create or replace function net.http_post(
129125
as $$
130126
declare
131127
request_id bigint;
132-
respone_rec net.http_response;
133128
begin
134129
-- Add to the request queue
135-
insert into net.http_request_queue(method, url, params, headers, content_type, body, timeout_milliseconds, delete_after)
136-
values ('POST', url, params, headers, content_type, body, timeout_milliseconds, timezone('utc', now()) + ttl)
130+
insert into net.http_request_queue(method, url, params, headers, body, timeout_milliseconds, delete_after)
131+
values ('POST', url, params, headers, body, timeout_milliseconds, timezone('utc', now()) + ttl)
137132
returning id
138133
into request_id;
139134

140-
-- If request is async, return id immediately
141-
if async then
142-
return request_id;
143-
end if;
144-
145-
-- If sync, wait for the request to complete before returning
146-
perform net._await_response(request_id);
147135
return request_id;
148136
end
149137
$$;

src/worker.c

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,30 @@ header_cb(void *contents, size_t size, size_t nmemb, void *userp)
103103
return realsize;
104104
}
105105

106-
static int init(CURLM *cm, char *method, char *url, char *contentType, char *reqBody, int64 id, HTAB *curlDataMap)
106+
static struct curl_slist *
107+
header_array_to_slist(ArrayType *array, struct curl_slist *headers)
108+
{
109+
ArrayIterator iterator;
110+
Datum value;
111+
bool isnull;
112+
char *header;
113+
114+
iterator = array_create_iterator(array, 0, NULL);
115+
116+
while (array_iterate(iterator, &value, &isnull))
117+
{
118+
if (isnull) continue;
119+
120+
header = TextDatumGetCString(value);
121+
elog(DEBUG1, "Request header \"%s\"\n", header);
122+
headers = curl_slist_append(headers, header);
123+
}
124+
array_free_iterator(iterator);
125+
126+
return headers;
127+
}
128+
129+
static int init(CURLM *cm, char *method, char *url, struct curl_slist *reqHeaders, char *reqBody, int64 id, HTAB *curlDataMap)
107130
{
108131
CURL *eh = curl_easy_init();
109132

@@ -121,11 +144,7 @@ static int init(CURLM *cm, char *method, char *url, char *contentType, char *req
121144
cdata->headers = headers;
122145
}
123146

124-
if (contentType) {
125-
struct curl_slist *reqHeaders = NULL;
126-
reqHeaders = curl_slist_append(reqHeaders, contentType);
127-
curl_easy_setopt(eh, CURLOPT_HTTPHEADER, reqHeaders);
128-
}
147+
reqHeaders = curl_slist_append(reqHeaders, "User-Agent: pg_net/0.0.1");
129148

130149
if (strcasecmp(method, "GET") == 0) {
131150
if (reqBody) {
@@ -146,8 +165,9 @@ static int init(CURLM *cm, char *method, char *url, char *contentType, char *req
146165
curl_easy_setopt(eh, CURLOPT_HEADERDATA, cdata->headers);
147166
curl_easy_setopt(eh, CURLOPT_HEADER, 0L);
148167
curl_easy_setopt(eh, CURLOPT_URL, url);
168+
curl_easy_setopt(eh, CURLOPT_HTTPHEADER, reqHeaders);
149169
curl_easy_setopt(eh, CURLOPT_PRIVATE, id);
150-
curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L);
170+
// curl_easy_setopt(eh, CURLOPT_VERBOSE, 1); // for debugging
151171
return curl_multi_add_handle(cm, eh);
152172
}
153173

@@ -224,7 +244,13 @@ worker_main(Datum main_arg)
224244

225245
appendStringInfo(&select_query, "\
226246
SELECT\
227-
q.id, q.method, q.url, q.content_type, q.body\
247+
q.id,\
248+
q.method,\
249+
q.url,\
250+
array(\
251+
select key || ': ' || value from jsonb_each_text(q.headers)\
252+
),\
253+
q.body\
228254
FROM net.http_request_queue q \
229255
LEFT JOIN net._http_response r ON q.id = r.id \
230256
WHERE r.id IS NULL");
@@ -243,35 +269,37 @@ worker_main(Datum main_arg)
243269

244270
for (int j = 0; j < SPI_processed; j++)
245271
{
246-
StringInfoData content_type;
272+
struct curl_slist *headers = NULL;
273+
// FIXME: Need to free headers, but only *after* curl_multi stuff during cleanup.
274+
// Maybe store in cdata?
275+
// curl_slist_free_all(headers);
247276

248277
int64 id = DatumGetInt64(SPI_getbinval(SPI_tuptable->vals[j], SPI_tuptable->tupdesc, 1, &tupIsNull));
249278
char *method = TextDatumGetCString(SPI_getbinval(SPI_tuptable->vals[j], SPI_tuptable->tupdesc, 2, &tupIsNull));
250279
char *url = TextDatumGetCString(SPI_getbinval(SPI_tuptable->vals[j], SPI_tuptable->tupdesc, 3, &tupIsNull));
251-
Datum contentTypeBin;
280+
281+
Datum headersBin;
252282
Datum bodyBin;
253-
char *contentType = NULL;
283+
ArrayType *pgHeaders;
254284
char *body = NULL;
255285

256-
contentTypeBin = SPI_getbinval(SPI_tuptable->vals[j], SPI_tuptable->tupdesc, 4, &tupIsNull);
286+
headersBin = SPI_getbinval(SPI_tuptable->vals[j], SPI_tuptable->tupdesc, 4, &tupIsNull);
257287
if (!tupIsNull) {
258-
initStringInfo(&content_type);
259-
appendStringInfo(&content_type, "Content-Type: %s", TextDatumGetCString(contentTypeBin));
260-
contentType = content_type.data;
288+
pgHeaders = DatumGetArrayTypeP(headersBin);
289+
headers = header_array_to_slist(pgHeaders, headers);
261290
}
262291
bodyBin = SPI_getbinval(SPI_tuptable->vals[j], SPI_tuptable->tupdesc, 5, &tupIsNull);
263292
if (!tupIsNull) body = TextDatumGetCString(bodyBin);
264293

265294
elog(DEBUG1, "Making a %s request to %s with id %ld", method, url, id);
266295

267-
res = init(cm, method, url, contentType, body, id, curlDataMap);
268-
269-
/* pfree(content_type.data); */
296+
res = init(cm, method, url, headers, body, id, curlDataMap);
270297

271298
if(res) {
272299
elog(ERROR, "error: init() returned %d\n", res);
273300
}
274301
res = curl_multi_perform(cm, &still_running);
302+
275303
if(res != CURLM_OK) {
276304
elog(ERROR, "error: curl_multi_perform() returned %d\n", res);
277305
}

0 commit comments

Comments
 (0)