aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2025-01-05 16:46:03 -0800
committerGarrett D'Amore <garrett@damore.org>2025-01-06 13:58:07 -0800
commitf42d0c6ef956d119e8762a3ecda37886fa055637 (patch)
tree1744a559dafafdfecd906608888bf0cb9f6c4d10 /src
parentbce6a79fc55852032e9d653b099a121353aaa238 (diff)
downloadnng-f42d0c6ef956d119e8762a3ecda37886fa055637.tar.gz
nng-f42d0c6ef956d119e8762a3ecda37886fa055637.tar.bz2
nng-f42d0c6ef956d119e8762a3ecda37886fa055637.zip
http: server callback API simplified
This simplified API lets callbacks obtain the response from the connection objection directly, and does not require the aio to carry it as a parameter. Further, the request and response are both stored inline in the connection, reducing allocations. This is at present only for the server; the client will get a similar set of changes.
Diffstat (limited to 'src')
-rw-r--r--src/supplemental/http/http_api.h17
-rw-r--r--src/supplemental/http/http_conn.c36
-rw-r--r--src/supplemental/http/http_msg.c46
-rw-r--r--src/supplemental/http/http_public.c12
-rw-r--r--src/supplemental/http/http_server.c230
-rw-r--r--src/supplemental/http/http_server_test.c12
-rw-r--r--src/supplemental/websocket/websocket.c78
7 files changed, 197 insertions, 234 deletions
diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h
index a6dfa6ca..1630198d 100644
--- a/src/supplemental/http/http_api.h
+++ b/src/supplemental/http/http_api.h
@@ -114,12 +114,13 @@ extern int nni_http_conn_getopt(
extern int nni_http_req_alloc(nni_http_req **, const nng_url *);
extern int nni_http_res_alloc(nni_http_res **);
extern int nni_http_res_alloc_error(nni_http_res **, uint16_t);
+extern int nni_http_res_set_error(nni_http_res *, uint16_t);
extern void nni_http_req_free(nni_http_req *);
extern void nni_http_res_free(nni_http_res *);
extern void nni_http_write_req(nni_http_conn *, nni_http_req *, nni_aio *);
-extern void nni_http_write_res(nni_http_conn *, nni_http_res *, nni_aio *);
-extern void nni_http_read_req(nni_http_conn *, nni_http_req *, nni_aio *);
extern void nni_http_read_res(nni_http_conn *, nni_http_res *, 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 *);
@@ -258,15 +259,8 @@ extern int nni_http_hijack(nni_http_conn *);
// Note that methods which modify a handler cannot be called while the handler
// is registered with the server, and that a handler can only be registered
// once per server.
-//
-// The callback function will receive the following arguments (via
-// nng_aio_get_input(): nni_http_request *, nni_http_handler *, and
-// nni_http_conn_t *. The first is a request object, for convenience.
-// The second is the handler, from which the callback can obtain any other
-// data it has set. The final is the http context, from which its possible
-// to hijack the session.
extern int nni_http_handler_init(
- nni_http_handler **, const char *, void (*)(nni_aio *));
+ nni_http_handler **, const char *, nng_http_handler_func);
// nni_http_handler_init_file creates a handler with a function to serve
// up a file named in the last argument.
@@ -395,4 +389,7 @@ extern void nni_http_transact(
// upper layer scheme.
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);
+
#endif // NNG_SUPPLEMENTAL_HTTP_HTTP_API_H
diff --git a/src/supplemental/http/http_conn.c b/src/supplemental/http/http_conn.c
index 912f2cc9..9ed882f1 100644
--- a/src/supplemental/http/http_conn.c
+++ b/src/supplemental/http/http_conn.c
@@ -63,6 +63,8 @@ struct nng_http_conn {
size_t rd_bufsz;
bool rd_buffered;
+ bool res_sent;
+
enum write_flavor wr_flavor;
};
@@ -509,10 +511,13 @@ http_wr_submit(nni_http_conn *conn, nni_aio *aio, enum write_flavor flavor)
}
void
-nni_http_read_req(nni_http_conn *conn, nni_http_req *req, nni_aio *aio)
+nni_http_read_req(nni_http_conn *conn, nni_aio *aio)
{
- nni_aio_set_prov_data(aio, req);
+ nni_aio_set_prov_data(aio, &conn->req);
+ // clear the sent flag (used for the server)
+ conn->res_sent = false;
+ nni_http_req_reset(&conn->req);
nni_mtx_lock(&conn->mtx);
http_rd_submit(conn, aio, HTTP_RD_REQ);
nni_mtx_unlock(&conn->mtx);
@@ -590,16 +595,18 @@ nni_http_write_req(nni_http_conn *conn, nni_http_req *req, nni_aio *aio)
}
void
-nni_http_write_res(nni_http_conn *conn, nni_http_res *res, nni_aio *aio)
+nni_http_write_res(nni_http_conn *conn, nni_aio *aio)
{
- int rv;
- void *buf;
- size_t bufsz;
- void *data;
- size_t size;
- nni_iov iov[2];
- int nio;
-
+ int rv;
+ void *buf;
+ size_t bufsz;
+ void *data;
+ size_t size;
+ nni_iov iov[2];
+ int nio;
+ nng_http_res *res = nng_http_conn_res(conn);
+
+ conn->res_sent = true;
if ((rv = nni_http_res_get_buf(res, &buf, &bufsz)) != 0) {
nni_aio_finish_error(aio, rv);
return;
@@ -713,3 +720,10 @@ nni_http_conn_init(nni_http_conn **connp, nng_stream *stream)
}
return (rv);
}
+
+// private to the HTTP framework, used on the server
+bool
+nni_http_conn_res_sent(nni_http_conn *conn)
+{
+ return (conn->res_sent);
+}
diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c
index 08c594ac..6b12496c 100644
--- a/src/supplemental/http/http_msg.c
+++ b/src/supplemental/http/http_msg.c
@@ -263,8 +263,10 @@ static int
http_entity_alloc_data(nni_http_entity *entity, size_t size)
{
void *newdata;
- if ((newdata = nni_zalloc(size)) == NULL) {
- return (NNG_ENOMEM);
+ if (size != 0) {
+ if ((newdata = nni_zalloc(size)) == NULL) {
+ return (NNG_ENOMEM);
+ }
}
http_entity_set_data(entity, newdata, size);
entity->own = true;
@@ -1057,25 +1059,37 @@ nni_http_alloc_html_error(char **html, uint16_t code, const char *details)
}
int
-nni_http_res_alloc_error(nni_http_res **resp, uint16_t err)
+nni_http_res_set_error(nni_http_res *res, uint16_t err)
{
- char *html = NULL;
- nni_http_res *res = NULL;
- int rv;
-
- if (((rv = nni_http_res_alloc(&res)) != 0) ||
- ((rv = nni_http_alloc_html_error(&html, err, NULL)) != 0) ||
+ int rv;
+ char *html = NULL;
+ if (((rv = nni_http_alloc_html_error(&html, err, NULL)) != 0) ||
((rv = nni_http_res_set_header(
res, "Content-Type", "text/html; charset=UTF-8")) != 0) ||
((rv = nni_http_res_copy_data(res, html, strlen(html))) != 0)) {
nni_strfree(html);
- nni_http_res_free(res);
- } else {
- nni_strfree(html);
- res->code = err;
- res->iserr = true;
- *resp = res;
+ return (rv);
}
+ nni_strfree(html);
+ res->code = err;
+ res->iserr = true;
+ return (0);
+}
- return (rv);
+int
+nni_http_res_alloc_error(nni_http_res **resp, uint16_t err)
+{
+ nni_http_res *res;
+ int rv;
+
+ if ((rv = nni_http_res_alloc(&res)) != 0) {
+ return (rv);
+ }
+ rv = nni_http_res_set_error(res, err);
+ if (rv != 0) {
+ nni_http_res_free(res);
+ return (rv);
+ }
+ *resp = res;
+ return (0);
}
diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c
index 8a81404e..dd35151a 100644
--- a/src/supplemental/http/http_public.c
+++ b/src/supplemental/http/http_public.c
@@ -482,25 +482,23 @@ nng_http_conn_write_req(nng_http_conn *conn, nng_http_req *req, nng_aio *aio)
}
void
-nng_http_conn_write_res(nng_http_conn *conn, nng_http_res *res, nng_aio *aio)
+nng_http_conn_write_res(nng_http_conn *conn, nng_aio *aio)
{
#ifdef NNG_SUPP_HTTP
- nni_http_write_res(conn, res, aio);
+ nni_http_write_res(conn, aio);
#else
NNI_ARG_UNUSED(conn);
- NNI_ARG_UNUSED(res);
nni_aio_finish_error(aio, NNG_ENOTSUP);
#endif
}
void
-nng_http_conn_read_req(nng_http_conn *conn, nng_http_req *req, nng_aio *aio)
+nng_http_conn_read_req(nng_http_conn *conn, nng_aio *aio)
{
#ifdef NNG_SUPP_HTTP
- nni_http_read_req(conn, req, aio);
+ nni_http_read_req(conn, aio);
#else
NNI_ARG_UNUSED(conn);
- NNI_ARG_UNUSED(req);
nni_aio_finish_error(aio, NNG_ENOTSUP);
#endif
}
@@ -519,7 +517,7 @@ nng_http_conn_read_res(nng_http_conn *conn, nng_http_res *res, nng_aio *aio)
int
nng_http_handler_alloc(
- nng_http_handler **hp, const char *uri, void (*cb)(nng_aio *))
+ nng_http_handler **hp, const char *uri, nng_http_handler_func cb)
{
#ifdef NNG_SUPP_HTTP
return (nni_http_handler_init(hp, uri, cb));
diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c
index c6c453c9..87285417 100644
--- a/src/supplemental/http/http_server.c
+++ b/src/supplemental/http/http_server.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>
// Copyright 2018 QXSoftware <lh563566994@126.com>
// Copyright 2019 Devolutions <info@devolutions.net>
@@ -20,35 +20,35 @@
#include "core/nng_impl.h"
#include "http_api.h"
+#include "nng/supplemental/http/http.h"
#ifndef NNG_HTTP_MAX_URI
#define NNG_HTTP_MAX_URI 1024
#endif
struct nng_http_handler {
- nni_list_node node;
- char uri[NNG_HTTP_MAX_URI];
- char method[32];
- char host[256]; // RFC 1035
- nng_sockaddr host_addr;
- bool host_ip;
- bool tree;
- bool tree_exclusive;
- nni_atomic_int ref;
- nni_atomic_bool busy;
- size_t maxbody;
- bool getbody;
- void *data;
- nni_cb dtor;
- void (*cb)(nni_aio *);
+ nni_list_node node;
+ char uri[NNG_HTTP_MAX_URI];
+ char method[32];
+ char host[256]; // RFC 1035
+ nng_sockaddr host_addr;
+ bool host_ip;
+ bool tree;
+ bool tree_exclusive;
+ nni_atomic_int ref;
+ nni_atomic_bool busy;
+ size_t maxbody;
+ bool getbody;
+ void *data;
+ nni_cb dtor;
+ nng_http_handler_func cb;
+ void *arg;
};
typedef struct http_sconn {
nni_list_node node;
nni_http_conn *conn;
nni_http_server *server;
- nni_http_req *req;
- nni_http_res *res;
nni_http_handler *handler; // set if we deferred to read body
nni_http_handler *release; // set if we dispatched handler
bool close;
@@ -103,7 +103,7 @@ static nni_reap_list http_server_reap_list = {
int
nni_http_handler_init(
- nni_http_handler **hp, const char *uri, void (*cb)(nni_aio *))
+ nni_http_handler **hp, const char *uri, nng_http_handler_func cb)
{
nni_http_handler *h;
@@ -255,8 +255,6 @@ http_sc_reap(void *arg)
if (sc->conn != NULL) {
nni_http_conn_fini(sc->conn);
}
- nni_http_req_free(sc->req);
- nni_http_res_free(sc->res);
nni_aio_fini(&sc->rxaio);
nni_aio_fini(&sc->txaio);
nni_aio_fini(&sc->txdataio);
@@ -307,17 +305,13 @@ http_sconn_txdatdone(void *arg)
return;
}
- nni_http_res_free(sc->res);
- sc->res = NULL;
-
if (sc->close) {
http_sconn_close(sc);
return;
}
sc->handler = NULL;
- nni_http_req_reset(sc->req);
- nni_http_read_req(sc->conn, sc->req, &sc->rxaio);
+ nni_http_read_req(sc->conn, &sc->rxaio);
}
static void
@@ -336,11 +330,8 @@ http_sconn_txdone(void *arg)
return;
}
- nni_http_res_free(sc->res);
- sc->res = NULL;
sc->handler = NULL;
- nni_http_req_reset(sc->req);
- nni_http_read_req(sc->conn, sc->req, &sc->rxaio);
+ nni_http_read_req(sc->conn, &sc->rxaio);
}
static char
@@ -425,26 +416,20 @@ http_sconn_error(http_sconn *sc, uint16_t err)
{
nni_http_res *res;
- if (nni_http_res_alloc(&res) != 0) {
- http_sconn_close(sc);
- return;
- }
+ res = nng_http_conn_res(sc->conn);
nni_http_res_set_status(res, err);
if (nni_http_server_res_error(sc->server, res) != 0) {
- nni_http_res_free(res);
http_sconn_close(sc);
return;
}
if (sc->close) {
if (nni_http_res_set_header(res, "Connection", "close") != 0) {
- nni_http_res_free(res);
http_sconn_close(sc);
return;
}
}
- sc->res = res;
- nni_http_write_res(sc->conn, res, &sc->txaio);
+ nni_http_write_res(sc->conn, &sc->txaio);
}
int
@@ -459,7 +444,6 @@ nni_http_hijack(nni_http_conn *conn)
nni_mtx_lock(&s->mtx);
sc->conn = NULL;
- sc->req = NULL;
nni_mtx_unlock(&s->mtx);
}
return (0);
@@ -531,7 +515,7 @@ http_sconn_rxdone(void *arg)
nni_http_handler *h = NULL;
nni_http_handler *head = NULL;
const char *val;
- nni_http_req *req = sc->req;
+ nni_http_req *req = nng_http_conn_req(sc->conn);
char *uri;
size_t urisz;
char *path;
@@ -693,9 +677,6 @@ http_sconn_rxdone(void *arg)
finish:
sc->release = h;
sc->handler = NULL;
- nni_aio_set_input(&sc->cbaio, 0, sc->req);
- nni_aio_set_input(&sc->cbaio, 1, h);
- nni_aio_set_input(&sc->cbaio, 2, sc->conn);
// Set a reference -- this because the callback may be running
// asynchronously even after it gets removed from the server.
@@ -704,7 +685,11 @@ finish:
nni_aio_reset(&sc->cbaio);
nni_mtx_unlock(&s->mtx);
- h->cb(&sc->cbaio);
+
+ // make sure the response is freshly initialized
+ nni_http_res_reset(nni_http_conn_res(sc->conn));
+
+ h->cb(sc->conn, h->data, &sc->cbaio);
}
static void
@@ -730,8 +715,6 @@ http_sconn_cbdone(void *arg)
return;
}
- res = nni_aio_get_output(aio, 0);
-
// If it's an upgrader, and they didn't give us back a response,
// it means that they took over, and we should just discard
// this session, without closing the underlying channel.
@@ -741,7 +724,8 @@ http_sconn_cbdone(void *arg)
http_sconn_close(sc);
return;
}
- if (res != NULL) {
+ res = nni_http_conn_res(sc->conn);
+ if (!nni_http_conn_res_sent(sc->conn)) {
const char *val;
val = nni_http_res_get_header(res, "Connection");
if ((val != NULL) && (strstr(val, "close") != NULL)) {
@@ -750,8 +734,9 @@ http_sconn_cbdone(void *arg)
if (sc->close) {
nni_http_res_set_header(res, "Connection", "close");
}
- sc->res = res;
- if (strcmp(nni_http_req_get_method(sc->req), "HEAD") == 0) {
+ if (strcmp(
+ nni_http_req_get_method(nng_http_conn_req(sc->conn)),
+ "HEAD") == 0) {
void *data;
size_t size;
// prune off the data, but preserve the content-length
@@ -763,15 +748,14 @@ http_sconn_cbdone(void *arg)
} else if (nni_http_res_is_error(res)) {
(void) nni_http_server_res_error(s, res);
}
- nni_http_write_res(sc->conn, res, &sc->txaio);
+ nni_http_write_res(sc->conn, &sc->txaio);
} else if (sc->close) {
http_sconn_close(sc);
} else {
// Presumably client already sent a response.
// Wait for another request.
sc->handler = NULL;
- nni_http_req_reset(sc->req);
- nni_http_read_req(sc->conn, sc->req, &sc->rxaio);
+ nni_http_read_req(sc->conn, &sc->rxaio);
}
}
@@ -791,8 +775,7 @@ http_sconn_init(http_sconn **scp, nng_stream *stream)
nni_aio_init(&sc->txdataio, http_sconn_txdatdone, sc);
nni_aio_init(&sc->cbaio, http_sconn_cbdone, sc);
- if (((rv = nni_http_req_alloc(&sc->req, NULL)) != 0) ||
- ((rv = nni_http_conn_init(&sc->conn, stream)) != 0)) {
+ if ((rv = nni_http_conn_init(&sc->conn, stream)) != 0) {
// Can't even accept the incoming request. Hard close.
http_sconn_close(sc);
return (rv);
@@ -839,7 +822,7 @@ http_server_acccb(void *arg)
nni_list_append(&s->conns, sc);
sc->handler = NULL;
- nni_http_read_req(sc->conn, sc->req, &sc->rxaio);
+ nni_http_read_req(sc->conn, &sc->rxaio);
nng_stream_listener_accept(s->listener, aio);
nni_mtx_unlock(&s->mtx);
}
@@ -1333,20 +1316,20 @@ http_lookup_type(const char *path)
}
typedef struct http_file {
+ char *base;
char *path;
char *ctype;
} http_file;
static void
-http_handle_file(nni_aio *aio)
+http_handle_file(nni_http_conn *conn, void *arg, nni_aio *aio)
{
- nni_http_handler *h = nni_aio_get_input(aio, 1);
- nni_http_res *res = NULL;
- void *data;
- size_t size;
- int rv;
- http_file *hf = nni_http_handler_get_data(h);
- const char *ctype;
+ nni_http_res *res = nng_http_conn_res(conn);
+ void *data;
+ size_t size;
+ int rv;
+ http_file *hf = arg;
+ const char *ctype;
if ((ctype = hf->ctype) == NULL) {
ctype = "application/octet-stream";
@@ -1373,7 +1356,7 @@ http_handle_file(nni_aio *aio)
status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
break;
}
- if ((rv = nni_http_res_alloc_error(&res, status)) != 0) {
+ if ((rv = nni_http_res_set_error(res, status)) != 0) {
nni_aio_finish_error(aio, rv);
return;
}
@@ -1381,11 +1364,9 @@ http_handle_file(nni_aio *aio)
nni_aio_finish(aio, 0, 0);
return;
}
- if (((rv = nni_http_res_alloc(&res)) != 0) ||
- ((rv = nni_http_res_set_header(res, "Content-Type", ctype)) !=
+ if (((rv = nni_http_res_set_header(res, "Content-Type", ctype)) !=
0) ||
((rv = nni_http_res_copy_data(res, data, size)) != 0)) {
- nni_http_res_free(res);
nni_free(data, size);
nni_aio_finish_error(aio, rv);
return;
@@ -1405,6 +1386,7 @@ http_file_free(void *arg)
if ((hf = arg) != NULL) {
nni_strfree(hf->path);
nni_strfree(hf->ctype);
+ nni_strfree(hf->base);
NNI_FREE_STRUCT(hf);
}
}
@@ -1457,23 +1439,22 @@ nni_http_handler_init_file(
}
static void
-http_handle_dir(nni_aio *aio)
+http_handle_dir(nng_http_conn *conn, void *arg, nng_aio *aio)
{
- nni_http_req *req = nni_aio_get_input(aio, 0);
- nni_http_handler *h = nni_aio_get_input(aio, 1);
- nni_http_res *res = NULL;
- void *data;
- size_t size;
- int rv;
- http_file *hf = nni_http_handler_get_data(h);
- const char *path = hf->path;
- const char *base = nni_http_handler_get_uri(h); // base uri
- const char *uri = nni_http_req_get_uri(req);
- const char *ctype;
- char *dst;
- size_t len;
- size_t pnsz;
- char *pn;
+ nni_http_req *req = nni_http_conn_req(conn);
+ nni_http_res *res = nni_http_conn_res(conn);
+ void *data;
+ size_t size;
+ int rv;
+ http_file *hf = arg;
+ const char *path = hf->path;
+ const char *base = hf->base;
+ const char *uri = nni_http_req_get_uri(req);
+ const char *ctype;
+ char *dst;
+ size_t len;
+ size_t pnsz;
+ char *pn;
len = strlen(base);
if (base[1] != '\0' && // Allows "/" as base
@@ -1563,7 +1544,7 @@ http_handle_dir(nni_aio *aio)
status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
break;
}
- if ((rv = nni_http_res_alloc_error(&res, status)) != 0) {
+ if ((rv = nni_http_res_set_error(res, status)) != 0) {
nni_aio_finish_error(aio, rv);
return;
}
@@ -1572,11 +1553,9 @@ http_handle_dir(nni_aio *aio)
return;
}
- if (((rv = nni_http_res_alloc(&res)) != 0) ||
- ((rv = nni_http_res_set_header(res, "Content-Type", ctype)) !=
+ if (((rv = nni_http_res_set_header(res, "Content-Type", ctype)) !=
0) ||
((rv = nni_http_res_copy_data(res, data, size)) != 0)) {
- nni_http_res_free(res);
nni_free(data, size);
nni_aio_finish_error(aio, rv);
return;
@@ -1600,8 +1579,9 @@ nni_http_handler_init_directory(
if ((hf = NNI_ALLOC_STRUCT(hf)) == NULL) {
return (NNG_ENOMEM);
}
- if ((hf->path = nni_strdup(path)) == NULL) {
- NNI_FREE_STRUCT(hf);
+ if (((hf->path = nni_strdup(path)) == NULL) ||
+ ((hf->base = nni_strdup(uri)) == NULL)) {
+ http_file_free(hf);
return (NNG_ENOMEM);
}
@@ -1621,29 +1601,25 @@ nni_http_handler_init_directory(
typedef struct http_redirect {
uint16_t code;
char *where;
+ char *from;
} http_redirect;
static void
-http_handle_redirect(nni_aio *aio)
+http_handle_redirect(nng_http_conn *conn, void *data, nng_aio *aio)
{
- nni_http_res *r = NULL;
- char *html = NULL;
- char *msg = NULL;
- char *loc = NULL;
- http_redirect *hr;
- nni_http_handler *h;
- int rv;
- nni_http_req *req;
- const char *base;
- const char *uri;
-
- req = nni_aio_get_input(aio, 0);
- h = nni_aio_get_input(aio, 1);
- base = nni_http_handler_get_uri(h); // base uri
+ nni_http_res *res = nng_http_conn_res(conn);
+ nni_http_req *req = nng_http_conn_req(conn);
+ char *html = NULL;
+ char *msg = NULL;
+ char *loc = NULL;
+ http_redirect *hr = data;
+ int rv;
+ const char *base;
+ const char *uri;
+
+ base = hr->from; // base uri
uri = nni_http_req_get_uri(req);
- hr = nni_http_handler_get_data(h);
-
// If we are doing a full tree, then include the entire suffix.
if (strncmp(uri, base, strlen(base)) == 0) {
rv = nni_asprintf(&loc, "%s%s", hr->where, uri + strlen(base));
@@ -1664,31 +1640,31 @@ http_handle_redirect(nni_aio *aio)
// because it is probably going to another server. This also
// keeps us from having to consume the entity body, we can just
// discard it.
- if ((rv != 0) || ((rv = nni_http_res_alloc(&r)) != 0) ||
+ if ((rv != 0) ||
((rv = nni_http_alloc_html_error(&html, hr->code, msg)) != 0) ||
- ((rv = nni_http_res_set_header(r, "Connection", "close")) != 0) ||
+ ((rv = nni_http_res_set_header(res, "Connection", "close")) !=
+ 0) ||
((rv = nni_http_res_set_header(
- r, "Content-Type", "text/html; charset=UTF-8")) != 0) ||
- ((rv = nni_http_res_set_header(r, "Location", loc)) != 0) ||
- ((rv = nni_http_res_copy_data(r, html, strlen(html))) != 0)) {
+ res, "Content-Type", "text/html; charset=UTF-8")) != 0) ||
+ ((rv = nni_http_res_set_header(res, "Location", loc)) != 0) ||
+ ((rv = nni_http_res_copy_data(res, html, strlen(html))) != 0)) {
if (loc != hr->where) {
nni_strfree(loc);
}
nni_strfree(msg);
nni_strfree(html);
- nni_http_res_free(r);
nni_aio_finish_error(aio, rv);
return;
}
- nni_http_res_set_status(r, hr->code);
+ nni_http_res_set_status(res, hr->code);
if (loc != hr->where) {
nni_strfree(loc);
}
nni_strfree(msg);
nni_strfree(html);
- nni_aio_set_output(aio, 0, r);
+ nni_aio_set_output(aio, 0, res);
nni_aio_finish(aio, 0, 0);
}
@@ -1699,6 +1675,7 @@ http_redirect_free(void *arg)
if ((hr = arg) != NULL) {
nni_strfree(hr->where);
+ nni_strfree(hr->from);
NNI_FREE_STRUCT(hr);
}
}
@@ -1714,8 +1691,9 @@ nni_http_handler_init_redirect(nni_http_handler **hpp, const char *uri,
if ((hr = NNI_ALLOC_STRUCT(hr)) == NULL) {
return (NNG_ENOMEM);
}
- if ((hr->where = nni_strdup(where)) == NULL) {
- NNI_FREE_STRUCT(hr);
+ if (((hr->where = nni_strdup(where)) == NULL) ||
+ ((hr->from = nni_strdup(uri)) == NULL)) {
+ http_redirect_free(hr);
return (NNG_ENOMEM);
}
if (status == 0) {
@@ -1747,25 +1725,21 @@ typedef struct http_static {
} http_static;
static void
-http_handle_static(nni_aio *aio)
+http_handle_static(nng_http_conn *conn, void *data, nni_aio *aio)
{
- http_static *hs;
- const char *ctype;
- nni_http_handler *h;
- nni_http_res *r = NULL;
- int rv;
-
- h = nni_aio_get_input(aio, 1);
- hs = nni_http_handler_get_data(h);
+ http_static *hs = data;
+ const char *ctype;
+ nni_http_res *r = NULL;
+ int rv;
if ((ctype = hs->ctype) == NULL) {
ctype = "application/octet-stream";
}
- if (((rv = nni_http_res_alloc(&r)) != 0) ||
- ((rv = nni_http_res_set_header(r, "Content-Type", ctype)) != 0) ||
+ r = nng_http_conn_res(conn);
+ nng_http_res_reset(r);
+ if (((rv = nni_http_res_set_header(r, "Content-Type", ctype)) != 0) ||
((rv = nni_http_res_set_data(r, hs->data, hs->size)) != 0)) {
- nni_http_res_free(r);
nni_aio_finish_error(aio, rv);
return;
}
diff --git a/src/supplemental/http/http_server_test.c b/src/supplemental/http/http_server_test.c
index 37c45f14..91411499 100644
--- a/src/supplemental/http/http_server_test.c
+++ b/src/supplemental/http/http_server_test.c
@@ -10,6 +10,7 @@
//
// Basic HTTP server tests.
+#include "core/defs.h"
#include <nng/nng.h>
#include <nng/supplemental/http/http.h>
@@ -141,21 +142,20 @@ fail:
}
static void
-httpecho(nng_aio *aio)
+httpecho(nng_http_conn *conn, void *arg, nng_aio *aio)
{
- nng_http_req *req = nng_aio_get_input(aio, 0);
- nng_http_res *res;
+ nng_http_req *req = nng_http_conn_req(conn);
+ nng_http_res *res = nng_http_conn_res(conn);
int rv;
void *body;
size_t len;
+ NNI_ARG_UNUSED(arg);
nng_http_req_get_data(req, &body, &len);
- if (((rv = nng_http_res_alloc(&res)) != 0) ||
- ((rv = nng_http_res_copy_data(res, body, len)) != 0) ||
+ if (((rv = nng_http_res_copy_data(res, body, len)) != 0) ||
((rv = nng_http_res_set_header(
res, "Content-type", "text/plain")) != 0)) {
- nng_http_res_free(res);
nng_aio_finish(aio, rv);
return;
}
diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c
index 84d3fd72..70323b0c 100644
--- a/src/supplemental/websocket/websocket.c
+++ b/src/supplemental/websocket/websocket.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>
// Copyright 2019 Devolutions <info@devolutions.net>
//
@@ -1243,12 +1243,6 @@ ws_fini(void *arg)
if (ws->http) {
nni_http_conn_fini(ws->http);
}
- if (ws->req) {
- nni_http_req_free(ws->req);
- }
- if (ws->res) {
- nni_http_res_free(ws->res);
- }
nni_strfree(ws->reqhdrs);
nni_strfree(ws->reshdrs);
@@ -1332,9 +1326,7 @@ ws_http_cb_dialer(nni_ws *ws, nni_aio *aio)
// If we have no response structure, then this was completion
// of sending the request. Prepare an empty response, and read it.
if (ws->res == NULL) {
- if ((rv = nni_http_res_alloc(&ws->res)) != 0) {
- goto err;
- }
+ ws->res = nni_http_conn_res(ws->http);
nni_http_read_res(ws->http, ws->res, &ws->httpaio);
nni_mtx_unlock(&d->mtx);
return;
@@ -1514,25 +1506,19 @@ ws_listener_free(void *arg)
}
static void
-ws_handler(nni_aio *aio)
+ws_handler(nng_http_conn *conn, void *arg, nng_aio *aio)
{
- nni_ws_listener *l;
- nni_ws *ws;
- nni_http_conn *conn;
- nni_http_req *req;
- nni_http_res *res;
- nni_http_handler *h;
- const char *ptr;
- const char *proto;
- uint16_t status;
- int rv;
- char key[29];
- ws_header *hdr;
-
- req = nni_aio_get_input(aio, 0);
- h = nni_aio_get_input(aio, 1);
- conn = nni_aio_get_input(aio, 2);
- l = nni_http_handler_get_data(h);
+ nni_ws_listener *l = arg;
+ ;
+ nni_http_req *req = nng_http_conn_req(conn);
+ nni_http_res *res = nng_http_conn_res(conn);
+ nni_ws *ws;
+ const char *ptr;
+ const char *proto;
+ uint16_t status;
+ int rv;
+ char key[29];
+ ws_header *hdr;
nni_mtx_lock(&l->mtx);
if (l->closed) {
@@ -1595,24 +1581,16 @@ ws_handler(nni_aio *aio)
goto err;
}
- if ((rv = nni_http_res_alloc(&res)) != 0) {
- // Give a chance to reply to client.
- status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
- goto err;
- }
-
nni_http_res_set_status(res, NNG_HTTP_STATUS_SWITCHING);
if ((SETH("Connection", "Upgrade") != 0) ||
(SETH("Upgrade", "websocket") != 0) ||
(SETH("Sec-WebSocket-Accept", key) != 0)) {
status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
- nni_http_res_free(res);
goto err;
}
if ((proto != NULL) && (SETH("Sec-WebSocket-Protocol", proto) != 0)) {
status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
- nni_http_res_free(res);
goto err;
}
@@ -1621,7 +1599,6 @@ ws_handler(nni_aio *aio)
NNI_LIST_FOREACH (&l->headers, hdr) {
if (SETH(hdr->name, hdr->value) != 0) {
status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
- nni_http_res_free(res);
goto err;
}
}
@@ -1633,7 +1610,6 @@ ws_handler(nni_aio *aio)
if (l->hookfn != NULL) {
rv = l->hookfn(l->hookarg, req, res);
if (rv != 0) {
- nni_http_res_free(res);
nni_aio_finish_error(aio, rv);
nni_mtx_unlock(&l->mtx);
return;
@@ -1649,7 +1625,6 @@ ws_handler(nni_aio *aio)
// the hook can also give back various other
// headers, but it would be bad for it to alter
// the websocket mandated headers.)
- nni_http_req_free(req);
nni_aio_set_output(aio, 0, res);
nni_aio_finish(aio, 0, 0);
nni_mtx_unlock(&l->mtx);
@@ -1663,8 +1638,6 @@ ws_handler(nni_aio *aio)
// We are good to go, provided we can get the websocket struct,
// and send the reply.
if ((rv = ws_init(&ws)) != 0) {
- nni_http_req_free(req);
- nni_http_res_free(res);
status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
goto err;
}
@@ -1681,7 +1654,7 @@ ws_handler(nni_aio *aio)
ws->listener = l;
nni_list_append(&l->reply, ws);
- nni_http_write_res(conn, res, &ws->httpaio);
+ nni_http_write_res(conn, &ws->httpaio);
(void) nni_http_hijack(conn);
nni_aio_set_output(aio, 0, NULL);
nni_aio_finish(aio, 0, 0);
@@ -1689,7 +1662,7 @@ ws_handler(nni_aio *aio)
return;
err:
- if ((rv = nni_http_res_alloc_error(&res, status)) != 0) {
+ if ((rv = nni_http_res_set_error(res, status)) != 0) {
nni_aio_finish_error(aio, rv);
} else {
nni_aio_set_output(aio, 0, res);
@@ -2174,7 +2147,6 @@ ws_conn_cb(void *arg)
nni_ws_dialer *d;
nni_ws *ws;
nni_aio *uaio;
- nni_http_conn *http;
nni_http_req *req = NULL;
int rv;
uint8_t raw[16];
@@ -2206,13 +2178,12 @@ ws_conn_cb(void *arg)
return;
}
+ ws->http = nni_aio_get_output(&ws->connaio, 0);
nni_mtx_lock(&ws->mtx);
uaio = ws->useraio;
- http = nni_aio_get_output(&ws->connaio, 0);
nni_aio_set_output(&ws->connaio, 0, NULL);
if (uaio == NULL) {
// This request was canceled for some reason.
- nni_http_conn_fini(http);
nni_mtx_unlock(&ws->mtx);
ws_reap(ws);
return;
@@ -2224,8 +2195,10 @@ ws_conn_cb(void *arg)
nni_base64_encode(raw, 16, wskey, 24);
wskey[24] = '\0';
+ req = nni_http_conn_req(ws->http);
+
#define SETH(h, v) nni_http_req_set_header(req, h, v)
- if ((rv != 0) || ((rv = nni_http_req_alloc(&req, d->url)) != 0) ||
+ if ((rv != 0) || ((rv = nni_http_req_set_url(req, d->url)) != 0) ||
((rv = SETH("Upgrade", "websocket")) != 0) ||
((rv = SETH("Connection", "Upgrade")) != 0) ||
((rv = SETH("Sec-WebSocket-Key", wskey)) != 0) ||
@@ -2245,22 +2218,15 @@ ws_conn_cb(void *arg)
}
#undef SETH
- ws->http = http;
- ws->req = req;
+ ws->req = req;
- nni_http_write_req(http, req, &ws->httpaio);
+ nni_http_write_req(ws->http, req, &ws->httpaio);
nni_mtx_unlock(&ws->mtx);
return;
err:
nni_aio_finish_error(uaio, rv);
nni_mtx_unlock(&ws->mtx);
- if (http != NULL) {
- nni_http_conn_fini(http);
- }
- if (req != NULL) {
- nni_http_req_free(req);
- }
ws_reap(ws);
}