diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/supplemental/http/http_api.h | 13 | ||||
| -rw-r--r-- | src/supplemental/http/http_client.c | 11 | ||||
| -rw-r--r-- | src/supplemental/http/http_conn.c | 20 | ||||
| -rw-r--r-- | src/supplemental/http/http_msg.c | 143 | ||||
| -rw-r--r-- | src/supplemental/http/http_msg.h | 57 | ||||
| -rw-r--r-- | src/supplemental/http/http_public.c | 39 |
6 files changed, 190 insertions, 93 deletions
diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 29a8c5c1..a6dfa6ca 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -34,13 +34,14 @@ typedef struct nng_http_chunks nni_http_chunks; extern const char *nni_http_reason(uint16_t); -extern int nni_http_req_init(nni_http_req **); +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(nni_http_req *, void *, size_t, size_t *); extern char *nni_http_req_headers(nni_http_req *); extern void nni_http_req_get_data(nni_http_req *, void **, 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_res *, void **, size_t *); extern int nni_http_res_parse(nni_http_res *, void *, size_t, size_t *); @@ -74,6 +75,9 @@ extern int nni_http_chunks_parse(nni_http_chunks *, void *, size_t, size_t *); extern void nni_http_read_chunks( nni_http_conn *, nni_http_chunks *, nni_aio *); +extern nni_http_req *nni_http_conn_req(nni_http_conn *); +extern nni_http_res *nni_http_conn_res(nni_http_conn *); + // Private to the server. (Used to support session hijacking.) extern void nni_http_conn_set_ctx(nni_http_conn *, void *); extern void *nni_http_conn_get_ctx(nni_http_conn *); @@ -137,6 +141,7 @@ extern const char *nni_http_req_get_uri(const nni_http_req *); extern void nni_http_req_set_method(nni_http_req *, const char *); extern int nni_http_req_set_version(nni_http_req *, const char *); extern int nni_http_req_set_uri(nni_http_req *, const char *); +extern int nni_http_req_set_url(nni_http_req *, const nng_url *); extern uint16_t nni_http_res_get_status(const nni_http_res *); extern void nni_http_res_set_status(nni_http_res *, uint16_t); extern const char *nni_http_res_get_version(const nni_http_res *); @@ -375,9 +380,9 @@ extern void nni_http_client_connect(nni_http_client *, nni_aio *); // unless some kind of significant error occurs. The caller should dispose // of the connection if the aio does not complete successfully. // Note that this will fail with NNG_ENOTSUP if the server attempts to reply -// with a chunked transfer encoding. -extern void nni_http_transact_conn( - nni_http_conn *, nni_http_req *, nni_http_res *, nni_aio *); +// with a chunked transfer encoding. The request and response used are the +// ones associated with the connection. +extern void nni_http_transact_conn(nni_http_conn *, nni_aio *); // nni_http_transact is used to execute a single transaction to a server. // The connection is opened, and will be closed when the transaction is diff --git a/src/supplemental/http/http_client.c b/src/supplemental/http/http_client.c index 52b6874d..8701a96b 100644 --- a/src/supplemental/http/http_client.c +++ b/src/supplemental/http/http_client.c @@ -361,8 +361,7 @@ http_txn_cancel(nni_aio *aio, void *arg, int rv) // for Chunked Transfer Encoding is missing. Note that cancelling the aio // is generally fatal to the connection. void -nni_http_transact_conn( - nni_http_conn *conn, nni_http_req *req, nni_http_res *res, nni_aio *aio) +nni_http_transact_conn(nni_http_conn *conn, nni_aio *aio) { http_txn *txn; int rv; @@ -380,10 +379,12 @@ nni_http_transact_conn( nni_aio_list_init(&txn->aios); txn->client = NULL; txn->conn = conn; - txn->req = req; - txn->res = res; + txn->req = nni_http_conn_req(conn); + txn->res = nni_http_conn_res(conn); txn->state = HTTP_SENDING; + nni_http_res_reset(txn->res); + nni_mtx_lock(&http_txn_lk); if (!nni_aio_start(aio, http_txn_cancel, txn)) { nni_mtx_unlock(&http_txn_lk); @@ -392,7 +393,7 @@ nni_http_transact_conn( } nni_http_res_reset(txn->res); nni_list_append(&txn->aios, aio); - nni_http_write_req(conn, req, txn->aio); + nni_http_write_req(conn, txn->req, txn->aio); nni_mtx_unlock(&http_txn_lk); } diff --git a/src/supplemental/http/http_conn.c b/src/supplemental/http/http_conn.c index 44860fe6..912f2cc9 100644 --- a/src/supplemental/http/http_conn.c +++ b/src/supplemental/http/http_conn.c @@ -17,6 +17,7 @@ #include "supplemental/tls/tls_api.h" #include "http_api.h" +#include "http_msg.h" // We insist that individual headers fit in 8K. // If you need more than that, you need something we can't do. @@ -52,6 +53,9 @@ struct nng_http_conn { nni_mtx mtx; + nng_http_req req; + nng_http_res res; + enum read_flavor rd_flavor; uint8_t *rd_buf; size_t rd_get; @@ -62,6 +66,18 @@ struct nng_http_conn { enum write_flavor wr_flavor; }; +nng_http_req * +nni_http_conn_req(nng_http_conn *conn) +{ + return (&conn->req); +} + +nng_http_res * +nni_http_conn_res(nng_http_conn *conn) +{ + return (&conn->res); +} + void nni_http_conn_set_ctx(nni_http_conn *conn, void *ctx) { @@ -651,6 +667,8 @@ nni_http_conn_fini(nni_http_conn *conn) nni_aio_fini(&conn->wr_aio); nni_aio_fini(&conn->rd_aio); + nni_http_req_reset(&conn->req); + nni_http_res_reset(&conn->res); nni_free(conn->rd_buf, conn->rd_bufsz); nni_mtx_fini(&conn->mtx); NNI_FREE_STRUCT(conn); @@ -667,6 +685,8 @@ http_init(nni_http_conn **connp, nng_stream *data) nni_mtx_init(&conn->mtx); nni_aio_list_init(&conn->rdq); nni_aio_list_init(&conn->wrq); + nni_http_req_init(&conn->req); + nni_http_res_init(&conn->res); if ((conn->rd_buf = nni_alloc(HTTP_BUFSIZE)) == NULL) { nni_http_conn_fini(conn); diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c index 44981354..08c594ac 100644 --- a/src/supplemental/http/http_msg.c +++ b/src/supplemental/http/http_msg.c @@ -1,5 +1,5 @@ // -// Copyright 2024 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2025 Staysail Systems, Inc. <info@staysail.tech> // Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a @@ -16,48 +16,9 @@ #include "core/nng_impl.h" #include "http_api.h" +#include "http_msg.h" #include "nng/supplemental/http/http.h" -// Note that as we parse headers, the rule is that if a header is already -// present, then we can append it to the existing header, separated by -// a comma. From experience, for example, Firefox uses a Connection: -// header with two values, "keepalive", and "upgrade". -typedef struct http_header { - char *name; - char *value; - nni_list_node node; -} http_header; - -typedef struct nni_http_entity { - char *data; - size_t size; // allocated/expected size - size_t len; // current length - bool own; // if true, data is "ours", and should be freed -} nni_http_entity; - -struct nng_http_req { - nni_list hdrs; - nni_http_entity data; - char meth[32]; - char *uri; - const char *vers; - char *buf; - size_t bufsz; - bool parsed; -}; - -struct nng_http_res { - nni_list hdrs; - nni_http_entity data; - uint16_t code; - char *rsn; - const char *vers; - char *buf; - size_t bufsz; - bool parsed; - bool iserr; -}; - static int http_set_string(char **strp, const char *val) { @@ -601,13 +562,9 @@ nni_http_res_get_buf(nni_http_res *res, void **data, size_t *szp) return (0); } -int -nni_http_req_alloc(nni_http_req **reqp, const nng_url *url) +void +nni_http_req_init(nni_http_req *req) { - nni_http_req *req; - if ((req = NNI_ALLOC_STRUCT(req)) == NULL) { - return (NNG_ENOMEM); - } NNI_LIST_INIT(&req->hdrs, http_header, node); req->buf = NULL; req->bufsz = 0; @@ -617,34 +574,56 @@ nni_http_req_alloc(nni_http_req **reqp, const nng_url *url) req->uri = NULL; nni_http_req_set_version(req, NNG_HTTP_VERSION_1_1); nni_http_req_set_method(req, "GET"); - if (url != NULL) { - const char *host; - char host_buf[264]; // 256 + 8 for port - int rv; - rv = nni_asprintf(&req->uri, "%s%s%s%s%s", url->u_path, - url->u_query ? "?" : "", url->u_query ? url->u_query : "", - url->u_fragment ? "#" : "", - url->u_fragment ? url->u_fragment : ""); - if (rv != 0) { - NNI_FREE_STRUCT(req); - return (NNG_ENOMEM); - } +} + +int +nni_http_req_set_url(nni_http_req *req, const nng_url *url) +{ + if (url == NULL) { + return (0); + } + const char *host; + char host_buf[264]; // 256 + 8 for port + int rv; + rv = nni_asprintf(&req->uri, "%s%s%s%s%s", url->u_path, + url->u_query ? "?" : "", url->u_query ? url->u_query : "", + url->u_fragment ? "#" : "", + url->u_fragment ? url->u_fragment : ""); + if (rv != 0) { + return (NNG_ENOMEM); + } - // Add a Host: header since we know that from the URL. Also, - // only include the :port portion if it isn't the default port. - if (nni_url_default_port(url->u_scheme) == url->u_port) { - host = url->u_hostname; + // Add a Host: header since we know that from the URL. Also, + // only include the :port portion if it isn't the default port. + if (nni_url_default_port(url->u_scheme) == url->u_port) { + host = url->u_hostname; + } else { + if (strchr(url->u_hostname, ':')) { + snprintf(host_buf, sizeof(host_buf), "[%s]:%u", + url->u_hostname, url->u_port); } else { - if (strchr(url->u_hostname, ':')) { - snprintf(host_buf, sizeof(host_buf), "[%s]:%u", - url->u_hostname, url->u_port); - } else { - snprintf(host_buf, sizeof(host_buf), "%s:%u", - url->u_hostname, url->u_port); - } - host = host_buf; + snprintf(host_buf, sizeof(host_buf), "%s:%u", + url->u_hostname, url->u_port); } - if ((rv = nni_http_req_add_header(req, "Host", host)) != 0) { + host = host_buf; + } + if ((rv = nni_http_req_set_header(req, "Host", host)) != 0) { + return (rv); + } + return (0); +} + +int +nni_http_req_alloc(nni_http_req **reqp, const nng_url *url) +{ + nni_http_req *req; + if ((req = NNI_ALLOC_STRUCT(req)) == NULL) { + return (NNG_ENOMEM); + } + nni_http_req_init(req); + if (url != NULL) { + int rv; + if ((rv = nni_http_req_set_url(req, url)) != 0) { nni_http_req_free(req); return (rv); } @@ -653,13 +632,9 @@ nni_http_req_alloc(nni_http_req **reqp, const nng_url *url) return (0); } -int -nni_http_res_alloc(nni_http_res **resp) +void +nni_http_res_init(nni_http_res *res) { - nni_http_res *res; - if ((res = NNI_ALLOC_STRUCT(res)) == NULL) { - return (NNG_ENOMEM); - } NNI_LIST_INIT(&res->hdrs, http_header, node); res->buf = NULL; res->bufsz = 0; @@ -669,7 +644,17 @@ nni_http_res_alloc(nni_http_res **resp) res->vers = NNG_HTTP_VERSION_1_1; res->rsn = NULL; res->code = 0; - *resp = res; +} + +int +nni_http_res_alloc(nni_http_res **resp) +{ + nni_http_res *res; + if ((res = NNI_ALLOC_STRUCT(res)) == NULL) { + return (NNG_ENOMEM); + } + nni_http_res_init(res); + *resp = res; return (0); } diff --git a/src/supplemental/http/http_msg.h b/src/supplemental/http/http_msg.h new file mode 100644 index 00000000..7d9e7dcf --- /dev/null +++ b/src/supplemental/http/http_msg.h @@ -0,0 +1,57 @@ +// +// Copyright 2025 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#ifndef NNG_SUPPLEMENTAL_HTTP_HTTP_MSG +#define NNG_SUPPLEMENTAL_HTTP_HTTP_MSG + +#include "core/defs.h" +#include "core/list.h" + +// Note that as we parse headers, the rule is that if a header is already +// present, then we can append it to the existing header, separated by +// a comma. From experience, for example, Firefox uses a Connection: +// header with two values, "keepalive", and "upgrade". +typedef struct http_header { + char *name; + char *value; + nni_list_node node; +} http_header; + +typedef struct nni_http_entity { + char *data; + size_t size; // allocated/expected size + size_t len; // current length + bool own; // if true, data is "ours", and should be freed +} nni_http_entity; + +struct nng_http_req { + nni_list hdrs; + nni_http_entity data; + char meth[32]; + char *uri; + const char *vers; + char *buf; + size_t bufsz; + bool parsed; +}; + +struct nng_http_res { + nni_list hdrs; + nni_http_entity data; + uint16_t code; + char *rsn; + const char *vers; + char *buf; + size_t bufsz; + bool parsed; + bool iserr; +}; + +#endif diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index 88ebaa68..8a81404e 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -303,6 +303,18 @@ nng_http_req_set_version(nng_http_req *req, const char *vers) } int +nng_http_req_set_url(nng_http_req *req, const nng_url *url) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_set_url(req, url)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(url); + return (NNG_ENOTSUP); +#endif +} + +int nng_http_req_set_uri(nng_http_req *req, const char *uri) { #ifdef NNG_SUPP_HTTP @@ -382,6 +394,26 @@ nng_http_res_set_reason(nng_http_res *res, const char *rsn) #endif } +nng_http_req * +nng_http_conn_req(nng_http_conn *conn) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_conn_req(conn)); +#else + return (NULL); +#endif +} + +nng_http_res * +nng_http_conn_res(nng_http_conn *conn) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_conn_res(conn)); +#else + return (NULL); +#endif +} + void nng_http_conn_close(nng_http_conn *conn) { @@ -875,15 +907,12 @@ nng_http_client_transact( } void -nng_http_conn_transact( - nng_http_conn *conn, nng_http_req *req, nng_http_res *res, nng_aio *aio) +nng_http_conn_transact(nng_http_conn *conn, nng_aio *aio) { #ifdef NNG_SUPP_HTTP - nni_http_transact_conn(conn, req, res, aio); + nni_http_transact_conn(conn, aio); #else NNI_ARG_UNUSED(conn); - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(res); nni_aio_finish_error(aio, NNG_ENOTSUP); #endif } |
