Skip to content

Commit

Permalink
http: more deduplication of code, and capture content-length on parse…
Browse files Browse the repository at this point in the history
… without alloc
  • Loading branch information
gdamore committed Jan 10, 2025
1 parent 594f928 commit 6beab96
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 386 deletions.
21 changes: 5 additions & 16 deletions src/supplemental/http/http_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,11 @@ extern void nni_http_read_res(nni_http_conn *, nni_aio *);
extern void nni_http_read_req(nni_http_conn *, nni_aio *);
extern void nni_http_write_res(nni_http_conn *, nni_aio *);

extern const char *nni_http_req_get_header(const nni_http_req *, const char *);
extern const char *nni_http_res_get_header(const nni_http_res *, const char *);
extern int nni_http_req_add_header(nni_http_req *, const char *, const char *);
extern int nni_http_res_add_header(nni_http_res *, const char *, const char *);
extern int nni_http_req_set_header(nni_http_req *, const char *, const char *);
extern int nni_http_res_set_header(nni_http_res *, const char *, const char *);
extern int nni_http_req_del_header(nni_http_req *, const char *);
extern int nni_http_res_del_header(nni_http_res *, const char *);
extern int nni_http_res_set_data(nni_http_res *, const void *, size_t);
extern int nni_http_req_alloc_data(nni_http_req *, size_t);
extern int nni_http_res_alloc_data(nni_http_res *, size_t);
extern void nni_http_res_set_content_type(nni_http_res *, const char *);
extern void nni_http_req_set_content_type(nni_http_req *, const char *);

extern bool nni_http_res_is_error(nni_http_res *);

Expand Down Expand Up @@ -369,7 +361,7 @@ extern void nni_http_transact(
extern const char *nni_http_stream_scheme(const char *);

// Private method used for the server.
extern bool nni_http_conn_res_sent(nni_http_conn *conn);
extern bool nni_http_res_sent(nni_http_conn *conn);

extern const char *nni_http_get_version(nng_http *conn);
extern int nni_http_set_version(nng_http *conn, const char *vers);
Expand Down Expand Up @@ -399,17 +391,14 @@ extern int nni_http_set_uri(
extern const char *nni_http_get_uri(nng_http *conn);

extern void nni_http_set_host(nng_http *conn, const char *);
extern void nni_http_set_content_type(nng_http *conn, const char *);
extern void nni_http_conn_reset(nng_http *conn);
extern int nni_http_add_request_header(
extern int nni_http_add_header(
nng_http *conn, const char *key, const char *val);
extern int nni_http_set_request_header(
nng_http *conn, const char *key, const char *val);
extern int nni_http_add_response_header(
nng_http *conn, const char *key, const char *val);
extern int nni_http_set_response_header(
nng_http *conn, const char *key, const char *val);

extern void nni_http_set_static_header(
nng_http *conn, nni_http_header *header, const char *key, const char *val);

extern bool nni_http_parsed(nng_http *conn);

#endif // NNG_SUPPLEMENTAL_HTTP_HTTP_API_H
222 changes: 143 additions & 79 deletions src/supplemental/http/http_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,9 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
return (NNG_EAGAIN);

case HTTP_RD_REQ:
rv = nni_http_req_parse(conn, rbuf, cnt, &n);
conn->client = true;
rv = nni_http_req_parse(conn, rbuf, cnt, &n);
conn->client = false;
conn->rd_get += n;
if (conn->rd_get == conn->rd_put) {
conn->rd_get = conn->rd_put = 0;
Expand All @@ -233,7 +235,9 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
return (rv);

case HTTP_RD_RES:
rv = nni_http_res_parse(conn, rbuf, cnt, &n);
conn->client = false;
rv = nni_http_res_parse(conn, rbuf, cnt, &n);
conn->client = true;
conn->rd_get += n;
if (conn->rd_get == conn->rd_put) {
conn->rd_get = conn->rd_put = 0;
Expand Down Expand Up @@ -905,8 +909,7 @@ http_conn_set_error(nng_http *conn, uint16_t status, const char *reason,
body = content;
}
if (strlen(body) > 0) {
nni_http_set_static_header(conn, &conn->res.content_type,
"Content-Type", "text/html; charset=UTF-8");
nni_http_set_content_type(conn, "text/html; charset=UTF-8");
return (nni_http_copy_body(conn, body, strlen(body)));
}
return (0);

Check warning on line 915 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L915

Added line #L915 was not covered by tests
Expand Down Expand Up @@ -934,7 +937,7 @@ nni_http_set_redirect(
conn->res.location.value = loc;
conn->res.location.static_name = true;
conn->res.location.static_value = false;
nni_list_prepend(&conn->res.hdrs, &conn->res.location);
nni_list_prepend(&conn->res.data.hdrs, &conn->res.location);
return (http_conn_set_error(conn, status, reason, NULL, redirect));
}

Expand All @@ -950,7 +953,28 @@ nni_http_set_host(nng_http *conn, const char *host)
conn->req.host_header.static_name = true;
conn->req.host_header.static_value = true;
conn->req.host_header.alloc_header = false;
nni_list_prepend(&conn->req.hdrs, &conn->req.host_header);
nni_list_prepend(&conn->req.data.hdrs, &conn->req.host_header);
}

void
nni_http_set_content_length(nng_http *conn, size_t size)
{
nni_http_entity *data =
conn->client ? &conn->req.data : &conn->res.data;

snprintf(data->clen, sizeof(data->clen), "%lu", (unsigned long) size);
nni_http_set_static_header(
conn, &data->content_length, "Content-Length", data->clen);
}

void
nni_http_set_content_type(nng_http *conn, const char *ctype)
{
nni_http_entity *data =
conn->client ? &conn->req.data : &conn->res.data;
snprintf(data->ctype, sizeof(data->ctype), "%s", ctype);
nni_http_set_static_header(
conn, &data->content_type, "Content-Type", data->ctype);
}

const char *
Expand Down Expand Up @@ -998,69 +1022,117 @@ nni_http_set_uri(nng_http *conn, const char *uri, const char *query)
return (0);

Check warning on line 1022 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1022

Added line #L1022 was not covered by tests
}

static bool
http_set_request_known_header(nng_http *conn, const char *key, const char *val)
static int
http_set_header(nng_http *conn, const char *key, const char *val)
{
if (nni_strcasecmp(key, "Host") == 0) {
nni_http_set_host(conn, val);
return (true);
}
if (nni_strcasecmp(key, "Content-Type") == 0) {
nni_http_req_set_content_type(&conn->req, val);
return (true);
}
return (false);
}
nni_http_entity *data =
conn->client ? &conn->req.data : &conn->res.data;
http_header *h;

int
nni_http_add_request_header(nng_http *conn, const char *key, const char *val)
{
if (http_set_request_known_header(conn, key, val)) {
return (0);
NNI_LIST_FOREACH (&data->hdrs, h) {
if (nni_strcasecmp(key, h->name) == 0) {
char *news;
if ((news = nni_strdup(val)) == NULL) {
return (NNG_ENOMEM);

Check warning on line 1036 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1036

Added line #L1036 was not covered by tests
}
if (!h->static_value) {
nni_strfree(h->value);
h->value = NULL;
}
h->value = news;
return (0);

Check warning on line 1043 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1039-L1043

Added lines #L1039 - L1043 were not covered by tests
}
}

return (nni_http_req_add_header(&conn->req, key, val));
if ((h = NNI_ALLOC_STRUCT(h)) == NULL) {
return (NNG_ENOMEM);

Check warning on line 1048 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1048

Added line #L1048 was not covered by tests
}
h->alloc_header = true;
if ((h->name = nni_strdup(key)) == NULL) {
NNI_FREE_STRUCT(h);
return (NNG_ENOMEM);

Check warning on line 1053 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1052-L1053

Added lines #L1052 - L1053 were not covered by tests
}
if ((h->value = nni_strdup(val)) == NULL) {
nni_strfree(h->name);
NNI_FREE_STRUCT(h);
return (NNG_ENOMEM);

Check warning on line 1058 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1056-L1058

Added lines #L1056 - L1058 were not covered by tests
}
nni_list_append(&data->hdrs, h);
return (0);
}

int
nni_http_set_request_header(nng_http *conn, const char *key, const char *val)
static int
http_add_header(nng_http *conn, const char *key, const char *val)
{
if (http_set_request_known_header(conn, key, val)) {
return (0);
nni_http_entity *data =
conn->client ? &conn->req.data : &conn->res.data;
http_header *h;
NNI_LIST_FOREACH (&data->hdrs, h) {
if (nni_strcasecmp(key, h->name) == 0) {
char *news;
int rv;
rv = nni_asprintf(&news, "%s, %s", h->value, val);

Check warning on line 1074 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1074

Added line #L1074 was not covered by tests
if (rv != 0) {
return (rv);

Check warning on line 1076 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1076

Added line #L1076 was not covered by tests
}
if (!h->static_value) {
nni_strfree(h->value);
}
h->value = news;
return (0);

Check warning on line 1082 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1079-L1082

Added lines #L1079 - L1082 were not covered by tests
}
}

return (nni_http_req_set_header(&conn->req, key, val));
if ((h = NNI_ALLOC_STRUCT(h)) == NULL) {
return (NNG_ENOMEM);

Check warning on line 1087 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1087

Added line #L1087 was not covered by tests
}
h->alloc_header = true;
if ((h->name = nni_strdup(key)) == NULL) {
NNI_FREE_STRUCT(h);
return (NNG_ENOMEM);

Check warning on line 1092 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1091-L1092

Added lines #L1091 - L1092 were not covered by tests
}
if ((h->value = nni_strdup(val)) == NULL) {
nni_strfree(h->name);
NNI_FREE_STRUCT(h);
return (NNG_ENOMEM);

Check warning on line 1097 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1095-L1097

Added lines #L1095 - L1097 were not covered by tests
}
nni_list_append(&data->hdrs, h);
return (0);
}

static bool
http_set_response_known_header(
nng_http *conn, const char *key, const char *val)
http_set_known_header(nng_http *conn, const char *key, const char *val)
{
if (nni_strcasecmp(key, "Content-Type") == 0) {
nni_http_res_set_content_type(&conn->res, val);
nni_http_set_content_type(conn, val);
return (true);
}
return (false);
}

int
nni_http_add_response_header(nng_http *conn, const char *key, const char *val)
{
if (http_set_response_known_header(conn, key, val)) {
return (0);
if (nni_strcasecmp(key, "Content-Length") == 0) {
nni_http_entity *data =
conn->client ? &conn->req.data : &conn->res.data;
snprintf(data->clen, sizeof(data->clen), "%s", val);
nni_http_set_static_header(
conn, &data->content_length, "Content-Length", data->clen);
return (true);
}

return (nni_http_res_add_header(&conn->res, key, val));
if (conn->client) {
if (nni_strcasecmp(key, "Host") == 0) {
nni_http_set_host(conn, val);
return (true);
}
}
return (false);
}

int
nni_http_set_response_header(nng_http *conn, const char *key, const char *val)
nni_http_add_header(nng_http *conn, const char *key, const char *val)
{
if (http_set_response_known_header(conn, key, val)) {
if (http_set_known_header(conn, key, val)) {
return (0);
}

return (nni_http_res_set_header(&conn->res, key, val));
return (http_add_header(conn, key, val));
}

void
Expand All @@ -1069,9 +1141,9 @@ nni_http_set_static_header(
{
nni_list *headers;
if (conn->client) {
headers = &conn->req.hdrs;
headers = &conn->req.data.hdrs;
} else {
headers = &conn->res.hdrs;
headers = &conn->res.data.hdrs;
}

nni_http_del_header(conn, key);
Expand All @@ -1087,30 +1159,32 @@ nni_http_set_static_header(
int
nni_http_set_header(nng_http *conn, const char *key, const char *val)
{
if (conn->client) {
return (nni_http_set_request_header(conn, key, val));
} else {
return (nni_http_set_response_header(conn, key, val));
if (http_set_known_header(conn, key, val)) {
return (0);
}
return (http_set_header(conn, key, val));
}

int
nni_http_add_header(nng_http *conn, const char *key, const char *val)
static bool
http_del_header_one(nni_list *hdrs, const char *key)
{
if (conn->client) {
return (nni_http_add_request_header(conn, key, val));
} else {
return (nni_http_add_response_header(conn, key, val));
http_header *h;
NNI_LIST_FOREACH (hdrs, h) {
if (nni_strcasecmp(key, h->name) == 0) {
nni_http_free_header(h);
return (true);
}
}
return (false);
}

void
nni_http_del_header(nng_http *conn, const char *key)
{
if (conn->client) {
nni_http_req_del_header(&conn->req, key);
} else {
nni_http_res_del_header(&conn->res, key);
nni_list *hdrs =
conn->client ? &conn->req.data.hdrs : &conn->res.data.hdrs;
while (http_del_header_one(hdrs, key)) {
continue;
}
}

Expand All @@ -1130,9 +1204,9 @@ const char *
nni_http_get_header(nng_http *conn, const char *key)
{
if (conn->client) {
return (http_get_header(&conn->res.hdrs, key));
return (http_get_header(&conn->res.data.hdrs, key));
} else {
return (http_get_header(&conn->req.hdrs, key));
return (http_get_header(&conn->req.data.hdrs, key));
}
}

Expand Down Expand Up @@ -1183,22 +1257,6 @@ http_copy_data(nni_http_entity *entity, const void *data, size_t size)
return (rv);
}

void
nni_http_set_content_length(nng_http *conn, size_t size)
{
if (conn->client) {
snprintf(conn->req.clen, sizeof(conn->req.clen), "%lu",
(unsigned long) size);
nni_http_set_static_header(conn, &conn->req.content_length,
"Content-Length", conn->req.clen);
} else {
snprintf(conn->res.clen, sizeof(conn->res.clen), "%lu",
(unsigned long) size);
nni_http_set_static_header(conn, &conn->res.content_length,
"Content-Length", conn->res.clen);
}
}

void
nni_http_set_body(nng_http *conn, void *data, size_t size)
{
Expand Down Expand Up @@ -1319,7 +1377,13 @@ nni_http_conn_init(nni_http_conn **connp, nng_stream *stream, bool client)

// private to the HTTP framework, used on the server
bool
nni_http_conn_res_sent(nni_http_conn *conn)
nni_http_res_sent(nni_http_conn *conn)
{
return (conn->res_sent);
}

bool
nni_http_parsed(nng_http *conn)

Check warning on line 1386 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1386

Added line #L1386 was not covered by tests
{
return (conn->client ? conn->res.data.parsed : conn->req.data.parsed);

Check warning on line 1388 in src/supplemental/http/http_conn.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_conn.c#L1388

Added line #L1388 was not covered by tests
}
Loading

0 comments on commit 6beab96

Please sign in to comment.