Skip to content

Change response body from text to bytea #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ where `response` is a composite
```sql
status_code integer
headers jsonb
content text
body bytea
```

Possible values for `net.http_response_result.status` are `('PENDING', 'SUCCESS', 'ERROR')`
6 changes: 3 additions & 3 deletions sql/pg_net--0.1.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ create table net._http_response(
status_code integer,
content_type text,
headers jsonb,
content text,
body bytea,
timed_out bool,
error_msg text
);
Expand Down Expand Up @@ -146,7 +146,7 @@ create type net.request_status as enum ('PENDING', 'SUCCESS', 'ERROR');
create type net.http_response AS (
status_code integer,
headers jsonb,
content text
body bytea
);

-- State wrapper around responses
Expand Down Expand Up @@ -220,7 +220,7 @@ begin
(
rec.status_code,
rec.headers,
rec.content
rec.body
)::net.http_response
)::net.http_response_result;
end;
Expand Down
22 changes: 14 additions & 8 deletions src/worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ body_cb(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
StringInfo si = (StringInfo)userp;
appendBinaryStringInfo(si, (const char*)contents, (int)realsize);
appendBinaryStringInfoNT(si, (const char*)contents, (int)realsize);
return realsize;
}

Expand Down Expand Up @@ -318,7 +318,7 @@ worker_main(Datum main_arg)

initStringInfo(&query_insert_response_ok);
appendStringInfo(&query_insert_response_ok, "\
insert into net._http_response(id, status_code, content, headers, content_type, timed_out) values ($1, $2, $3, $4, $5, $6)");
insert into net._http_response(id, status_code, body, headers, content_type, timed_out) values ($1, $2, $3, $4, $5, $6)");

initStringInfo(&query_insert_response_bad);
appendStringInfo(&query_insert_response_bad, "\
Expand Down Expand Up @@ -353,6 +353,8 @@ worker_main(Datum main_arg)
false, 1) != SPI_OK_INSERT)
{
elog(ERROR, "SPI_exec failed: %s", query_insert_response_bad.data);


}
} else {
int argCount = 6;
Expand All @@ -362,6 +364,7 @@ worker_main(Datum main_arg)
CurlData *cdata = NULL;
char *contentType = NULL;
bool timedOut = false;
bytea *body_data = NULL;

curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &http_status_code);
curl_easy_getinfo(eh, CURLINFO_CONTENT_TYPE, &contentType);
Expand All @@ -379,12 +382,14 @@ worker_main(Datum main_arg)
argValues[1] = Int32GetDatum(http_status_code);
nulls[1] = ' ';

argTypes[2] = CSTRINGOID;
argValues[2] = CStringGetDatum(cdata->body->data);
if(cdata->body->data[0] == '\0')
nulls[2] = 'n';
else
nulls[2] = ' ';
argTypes[2] = BYTEAOID;

body_data = (bytea *) palloc(cdata->body->len + VARHDRSZ);
SET_VARSIZE(body_data, cdata->body->len + VARHDRSZ);
memcpy(VARDATA(body_data), cdata->body->data, cdata->body->len);
Comment on lines +387 to +389
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way of converting a char* to bytea is done in many parts of the postgres code(example).


argValues[2] = PointerGetDatum(body_data);
nulls[2] = ' ';

argTypes[3] = JSONBOID;
argValues[3] = JsonbPGetDatum(JsonbValueToJsonb(pushJsonbValue(&cdata->headers, WJB_END_OBJECT, NULL)));
Expand All @@ -409,6 +414,7 @@ worker_main(Datum main_arg)

pfree(cdata->body->data);
pfree(cdata->body);
pfree(body_data);
}

curl_multi_remove_handle(cm, eh);
Expand Down
30 changes: 30 additions & 0 deletions test/test_http_get_collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,33 @@ def test_http_collect_response_async_does_not_exist(sess):
assert response[0] == "ERROR"
assert "not found" in response[1]
assert response[2] is None


def test_http_get_returns_jsonb_body(sess):
"""Confirm bytea response body is deserializeable"""

# Create a request
(request_id,) = sess.execute(
"""
select net.http_get(url:='https://httpbin.org/anything');
"""
).fetchone()

# Commit so background worker can start
sess.commit()

# Collect the response, waiting as needed
(body,) = sess.execute(
text(
"""
select
encode((x.response).body, 'escape')::jsonb
from
net.http_collect_response(:request_id, async:=false) x;
"""
),
{"request_id": request_id},
).fetchone()

assert isinstance(body, dict)
assert "url" in body