aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/supplemental/http/http_api.h5
-rw-r--r--src/supplemental/http/http_client.c2
-rw-r--r--src/supplemental/http/http_conn.c251
-rw-r--r--src/supplemental/http/http_msg.c128
-rw-r--r--src/supplemental/http/http_msg.h6
-rw-r--r--src/supplemental/http/http_server.c66
6 files changed, 243 insertions, 215 deletions
diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h
index ade6cf06..8ebe74bb 100644
--- a/src/supplemental/http/http_api.h
+++ b/src/supplemental/http/http_api.h
@@ -36,12 +36,10 @@ typedef struct nng_http_chunks nni_http_chunks;
extern void nni_http_req_init(nni_http_req *);
extern void nni_http_req_reset(nni_http_req *);
-extern int nni_http_req_get_buf(nni_http_req *, void **, size_t *);
extern int nni_http_req_parse(nng_http *, void *, size_t, size_t *);
extern void nni_http_res_init(nni_http_res *);
extern void nni_http_res_reset(nni_http_res *);
-extern int nni_http_res_get_buf(nni_http_conn *, void **, size_t *);
extern int nni_http_res_parse(nng_http *, void *, size_t, size_t *);
// Chunked transfer encoding. For the moment this is not part of our public
@@ -115,10 +113,9 @@ extern void nni_http_write_req(nni_http_conn *, nni_aio *);
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 void nni_http_read_discard(nni_http_conn *, size_t, nni_aio *);
extern int nni_http_req_add_header(nni_http_req *, 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_req_alloc_data(nni_http_req *, size_t);
extern int nni_http_res_alloc_data(nni_http_res *, size_t);
diff --git a/src/supplemental/http/http_client.c b/src/supplemental/http/http_client.c
index 7062ae3c..4622dd94 100644
--- a/src/supplemental/http/http_client.c
+++ b/src/supplemental/http/http_client.c
@@ -217,7 +217,6 @@ typedef struct http_txn {
nni_list aios; // upper level aio(s) -- maximum one
nni_http_client *client;
nni_http_conn *conn;
- nni_http_req *req;
nni_http_res *res;
nni_http_chunks *chunks;
http_txn_state state;
@@ -398,7 +397,6 @@ nni_http_transact_conn(nni_http_conn *conn, nni_aio *aio)
nni_aio_list_init(&txn->aios);
txn->client = NULL;
txn->conn = conn;
- txn->req = nni_http_conn_req(conn);
txn->res = nni_http_conn_res(conn);
txn->state = HTTP_SENDING;
diff --git a/src/supplemental/http/http_conn.c b/src/supplemental/http/http_conn.c
index 20ae2f05..f3e02314 100644
--- a/src/supplemental/http/http_conn.c
+++ b/src/supplemental/http/http_conn.c
@@ -9,6 +9,7 @@
// found online at https://opensource.org/licenses/MIT.
//
+#include <complex.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
@@ -24,7 +25,9 @@
// We insist that individual headers fit in 8K.
// If you need more than that, you need something we can't do.
-#define HTTP_BUFSIZE 8192
+// We leave some room for allocator overhead (32 bytes should
+// be more than enough), to avoid possibly wasting an extra page.
+#define HTTP_BUFSIZE (8192 - 32)
// types of reads
enum read_flavor {
@@ -33,6 +36,7 @@ enum read_flavor {
HTTP_RD_REQ,
HTTP_RD_RES,
HTTP_RD_CHUNK,
+ HTTP_RD_DISCARD,
};
enum write_flavor {
@@ -45,7 +49,6 @@ enum write_flavor {
struct nng_http_conn {
nng_stream *sock;
void *ctx;
- bool closed;
nni_list rdq; // high level http read requests
nni_list wrq; // high level http write requests
@@ -59,16 +62,23 @@ struct nng_http_conn {
nng_http_req req;
nng_http_res res;
- enum read_flavor rd_flavor;
- uint8_t *rd_buf;
- size_t rd_get;
- size_t rd_put;
- size_t rd_bufsz;
- bool rd_buffered;
- bool client; // true if this is a client's connection
- bool res_sent;
-
+ char meth[32];
+ char host[260]; // 253 per IETF, plus 6 for :port plus null
+ char ubuf[200]; // Most URIs are smaller than this
+ const char *vers;
+ char *uri;
+ uint8_t *buf;
+ size_t bufsz;
+ size_t rd_get;
+ size_t rd_put;
+ size_t rd_discard;
+
+ enum read_flavor rd_flavor;
enum write_flavor wr_flavor;
+ bool rd_buffered;
+ bool client; // true if a client's connection
+ bool res_sent;
+ bool closed;
};
nng_http_req *
@@ -141,14 +151,14 @@ nni_http_conn_close(nni_http_conn *conn)
nni_mtx_unlock(&conn->mtx);
}
-// http_rd_buf_pull_up pulls the content of the read buffer back to the
+// http_buf_pull_up pulls the content of the read buffer back to the
// beginning, so that the next read can go at the end. This avoids the problem
// of dealing with a read that might wrap.
static void
-http_rd_buf_pull_up(nni_http_conn *conn)
+http_buf_pull_up(nni_http_conn *conn)
{
if (conn->rd_get != 0) {
- memmove(conn->rd_buf, conn->rd_buf + conn->rd_get,
+ memmove(conn->buf, conn->buf + conn->rd_get,
conn->rd_put - conn->rd_get);
conn->rd_put -= conn->rd_get;
conn->rd_get = 0;
@@ -161,7 +171,7 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
{
size_t cnt = conn->rd_put - conn->rd_get;
size_t n;
- uint8_t *rbuf = conn->rd_buf;
+ uint8_t *rbuf = conn->buf;
int rv;
bool raw = false;
nni_iov *iov;
@@ -212,6 +222,25 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
nng_stream_recv(conn->sock, &conn->rd_aio);
return (NNG_EAGAIN);
+ case HTTP_RD_DISCARD:
+ n = conn->rd_put - conn->rd_get;
+ if (n > conn->rd_discard) {
+ n = conn->rd_discard;
+ }
+ conn->rd_get += n;
+ conn->rd_discard -= n;
+ http_buf_pull_up(conn);
+ if (conn->rd_discard > 0) {
+ nni_iov iov1;
+ iov1.iov_buf = conn->buf + conn->rd_put;
+ iov1.iov_len = conn->bufsz - conn->rd_put;
+ conn->rd_buffered = true;
+ nni_aio_set_iov(&conn->rd_aio, 1, &iov1);
+ nng_stream_recv(conn->sock, &conn->rd_aio);
+ return (NNG_EAGAIN);
+ }
+ return (0);
+
case HTTP_RD_REQ:
conn->client = true;
rv = nni_http_req_parse(conn, rbuf, cnt, &n);
@@ -222,9 +251,9 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
}
if (rv == NNG_EAGAIN) {
nni_iov iov1;
- http_rd_buf_pull_up(conn);
- iov1.iov_buf = conn->rd_buf + conn->rd_put;
- iov1.iov_len = conn->rd_bufsz - conn->rd_put;
+ http_buf_pull_up(conn);
+ iov1.iov_buf = conn->buf + conn->rd_put;
+ iov1.iov_len = conn->bufsz - conn->rd_put;
conn->rd_buffered = true;
if (iov1.iov_len == 0) {
return (NNG_EMSGSIZE);
@@ -244,9 +273,9 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
}
if (rv == NNG_EAGAIN) {
nni_iov iov1;
- http_rd_buf_pull_up(conn);
- iov1.iov_buf = conn->rd_buf + conn->rd_put;
- iov1.iov_len = conn->rd_bufsz - conn->rd_put;
+ http_buf_pull_up(conn);
+ iov1.iov_buf = conn->buf + conn->rd_put;
+ iov1.iov_len = conn->bufsz - conn->rd_put;
conn->rd_buffered = true;
if (iov1.iov_len == 0) {
return (NNG_EMSGSIZE);
@@ -265,8 +294,8 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio)
}
if (rv == NNG_EAGAIN) {
nni_iov iov1;
- iov1.iov_buf = conn->rd_buf + conn->rd_put;
- iov1.iov_len = conn->rd_bufsz - conn->rd_put;
+ iov1.iov_buf = conn->buf + conn->rd_put;
+ iov1.iov_len = conn->bufsz - conn->rd_put;
conn->rd_buffered = true;
nni_aio_set_iov(&conn->rd_aio, 1, &iov1);
nng_stream_recv(conn->sock, &conn->rd_aio);
@@ -341,7 +370,7 @@ http_rd_cb(void *arg)
// If we were reading into the buffer, then advance location(s).
if (conn->rd_buffered) {
conn->rd_put += cnt;
- NNI_ASSERT(conn->rd_put <= conn->rd_bufsz);
+ NNI_ASSERT(conn->rd_put <= conn->bufsz);
http_rd_start(conn);
nni_mtx_unlock(&conn->mtx);
return;
@@ -542,9 +571,15 @@ nni_http_conn_reset(nng_http *conn)
{
nni_http_req_reset(&conn->req);
nni_http_res_reset(&conn->res);
- if (strlen(conn->req.host)) {
- nni_http_set_host(conn, conn->req.host);
+ (void) snprintf(conn->meth, sizeof(conn->meth), "GET");
+ if (strlen(conn->host)) {
+ nni_http_set_host(conn, conn->host);
}
+ if (conn->uri != NULL && conn->uri != conn->ubuf) {
+ nni_strfree(conn->uri);
+ }
+ conn->uri = NULL;
+ nni_http_set_version(conn, NNG_HTTP_VERSION_1_1);
}
void
@@ -572,6 +607,7 @@ nni_http_read_chunks(nni_http_conn *conn, nni_http_chunks *cl, nni_aio *aio)
nni_aio_set_prov_data(aio, cl);
nni_mtx_lock(&conn->mtx);
+ conn->rd_discard = 0;
http_rd_submit(conn, aio, HTTP_RD_CHUNK);
nni_mtx_unlock(&conn->mtx);
}
@@ -582,11 +618,21 @@ nni_http_read_full(nni_http_conn *conn, nni_aio *aio)
nni_aio_set_prov_data(aio, NULL);
nni_mtx_lock(&conn->mtx);
+ conn->rd_discard = 0;
http_rd_submit(conn, aio, HTTP_RD_FULL);
nni_mtx_unlock(&conn->mtx);
}
void
+nni_http_read_discard(nng_http *conn, size_t discard, nng_aio *aio)
+{
+ nni_mtx_lock(&conn->mtx);
+ conn->rd_discard = discard;
+ http_rd_submit(conn, aio, HTTP_RD_DISCARD);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+void
nni_http_read(nni_http_conn *conn, nni_aio *aio)
{
nni_aio_set_prov_data(aio, NULL);
@@ -596,8 +642,97 @@ nni_http_read(nni_http_conn *conn, nni_aio *aio)
nni_mtx_unlock(&conn->mtx);
}
+static size_t
+http_sprintf_headers(char *buf, size_t sz, nni_list *list)
+{
+ size_t rv = 0;
+ http_header *h;
+
+ if (buf == NULL) {
+ sz = 0;
+ }
+
+ NNI_LIST_FOREACH (list, h) {
+ size_t l;
+ l = snprintf(buf, sz, "%s: %s\r\n", h->name, h->value);
+ if (buf != NULL) {
+ buf += l;
+ }
+ sz = (sz > l) ? sz - l : 0;
+ rv += l;
+ }
+ return (rv);
+}
+
+static int
+http_snprintf(nng_http *conn, char *buf, size_t sz)
+{
+ size_t len;
+ size_t n;
+ nni_list *hdrs;
+
+ if (conn->client) {
+ len = snprintf(buf, sz, "%s %s %s\r\n",
+ nni_http_get_method(conn), nni_http_get_uri(conn),
+ nni_http_get_version(conn));
+ hdrs = &conn->req.data.hdrs;
+ } else {
+ len = snprintf(buf, sz, "%s %d %s\r\n",
+ nni_http_get_version(conn), nni_http_get_status(conn),
+ nni_http_get_reason(conn));
+ hdrs = &conn->res.data.hdrs;
+ }
+
+ if (len < sz) {
+ sz -= len;
+ buf += len;
+ } else {
+ sz = 0;
+ buf = NULL;
+ }
+
+ n = http_sprintf_headers(buf, sz, hdrs);
+ len += n;
+ if (len < sz) {
+ sz -= n;
+ buf += n;
+ } else {
+ sz = 0;
+ buf = NULL;
+ }
+
+ len += snprintf(buf, sz, "\r\n");
+ return (len);
+}
+
+static int
+http_prepare(nng_http *conn, void **data, size_t *szp)
+{
+ size_t len;
+
+ // get length needed first
+ len = http_snprintf(conn, NULL, 0);
+
+ // If it fits in the fixed buffer, use it. It should cover
+ // like 99% or more cases, as this buffer is 8KB.
+ if (len < conn->bufsz) {
+ http_snprintf(conn, (char *) conn->buf, conn->bufsz);
+ *data = conn->buf;
+ *szp = len;
+ return (0);
+ }
+
+ // we have to allocate.
+ if ((*data = nni_alloc(len + 1)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ http_snprintf(conn, *data, len + 1);
+ *szp = len; // this does not include the terminating null
+ return (0);
+}
+
void
-nni_http_write_req(nni_http_conn *conn, nni_aio *aio)
+nni_http_write_req(nng_http *conn, nni_aio *aio)
{
int rv;
void *buf;
@@ -605,10 +740,15 @@ nni_http_write_req(nni_http_conn *conn, nni_aio *aio)
nni_iov iov[2];
int niov;
- if ((rv = nni_http_req_get_buf(&conn->req, &buf, &bufsz)) != 0) {
+ if ((rv = http_prepare(conn, &buf, &bufsz)) != 0) {
nni_aio_finish_error(aio, rv);
return;
}
+ if (buf != conn->buf) {
+ nni_free(conn->req.data.buf, conn->req.data.bufsz);
+ conn->req.data.buf = buf;
+ conn->req.data.bufsz = bufsz + 1; // including \0
+ }
niov = 1;
iov[0].iov_len = bufsz;
iov[0].iov_buf = buf;
@@ -625,7 +765,7 @@ nni_http_write_req(nni_http_conn *conn, nni_aio *aio)
}
void
-nni_http_write_res(nni_http_conn *conn, nni_aio *aio)
+nni_http_write_res(nng_http *conn, nni_aio *aio)
{
int rv;
void *buf;
@@ -633,11 +773,17 @@ nni_http_write_res(nni_http_conn *conn, nni_aio *aio)
nni_iov iov[2];
int nio;
- conn->res_sent = true;
- if ((rv = nni_http_res_get_buf(conn, &buf, &bufsz)) != 0) {
+ if ((rv = http_prepare(conn, &buf, &bufsz)) != 0) {
nni_aio_finish_error(aio, rv);
return;
}
+ if (buf != conn->buf) {
+ nni_free(conn->res.data.buf, conn->res.data.bufsz);
+ conn->res.data.buf = buf;
+ conn->res.data.bufsz = bufsz + 1; // including \0
+ }
+
+ conn->res_sent = true;
nio = 1;
iov[0].iov_len = bufsz;
iov[0].iov_buf = buf;
@@ -672,7 +818,7 @@ nni_http_write_full(nni_http_conn *conn, nni_aio *aio)
const char *
nni_http_get_version(nng_http *conn)
{
- return (conn->req.vers);
+ return (conn->vers);
}
int
@@ -691,8 +837,7 @@ nni_http_set_version(nng_http *conn, const char *vers)
vers = vers != NULL ? vers : NNG_HTTP_VERSION_1_1;
for (int i = 0; http_versions[i] != NULL; i++) {
if (strcmp(vers, http_versions[i]) == 0) {
- conn->req.vers = http_versions[i];
- conn->res.vers = http_versions[i];
+ conn->vers = http_versions[i];
return (0);
}
}
@@ -707,18 +852,21 @@ nni_http_set_method(nng_http *conn, const char *method)
}
// this may truncate the method, but nobody should be sending
// methods so long.
- (void) snprintf(conn->req.meth, sizeof(conn->req.meth), "%s", method);
+ (void) snprintf(conn->meth, sizeof(conn->meth), "%s", method);
}
const char *
nni_http_get_method(nng_http *conn)
{
- return (conn->req.meth);
+ return (conn->meth);
}
uint16_t
nni_http_get_status(nng_http *conn)
{
+ if (conn->res.code == 0) {
+ return (NNG_HTTP_STATUS_OK);
+ }
return (conn->res.code);
}
@@ -944,12 +1092,12 @@ nni_http_set_redirect(
void
nni_http_set_host(nng_http *conn, const char *host)
{
- if (host != conn->req.host) {
- snprintf(conn->req.host, sizeof(conn->req.host), "%s", host);
+ if (host != conn->host) {
+ snprintf(conn->host, sizeof(conn->host), "%s", host);
}
nni_list_node_remove(&conn->req.host_header.node);
conn->req.host_header.name = "Host";
- conn->req.host_header.value = conn->req.host;
+ conn->req.host_header.value = conn->host;
conn->req.host_header.static_name = true;
conn->req.host_header.static_value = true;
conn->req.host_header.alloc_header = false;
@@ -980,7 +1128,7 @@ nni_http_set_content_type(nng_http *conn, const char *ctype)
const char *
nni_http_get_uri(nng_http *conn)
{
- return (conn->req.uri);
+ return (conn->uri);
}
int
@@ -998,25 +1146,24 @@ nni_http_set_uri(nng_http *conn, const char *uri, const char *query)
needed = strlen(uri);
}
- if (conn->req.uri != NULL && (strcmp(uri, conn->req.uri) == 0) &&
+ if (conn->uri != NULL && (strcmp(uri, conn->uri) == 0) &&
strlen(query) == 0) {
// no change, do nothing
return (0);
}
- if (conn->req.uri != NULL && conn->req.uri != conn->req.ubuf) {
- nni_strfree(conn->req.uri);
+ if (conn->uri != NULL && conn->uri != conn->ubuf) {
+ nni_strfree(conn->uri);
}
// fast path, small size URI fits in our buffer
- if (needed < sizeof(conn->req.ubuf)) {
- snprintf(
- conn->req.ubuf, sizeof(conn->req.ubuf), fmt, uri, query);
- conn->req.uri = conn->req.ubuf;
+ if (needed < sizeof(conn->ubuf)) {
+ snprintf(conn->ubuf, sizeof(conn->ubuf), fmt, uri, query);
+ conn->uri = conn->ubuf;
return (0);
}
// too big, we have to allocate it (slow path)
- if (nni_asprintf(&conn->req.uri, fmt, uri, query) != 0) {
+ if (nni_asprintf(&conn->uri, fmt, uri, query) != 0) {
return (NNG_ENOMEM);
}
return (0);
@@ -1327,7 +1474,7 @@ nni_http_conn_fini(nni_http_conn *conn)
nni_aio_fini(&conn->wr_aio);
nni_aio_fini(&conn->rd_aio);
nni_http_conn_reset(conn);
- nni_free(conn->rd_buf, conn->rd_bufsz);
+ nni_free(conn->buf, conn->bufsz);
nni_mtx_fini(&conn->mtx);
NNI_FREE_STRUCT(conn);
}
@@ -1347,13 +1494,13 @@ http_init(nni_http_conn **connp, nng_stream *data, bool client)
nni_http_req_init(&conn->req);
nni_http_res_init(&conn->res);
nni_http_set_version(conn, NNG_HTTP_VERSION_1_1);
- nni_http_set_method(conn, NULL);
+ nni_http_set_method(conn, "GET");
- if ((conn->rd_buf = nni_alloc(HTTP_BUFSIZE)) == NULL) {
+ if ((conn->buf = nni_alloc(HTTP_BUFSIZE)) == NULL) {
nni_http_conn_fini(conn);
return (NNG_ENOMEM);
}
- conn->rd_bufsz = HTTP_BUFSIZE;
+ conn->bufsz = HTTP_BUFSIZE;
nni_aio_init(&conn->wr_aio, http_wr_cb, conn);
nni_aio_init(&conn->rd_aio, http_rd_cb, conn);
diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c
index fbe73e4c..5cc71b7d 100644
--- a/src/supplemental/http/http_msg.c
+++ b/src/supplemental/http/http_msg.c
@@ -66,11 +66,6 @@ void
nni_http_req_reset(nni_http_req *req)
{
http_entity_reset(&req->data);
- if (req->uri != req->ubuf) {
- nni_strfree(req->uri);
- }
- req->uri = NULL;
- (void) snprintf(req->meth, sizeof(req->meth), "GET");
}
void
@@ -78,7 +73,6 @@ nni_http_res_reset(nni_http_res *res)
{
http_entity_reset(&res->data);
nni_strfree(res->rsn);
- res->vers = NNG_HTTP_VERSION_1_1;
res->rsn = NULL;
res->code = 0;
}
@@ -169,125 +163,6 @@ http_parse_header(nng_http *conn, void *line)
return (nni_http_add_header(conn, key, val));
}
-// http_sprintf_headers makes headers for an HTTP request or an HTTP response
-// object. Each header is dumped from the list. If the buf is NULL,
-// or the sz is 0, then a dryrun is done, in order to allow the caller to
-// determine how much space is needed. Returns the size of the space needed,
-// not including the terminating NULL byte. Truncation occurs if the size
-// returned is >= the requested size.
-static size_t
-http_sprintf_headers(char *buf, size_t sz, nni_list *list)
-{
- size_t rv = 0;
- http_header *h;
-
- if (buf == NULL) {
- sz = 0;
- }
-
- NNI_LIST_FOREACH (list, h) {
- size_t l;
- l = snprintf(buf, sz, "%s: %s\r\n", h->name, h->value);
- if (buf != NULL) {
- buf += l;
- }
- sz = (sz > l) ? sz - l : 0;
- rv += l;
- }
- return (rv);
-}
-
-static int
-http_asprintf(char **bufp, size_t *szp, nni_list *hdrs, const char *fmt, ...)
-{
- va_list ap;
- size_t len;
- size_t n;
- char *buf;
-
- va_start(ap, fmt);
- len = vsnprintf(NULL, 0, fmt, ap);
- va_end(ap);
-
- len += http_sprintf_headers(NULL, 0, hdrs);
- len += 3; // \r\n\0
-
- if (len <= *szp) {
- buf = *bufp;
- } else {
- if ((buf = nni_alloc(len)) == NULL) {
- return (NNG_ENOMEM);
- }
- nni_free(*bufp, *szp);
- *bufp = buf;
- *szp = len;
- }
- va_start(ap, fmt);
- n = vsnprintf(buf, len, fmt, ap);
- va_end(ap);
- buf += n;
- len -= n;
- n = http_sprintf_headers(buf, len, hdrs);
- buf += n;
- len -= n;
- snprintf(buf, len, "\r\n");
- NNI_ASSERT(len == 3);
- return (0);
-}
-
-static int
-http_req_prepare(nni_http_req *req)
-{
- int rv;
- if (req->uri == NULL) {
- return (NNG_EINVAL);
- }
- rv = http_asprintf(&req->data.buf, &req->data.bufsz, &req->data.hdrs,
- "%s %s %s\r\n", req->meth, req->uri, req->vers);
- return (rv);
-}
-
-static int
-http_res_prepare(nng_http *conn)
-{
- int rv;
- nng_http_res *res = nni_http_conn_res(conn);
-
- if (res->code == 0) {
- res->code = NNG_HTTP_STATUS_OK;
- }
- rv = http_asprintf(&res->data.buf, &res->data.bufsz, &res->data.hdrs,
- "%s %d %s\r\n", res->vers, res->code, nni_http_get_reason(conn));
- return (rv);
-}
-
-int
-nni_http_req_get_buf(nni_http_req *req, void **data, size_t *szp)
-{
- int rv;
-
- if ((req->data.buf == NULL) && (rv = http_req_prepare(req)) != 0) {
- return (rv);
- }
- *data = req->data.buf;
- *szp = req->data.bufsz - 1; // exclude terminating NUL
- return (0);
-}
-
-int
-nni_http_res_get_buf(nng_http *conn, void **data, size_t *szp)
-{
- int rv;
- nni_http_res *res = nni_http_conn_res(conn);
-
- if ((res->data.buf == NULL) && (rv = http_res_prepare(conn)) != 0) {
- return (rv);
- }
- *data = res->data.buf;
- *szp = res->data.bufsz - 1; // exclude terminating NUL
- return (0);
-}
-
void
nni_http_req_init(nni_http_req *req)
{
@@ -297,8 +172,6 @@ nni_http_req_init(nni_http_req *req)
req->data.data = NULL;
req->data.size = 0;
req->data.own = false;
- req->uri = NULL;
- (void) snprintf(req->meth, sizeof(req->meth), "GET");
}
void
@@ -310,7 +183,6 @@ nni_http_res_init(nni_http_res *res)
res->data.data = NULL;
res->data.size = 0;
res->data.own = false;
- res->vers = NNG_HTTP_VERSION_1_1;
res->rsn = NULL;
res->code = 0;
}
diff --git a/src/supplemental/http/http_msg.h b/src/supplemental/http/http_msg.h
index e08dab8a..038d9a04 100644
--- a/src/supplemental/http/http_msg.h
+++ b/src/supplemental/http/http_msg.h
@@ -44,11 +44,6 @@ typedef struct nni_http_entity {
struct nng_http_req {
nni_http_entity data;
- char meth[32];
- char host[260]; // 253 per IETF, plus 6 for :port plus null
- char ubuf[200]; // Most URIs are smaller than this
- char *uri;
- const char *vers;
http_header host_header;
};
@@ -56,7 +51,6 @@ struct nng_http_res {
nni_http_entity data;
uint16_t code;
char *rsn;
- const char *vers;
bool iserr;
http_header location;
};
diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c
index 76ac075d..7a7caeca 100644
--- a/src/supplemental/http/http_server.c
+++ b/src/supplemental/http/http_server.c
@@ -54,6 +54,8 @@ typedef struct http_sconn {
nni_http_handler *release; // set if we dispatched handler
bool close;
bool finished;
+ size_t unconsumed_body;
+ size_t unconsumed_request;
nni_aio cbaio;
nni_aio rxaio;
nni_aio txaio;
@@ -322,7 +324,12 @@ http_sconn_txdone(void *arg)
}
sc->handler = NULL;
- nni_http_read_req(sc->conn, &sc->rxaio);
+ if (sc->unconsumed_body) {
+ nni_http_read_discard(
+ sc->conn, sc->unconsumed_body, &sc->rxaio);
+ } else {
+ nni_http_read_req(sc->conn, &sc->rxaio);
+ }
}
static char
@@ -523,6 +530,13 @@ http_sconn_rxdone(void *arg)
return;
}
+ // read the body, keep going
+ if (sc->unconsumed_body) {
+ sc->unconsumed_body = 0;
+ nni_http_read_req(sc->conn, aio);
+ return;
+ }
+
if ((h = sc->handler) != NULL) {
nni_mtx_lock(&s->mtx);
goto finish;
@@ -563,6 +577,17 @@ http_sconn_rxdone(void *arg)
}
}
+ sc->unconsumed_body = 0;
+ if ((cls = nni_http_get_header(sc->conn, "Content-Length")) != NULL) {
+ char *end;
+ sc->unconsumed_body = strtoull(cls, &end, 10);
+ if ((end == NULL) && (*end != '\0')) {
+ sc->unconsumed_body = 0;
+ http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST);
+ return;
+ }
+ }
+
val = nni_http_get_uri(sc->conn);
urisz = strlen(val) + 1;
if ((uri = nni_alloc(urisz)) == NULL) {
@@ -639,35 +664,29 @@ http_sconn_rxdone(void *arg)
return;
}
- if ((h->getbody) &&
- ((cls = nni_http_get_header(sc->conn, "Content-Length")) !=
- NULL)) {
- uint64_t len;
- char *end;
+ if ((h->getbody) && (sc->unconsumed_body > 0)) {
- len = strtoull(cls, &end, 10);
- if ((end == NULL) || (*end != '\0') || (len > h->maxbody)) {
+ if (sc->unconsumed_body > h->maxbody) {
nni_mtx_unlock(&s->mtx);
- http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST);
+ http_sconn_error(
+ sc, NNG_HTTP_STATUS_CONTENT_TOO_LARGE);
return;
}
- if (len > 0) {
- nng_iov iov;
- if ((nni_http_req_alloc_data(req, (size_t) len)) !=
- 0) {
- nni_mtx_unlock(&s->mtx);
- http_sconn_error(
- sc, NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR);
- return;
- }
- iov.iov_buf = req->data.data;
- iov.iov_len = req->data.size;
- sc->handler = h;
+ nng_iov iov;
+ if ((nni_http_req_alloc_data(req, sc->unconsumed_body)) != 0) {
nni_mtx_unlock(&s->mtx);
- nni_aio_set_iov(&sc->rxaio, 1, &iov);
- nni_http_read_full(sc->conn, aio);
+ http_sconn_error(
+ sc, NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR);
return;
}
+ iov.iov_buf = req->data.data;
+ iov.iov_len = req->data.size;
+ sc->unconsumed_body = 0;
+ sc->handler = h;
+ nni_mtx_unlock(&s->mtx);
+ nni_aio_set_iov(&sc->rxaio, 1, &iov);
+ nni_http_read_full(sc->conn, aio);
+ return;
}
finish:
@@ -684,6 +703,7 @@ finish:
// make sure the response is freshly initialized
nni_http_res_reset(nni_http_conn_res(sc->conn));
+ nni_http_set_version(sc->conn, NNG_HTTP_VERSION_1_1);
h->cb(sc->conn, h->data, &sc->cbaio);
}