From 73f50e2679525e7df8734c875a3c12732565f953 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 6 Jan 2025 15:20:09 -0800 Subject: [PATCH] http: The big HTTP API refactoring of January 2025. This represents a major change in the HTTP code base, consisting of a complete revamp of the HTTP API. The changes here are too numerous to mention, but the end result should be a vastly simpler API for both server and client applications. Many needless allocations were removed by providing fixed buffers for various parameters and headers when possible. A few bugs were fixed. Most especially we have fixed some bugs around very large URIs and headers, and we have also addressed conformance bugs to more closely conform to RFCs 9110 and 9112. As part of this work, the APIs for WebSockets changed slightly as well. In particular the properties available for accessing headers have changed. There is still documentation conversion work to do, and additional functionality (such as proper support for chunked transfers), but this is a big step in the right direction. --- demo/http_client/http_client.c | 25 +- demo/reqrep/reqrep.c | 1 - demo/rest/server.c | 63 +- docs/man/libnng.3.adoc | 39 - docs/man/nng.7.adoc | 1 - docs/man/nng_http_client_alloc.3http.adoc | 49 -- docs/man/nng_http_client_connect.3http.adoc | 98 --- docs/man/nng_http_client_free.3http.adoc | 48 -- docs/man/nng_http_client_get_tls.3http.adoc | 59 -- docs/man/nng_http_client_set_tls.3http.adoc | 57 -- docs/man/nng_http_client_transact.3http.adoc | 84 -- docs/man/nng_http_conn_close.3http.adoc | 47 -- docs/man/nng_http_conn_read.3http.adoc | 77 -- docs/man/nng_http_conn_read_all.3http.adoc | 78 -- docs/man/nng_http_conn_read_req.3http.adoc | 66 -- docs/man/nng_http_conn_read_res.3http.adoc | 75 -- docs/man/nng_http_conn_transact.3http.adoc | 93 --- docs/man/nng_http_conn_write.3http.adoc | 76 -- docs/man/nng_http_conn_write_all.3http.adoc | 96 --- docs/man/nng_http_conn_write_req.3http.adoc | 72 -- docs/man/nng_http_conn_write_res.3http.adoc | 80 -- docs/man/nng_http_handler_alloc.3http.adoc | 4 +- .../nng_http_handler_collect_body.3http.adoc | 2 +- docs/man/nng_http_handler_free.3http.adoc | 2 +- docs/man/nng_http_handler_get_data.3http.adoc | 2 +- docs/man/nng_http_handler_set_data.3http.adoc | 2 +- docs/man/nng_http_handler_set_host.3http.adoc | 2 +- .../nng_http_handler_set_method.3http.adoc | 2 +- docs/man/nng_http_handler_set_tree.3http.adoc | 4 +- docs/man/nng_http_hijack.3http.adoc | 65 -- docs/man/nng_http_req_add_header.3http.adoc | 65 -- docs/man/nng_http_req_alloc.3http.adoc | 68 -- docs/man/nng_http_req_copy_data.3http.adoc | 62 -- docs/man/nng_http_req_del_header.3http.adoc | 53 -- docs/man/nng_http_req_free.3http.adoc | 47 -- docs/man/nng_http_req_get_data.3http.adoc | 50 -- docs/man/nng_http_req_get_header.3http.adoc | 52 -- docs/man/nng_http_req_get_method.3http.adoc | 46 -- docs/man/nng_http_req_get_uri.3http.adoc | 47 -- docs/man/nng_http_req_get_version.3http.adoc | 45 - docs/man/nng_http_req_reset.3http.adoc | 48 -- docs/man/nng_http_req_set_data.3http.adoc | 64 -- docs/man/nng_http_req_set_header.3http.adoc | 59 -- docs/man/nng_http_req_set_uri.3http.adoc | 59 -- docs/man/nng_http_req_set_version.3http.adoc | 57 -- docs/man/nng_http_res_add_header.3http.adoc | 65 -- docs/man/nng_http_res_alloc.3http.adoc | 68 -- docs/man/nng_http_res_alloc_error.3http.adoc | 58 -- docs/man/nng_http_res_copy_data.3http.adoc | 62 -- docs/man/nng_http_res_del_header.3http.adoc | 52 -- docs/man/nng_http_res_free.3http.adoc | 47 -- docs/man/nng_http_res_get_data.3http.adoc | 50 -- docs/man/nng_http_res_get_header.3http.adoc | 52 -- docs/man/nng_http_res_get_reason.3http.adoc | 48 -- docs/man/nng_http_res_get_status.3http.adoc | 117 --- docs/man/nng_http_res_get_version.3http.adoc | 45 - docs/man/nng_http_res_reset.3http.adoc | 44 - docs/man/nng_http_res_set_data.3http.adoc | 64 -- docs/man/nng_http_res_set_header.3http.adoc | 59 -- docs/man/nng_http_res_set_status.3http.adoc | 115 --- docs/man/nng_http_res_set_version.3http.adoc | 57 -- .../nng_http_server_add_handler.3http.adoc | 2 +- .../nng_http_server_del_handler.3http.adoc | 2 +- docs/man/nng_http_server_get_addr.3http.adoc | 2 +- docs/man/nng_http_server_get_tls.3http.adoc | 2 +- docs/man/nng_http_server_hold.3http.adoc | 2 +- docs/man/nng_http_server_release.3http.adoc | 2 +- docs/man/nng_http_server_res_error.3http.adoc | 10 +- .../nng_http_server_set_error_file.3http.adoc | 73 -- .../nng_http_server_set_error_page.3http.adoc | 8 +- docs/man/nng_http_server_set_tls.3http.adoc | 2 +- docs/man/nng_http_server_start.3http.adoc | 2 +- docs/man/nng_http_server_stop.3http.adoc | 2 +- ...tp.adoc => nng_http_set_method.3http.adoc} | 21 +- ...tp.adoc => nng_http_set_reason.3http.adoc} | 22 +- docs/man/nng_ws.7.adoc | 15 +- docs/ref/SUMMARY.md | 2 + docs/ref/api/http.md | 572 +++++++++++++ docs/ref/api/index.md | 1 + docs/ref/migrate/nng1.md | 21 +- docs/ref/xref.md | 38 + include/nng/{supplemental/http => }/http.h | 304 +++---- include/nng/nng.h | 23 +- src/CMakeLists.txt | 1 + src/sp/transport/ws/ws_test.c | 11 - src/supplemental/http/CMakeLists.txt | 3 +- src/supplemental/http/http_api.h | 131 +-- src/supplemental/http/http_client.c | 139 ++-- src/supplemental/http/http_conn.c | 744 ++++++++++++++++- src/supplemental/http/http_msg.c | 778 +++--------------- src/supplemental/http/http_msg.h | 33 +- src/supplemental/http/http_public.c | 411 ++------- src/supplemental/http/http_server.c | 260 +++--- src/supplemental/http/http_server_test.c | 284 +++---- src/supplemental/websocket/websocket.c | 348 +++----- src/supplemental/websocket/websocket_test.c | 16 +- tests/httpclient.c | 129 ++- tests/wss.c | 13 - 98 files changed, 2251 insertions(+), 5372 deletions(-) delete mode 100644 docs/man/nng_http_client_alloc.3http.adoc delete mode 100644 docs/man/nng_http_client_connect.3http.adoc delete mode 100644 docs/man/nng_http_client_free.3http.adoc delete mode 100644 docs/man/nng_http_client_get_tls.3http.adoc delete mode 100644 docs/man/nng_http_client_set_tls.3http.adoc delete mode 100644 docs/man/nng_http_client_transact.3http.adoc delete mode 100644 docs/man/nng_http_conn_close.3http.adoc delete mode 100644 docs/man/nng_http_conn_read.3http.adoc delete mode 100644 docs/man/nng_http_conn_read_all.3http.adoc delete mode 100644 docs/man/nng_http_conn_read_req.3http.adoc delete mode 100644 docs/man/nng_http_conn_read_res.3http.adoc delete mode 100644 docs/man/nng_http_conn_transact.3http.adoc delete mode 100644 docs/man/nng_http_conn_write.3http.adoc delete mode 100644 docs/man/nng_http_conn_write_all.3http.adoc delete mode 100644 docs/man/nng_http_conn_write_req.3http.adoc delete mode 100644 docs/man/nng_http_conn_write_res.3http.adoc delete mode 100644 docs/man/nng_http_hijack.3http.adoc delete mode 100644 docs/man/nng_http_req_add_header.3http.adoc delete mode 100644 docs/man/nng_http_req_alloc.3http.adoc delete mode 100644 docs/man/nng_http_req_copy_data.3http.adoc delete mode 100644 docs/man/nng_http_req_del_header.3http.adoc delete mode 100644 docs/man/nng_http_req_free.3http.adoc delete mode 100644 docs/man/nng_http_req_get_data.3http.adoc delete mode 100644 docs/man/nng_http_req_get_header.3http.adoc delete mode 100644 docs/man/nng_http_req_get_method.3http.adoc delete mode 100644 docs/man/nng_http_req_get_uri.3http.adoc delete mode 100644 docs/man/nng_http_req_get_version.3http.adoc delete mode 100644 docs/man/nng_http_req_reset.3http.adoc delete mode 100644 docs/man/nng_http_req_set_data.3http.adoc delete mode 100644 docs/man/nng_http_req_set_header.3http.adoc delete mode 100644 docs/man/nng_http_req_set_uri.3http.adoc delete mode 100644 docs/man/nng_http_req_set_version.3http.adoc delete mode 100644 docs/man/nng_http_res_add_header.3http.adoc delete mode 100644 docs/man/nng_http_res_alloc.3http.adoc delete mode 100644 docs/man/nng_http_res_alloc_error.3http.adoc delete mode 100644 docs/man/nng_http_res_copy_data.3http.adoc delete mode 100644 docs/man/nng_http_res_del_header.3http.adoc delete mode 100644 docs/man/nng_http_res_free.3http.adoc delete mode 100644 docs/man/nng_http_res_get_data.3http.adoc delete mode 100644 docs/man/nng_http_res_get_header.3http.adoc delete mode 100644 docs/man/nng_http_res_get_reason.3http.adoc delete mode 100644 docs/man/nng_http_res_get_status.3http.adoc delete mode 100644 docs/man/nng_http_res_get_version.3http.adoc delete mode 100644 docs/man/nng_http_res_reset.3http.adoc delete mode 100644 docs/man/nng_http_res_set_data.3http.adoc delete mode 100644 docs/man/nng_http_res_set_header.3http.adoc delete mode 100644 docs/man/nng_http_res_set_status.3http.adoc delete mode 100644 docs/man/nng_http_res_set_version.3http.adoc delete mode 100644 docs/man/nng_http_server_set_error_file.3http.adoc rename docs/man/{nng_http_req_set_method.3http.adoc => nng_http_set_method.3http.adoc} (52%) rename docs/man/{nng_http_res_set_reason.3http.adoc => nng_http_set_reason.3http.adoc} (59%) create mode 100644 docs/ref/api/http.md rename include/nng/{supplemental/http => }/http.h (62%) diff --git a/demo/http_client/http_client.c b/demo/http_client/http_client.c index a18725a91..8f7db96d1 100644 --- a/demo/http_client/http_client.c +++ b/demo/http_client/http_client.c @@ -1,5 +1,5 @@ // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2025 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -33,8 +33,8 @@ // % ./http_client http://httpbin.org/ip // +#include #include -#include #include #include @@ -49,11 +49,9 @@ int main(int argc, char **argv) { nng_http_client *client; - nng_http_conn *conn; + nng_http *conn; nng_url *url; nng_aio *aio; - nng_http_req *req; - nng_http_res *res; const char *hdr; int rv; int len; @@ -66,12 +64,12 @@ main(int argc, char **argv) } if (((rv = nng_init(NULL)) != 0) || + ((rv = nng_aio_alloc(&aio, NULL, NULL)) != 0) || ((rv = nng_url_parse(&url, argv[1])) != 0) || ((rv = nng_http_client_alloc(&client, url)) != 0) || - ((rv = nng_http_req_alloc(&req, url)) != 0) || - ((rv = nng_http_res_alloc(&res)) != 0) || ((rv = nng_aio_alloc(&aio, NULL, NULL)) != 0)) { fatal(rv); + return 1; } // Start connection process... @@ -90,7 +88,7 @@ main(int argc, char **argv) // The Host: header is already set up too. // Send the request, and wait for that to finish. - nng_http_conn_write_req(conn, req, aio); + nng_http_write_request(conn, aio); nng_aio_wait(aio); if ((rv = nng_aio_result(aio)) != 0) { @@ -98,22 +96,21 @@ main(int argc, char **argv) } // Read a response. - nng_http_conn_read_res(conn, res, aio); + nng_http_read_response(conn, aio); nng_aio_wait(aio); if ((rv = nng_aio_result(aio)) != 0) { fatal(rv); } - if (nng_http_res_get_status(res) != NNG_HTTP_STATUS_OK) { + if (nng_http_get_status(conn) != NNG_HTTP_STATUS_OK) { fprintf(stderr, "HTTP Server Responded: %d %s\n", - nng_http_res_get_status(res), - nng_http_res_get_reason(res)); + nng_http_get_status(conn), nng_http_get_reason(conn)); } // This only supports regular transfer encoding (no Chunked-Encoding, // and a Content-Length header is required.) - if ((hdr = nng_http_res_get_header(res, "Content-Length")) == NULL) { + if ((hdr = nng_http_get_header(conn, "Content-Length")) == NULL) { fprintf(stderr, "Missing Content-Length header.\n"); exit(1); } @@ -134,7 +131,7 @@ main(int argc, char **argv) nng_aio_set_iov(aio, 1, &iov); // Now attempt to receive the data. - nng_http_conn_read_all(conn, aio); + nng_http_read_all(conn, aio); // Wait for it to complete. nng_aio_wait(aio); diff --git a/demo/reqrep/reqrep.c b/demo/reqrep/reqrep.c index 9d7110f7b..38e9d2c0e 100644 --- a/demo/reqrep/reqrep.c +++ b/demo/reqrep/reqrep.c @@ -103,7 +103,6 @@ client(const char *url) nng_socket sock; nng_dialer dialer; int rv; - size_t sz; int sleep = 0; if ((rv = nng_init(NULL)) != 0) { diff --git a/demo/rest/server.c b/demo/rest/server.c index 96cdc79c2..0fe21acb2 100644 --- a/demo/rest/server.c +++ b/demo/rest/server.c @@ -32,11 +32,8 @@ // GRFG // +#include #include -#include -#include -#include -#include #include #include @@ -74,12 +71,12 @@ typedef enum { typedef struct rest_job { nng_aio *http_aio; // aio from HTTP we must reply to - nng_http_res *http_res; // HTTP response object job_state state; // 0 = sending, 1 = receiving nng_msg *msg; // request message nng_aio *aio; // request flow nng_ctx ctx; // context on the request socket - struct rest_job *next; // next on the freelist + nng_http *conn; + struct rest_job *next; // next on the freelist } rest_job; nng_socket req_sock; @@ -94,10 +91,6 @@ static void rest_job_cb(void *arg); static void rest_recycle_job(rest_job *job) { - if (job->http_res != NULL) { - nng_http_res_free(job->http_res); - job->http_res = NULL; - } if (job->msg != NULL) { nng_msg_free(job->msg); job->msg = NULL; @@ -136,20 +129,13 @@ rest_get_job(void) } static void -rest_http_fatal(rest_job *job, const char *fmt, int rv) +rest_http_fatal(rest_job *job, int rv) { - char buf[128]; - nng_aio *aio = job->http_aio; - nng_http_res *res = job->http_res; - - job->http_res = NULL; - job->http_aio = NULL; - snprintf(buf, sizeof(buf), fmt, nng_strerror(rv)); - nng_http_res_set_status(res, NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR); - nng_http_res_set_reason(res, buf); - - nng_aio_set_output(aio, 0, res); - nng_aio_finish(aio, 0); + nng_aio *aio = job->http_aio; + + // let the server give the details, we could have done more here + // ourselves if we wanted a detailed message + nng_aio_finish(aio, rv); rest_recycle_job(job); } @@ -163,7 +149,7 @@ rest_job_cb(void *arg) switch (job->state) { case SEND_REQ: if ((rv = nng_aio_result(aio)) != 0) { - rest_http_fatal(job, "send REQ failed: %s", rv); + rest_http_fatal(job, rv); return; } job->msg = NULL; @@ -174,23 +160,20 @@ rest_job_cb(void *arg) break; case RECV_REP: if ((rv = nng_aio_result(aio)) != 0) { - rest_http_fatal(job, "recv reply failed: %s", rv); + rest_http_fatal(job, rv); return; } job->msg = nng_aio_get_msg(aio); // We got a reply, so give it back to the server. - rv = nng_http_res_copy_data(job->http_res, - nng_msg_body(job->msg), nng_msg_len(job->msg)); + rv = nng_http_copy_body( + job->conn, nng_msg_body(job->msg), nng_msg_len(job->msg)); if (rv != 0) { - rest_http_fatal(job, "nng_http_res_copy_data: %s", rv); + rest_http_fatal(job, rv); return; } - // Set the output - the HTTP server will send it back to the - // user agent with a 200 response. - nng_aio_set_output(job->http_aio, 0, job->http_res); + nng_http_set_status(job->conn, NNG_HTTP_STATUS_OK, NULL); nng_aio_finish(job->http_aio, 0); job->http_aio = NULL; - job->http_res = NULL; // We are done with the job. rest_recycle_job(job); return; @@ -203,14 +186,10 @@ rest_job_cb(void *arg) // Our rest server just takes the message body, creates a request ID // for it, and sends it on. This runs in raw mode, so void -rest_handle(nng_aio *aio) +rest_handle(nng_http *conn, void *arg, nng_aio *aio) { struct rest_job *job; - nng_http_req *req = nng_aio_get_input(aio, 0); - nng_http_conn *conn = nng_aio_get_input(aio, 2); - const char *clen; size_t sz; - nng_iov iov; int rv; void *data; @@ -218,18 +197,18 @@ rest_handle(nng_aio *aio) nng_aio_finish(aio, NNG_ENOMEM); return; } - if (((rv = nng_http_res_alloc(&job->http_res)) != 0) || - ((rv = nng_ctx_open(&job->ctx, req_sock)) != 0)) { + job->conn = conn; + if (((rv = nng_ctx_open(&job->ctx, req_sock)) != 0)) { rest_recycle_job(job); nng_aio_finish(aio, rv); return; } - nng_http_req_get_data(req, &data, &sz); + nng_http_get_body(conn, &data, &sz); job->http_aio = aio; if ((rv = nng_msg_alloc(&job->msg, sz)) != 0) { - rest_http_fatal(job, "nng_msg_alloc: %s", rv); + rest_http_fatal(job, rv); return; } @@ -329,7 +308,7 @@ inproc_server(void *arg) fatal("inproc recvmsg", rv); } body = nng_msg_body(msg); - for (int i = 0; i < nng_msg_len(msg); i++) { + for (size_t i = 0; i < nng_msg_len(msg); i++) { // Table lookup would be faster, but this works. if (isupper(body[i])) { char base = body[i] - 'A'; diff --git a/docs/man/libnng.3.adoc b/docs/man/libnng.3.adoc index f63669426..5bc947b1f 100644 --- a/docs/man/libnng.3.adoc +++ b/docs/man/libnng.3.adoc @@ -99,48 +99,16 @@ The following functions are used to work with HTTP requests, responses, and connections. |=== -|xref:nng_http_conn_close.3http.adoc[nng_http_conn_close()]|close HTTP connection -|xref:nng_http_conn_read.3http.adoc[nng_http_conn_read()]|read from HTTP connection -|xref:nng_http_conn_read_all.3http.adoc[nng_http_conn_read_all()]|read all from HTTP connection |xref:nng_http_conn_read_req.3http.adoc[nng_http_conn_read_req()]|read HTTP request |xref:nng_http_conn_read_res.3http.adoc[nng_http_conn_read_res()]|read HTTP response -|xref:nng_http_conn_write.3http.adoc[nng_http_conn_write()]|write to HTTP connection -|xref:nng_http_conn_write_all.3http.adoc[nng_http_conn_write_all()]|write all to HTTP connection |xref:nng_http_conn_write_req.3http.adoc[nng_http_conn_write_req()]|write HTTP request |xref:nng_http_conn_write_res.3http.adoc[nng_http_conn_write_res()]|write HTTP response -|xref:nng_http_req_add_header.3http.adoc[nng_http_req_add_header()]|add HTTP request header -|xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc()]|allocate HTTP request structure -|xref:nng_http_req_copy_data.3http.adoc[nng_http_req_copy_data()]|copy HTTP request body -|xref:nng_http_req_del_header.3http.adoc[nng_http_req_del_header()]|delete HTTP request header -|xref:nng_http_req_free.3http.adoc[nng_http_req_free()]|free HTTP request structure |xref:nng_http_req_get_data.3http.adoc[nng_http_req_get_data()]|get HTTP request body -|xref:nng_http_req_get_header.3http.adoc[nng_http_req_get_header()]|return HTTP request header -|xref:nng_http_req_get_method.3http.adoc[nng_http_req_get_method()]|return HTTP request method -|xref:nng_http_req_get_uri.3http.adoc[nng_http_req_get_uri()]|return HTTP request URI -|xref:nng_http_req_get_version.3http.adoc[nng_http_req_get_version()]|return HTTP request protocol version -|xref:nng_http_req_reset.3http.adoc[nng_http_req_reset()]|reset HTTP request structure |xref:nng_http_req_set_data.3http.adoc[nng_http_req_set_data()]|set HTTP request body -|xref:nng_http_req_set_header.3http.adoc[nng_http_req_set_header()]|set HTTP request header -|xref:nng_http_req_set_method.3http.adoc[nng_http_req_set_method()]|set HTTP request method -|xref:nng_http_req_set_uri.3http.adoc[nng_http_req_set_uri()]|set HTTP request URI -|xref:nng_http_req_set_version.3http.adoc[nng_http_req_set_version()]|set HTTP request protocol version -|xref:nng_http_res_add_header.3http.adoc[nng_http_res_add_header()]|add HTTP response header -|xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc()]|allocate HTTP response structure -|xref:nng_http_res_alloc_error.3http.adoc[nng_http_res_alloc_error()]|allocate HTTP error response |xref:nng_http_res_copy_data.3http.adoc[nng_http_res_copy_data()]|copy HTTP response body -|xref:nng_http_res_del_header.3http.adoc[nng_http_res_del_header()]|delete HTTP response header -|xref:nng_http_res_free.3http.adoc[nng_http_res_free()]|free HTTP response structure |xref:nng_http_res_get_data.3http.adoc[nng_http_res_get_data()]|get HTTP response body |xref:nng_http_res_get_header.3http.adoc[nng_http_res_get_header()]|return HTTP response header -|xref:nng_http_res_get_reason.3http.adoc[nng_http_res_get_reason()]|return HTTP response reason -|xref:nng_http_res_get_status.3http.adoc[nng_http_res_get_status()]|return HTTP response status -|xref:nng_http_res_get_version.3http.adoc[nng_http_res_get_version()]|return HTTP response protocol version -|xref:nng_http_res_reset.3http.adoc[nng_http_res_reset()]|reset HTTP response structure |xref:nng_http_res_set_data.3http.adoc[nng_http_res_set_data()]|set HTTP response body -|xref:nng_http_res_set_header.3http.adoc[nng_http_res_set_header()]|set HTTP response header -|xref:nng_http_res_set_reason.3http.adoc[nng_http_res_set_reason()]|set HTTP response reason -|xref:nng_http_res_set_status.3http.adoc[nng_http_res_set_status()]|set HTTP response status -|xref:nng_http_res_set_version.3http.adoc[nng_http_res_set_version()]|set HTTP response protocol version |=== ==== HTTP Client Functions @@ -148,12 +116,6 @@ and connections. These functions are intended for use with HTTP client applications. |=== -|xref:nng_http_client_alloc.3http.adoc[nng_http_client_alloc()]|allocate HTTP client -|xref:nng_http_client_connect.3http.adoc[nng_http_client_connect()]|establish HTTP client connection -|xref:nng_http_client_free.3http.adoc[nng_http_client_free()]|free HTTP client -|xref:nng_http_client_get_tls.3http.adoc[nng_http_client_get_tls()]|get HTTP client TLS configuration -|xref:nng_http_client_set_tls.3http.adoc[nng_http_client_set_tls()]|set HTTP client TLS configuration -|xref:nng_http_client_transact.3http.adoc[nng_http_client_transact()]|perform one HTTP transaction |xref:nng_http_conn_transact.3http.adoc[nng_http_conn_transact()]|perform one HTTP transaction on connection |=== @@ -170,7 +132,6 @@ These functions are intended for use with HTTP server applications. |xref:nng_http_handler_set_host.3http.adoc[nng_http_handler_set_host()]|set host for HTTP handler |xref:nng_http_handler_set_method.3http.adoc[nng_http_handler_set_method()]|set HTTP handler method |xref:nng_http_handler_set_tree.3http.adoc[nng_http_handler_set_tree()]|set HTTP handler to match trees -|xref:nng_http_hijack.3http.adoc[nng_http_hijack()]|hijack HTTP server connection |xref:nng_http_server_add_handler.3http.adoc[nng_http_server_add_handler()]|add HTTP server handler |xref:nng_http_server_del_handler.3http.adoc[nng_http_server_del_handler()]|delete HTTP server handler |xref:nng_http_server_get_addr.3http.adoc[nng_http_server_get_addr()]|get HTTP server address diff --git a/docs/man/nng.7.adoc b/docs/man/nng.7.adoc index 2c5d0d724..e1680e1a5 100644 --- a/docs/man/nng.7.adoc +++ b/docs/man/nng.7.adoc @@ -73,7 +73,6 @@ xref:nng_socket.7.adoc[nng_socket(7)]:: BSD socket transport xref:nng_tls.7.adoc[nng_tls(7)]:: TLSv1.2 over TCP transport xref:nng_tcp.7.adoc[nng_tcp(7)]:: TCP (and TCPv6) transport xref:nng_ws.7.adoc[nng_ws(7)]:: WebSocket transport -xref:nng_zerotier.7.adoc[nng_zerotier(7)]:: ZeroTier transport === Conceptual Overview diff --git a/docs/man/nng_http_client_alloc.3http.adoc b/docs/man/nng_http_client_alloc.3http.adoc deleted file mode 100644 index f433001a7..000000000 --- a/docs/man/nng_http_client_alloc.3http.adoc +++ /dev/null @@ -1,49 +0,0 @@ -= nng_http_client_alloc(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_client_alloc - allocate HTTP client - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_client_alloc(nng_http_client *clientp, const nng_url *url); ----- - -== DESCRIPTION - -The `nng_http_client_alloc()` allocates an HTTP client suitable for -connecting to the server identified by _url_ and stores a pointer to -it in the location referenced by _clientp_. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient free memory exists. -`NNG_ENOTSUP`:: HTTP not supported. - -== SEE ALSO - -[.text-left] -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_client_free.3http.adoc[nng_http_client_free(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng_url_parse.3.adoc[nng_url_parse(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_client_connect.3http.adoc b/docs/man/nng_http_client_connect.3http.adoc deleted file mode 100644 index e2a3e23c3..000000000 --- a/docs/man/nng_http_client_connect.3http.adoc +++ /dev/null @@ -1,98 +0,0 @@ -= nng_http_client_connect(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_client_connect - establish HTTP client connection - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_client_connect(nng_http_client *client, nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_client_connect()` starts the process of establishing an HTTP -connection from _client_ to the server that was indicated in the URL that -_client_ was configured with. - -The result of the operation will be stored in the _aio_ when the operation -is complete, and will be obtainable via -xref:nng_aio_result.3.adoc[`nng_aio_result()`]. - -On success, a pointer to the underlying HTTP client (type `nng_http_conn *`) -will be stored in the first output result of the _aio_, and can be -obtained by -xref:nng_aio_get_output.3.adoc[`nng_aio_get_output()`] with an _index_ of zero (0). - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_EADDRINVAL`:: The client is configured with an invalid address. -`NNG_ECANCELED`:: The operation was aborted. -`NNG_ECONNREFUSED`:: The TCP connection was refused by the server. -`NNG_ECONNRESET`:: The TCP connection was reset by the server. -`NNG_ENOMEM`:: Insufficient free memory exists. - -== EXAMPLE - -[source, c] ----- - nng_aio *aio; - nng_url *url; - nng_http_client *client; - nng_http_conn *conn; - int rv; - - // Error checks elided for clarity. - nng_url_parse(&url, "http://www.google.com"); - nng_aio_alloc(&aio, NULL, NULL); - nng_http_client_alloc(&client, url); - - nng_http_client_connect(client, aio); - - // Wait for connection to establish (or attempt to fail). - nng_aio_wait(aio); - - if ((rv = nng_aio_result(aio)) != 0) { - printf("Connection failed: %s\n", nng_strerror(rv)); - } else { - // Connection established, get it. - conn = nng_aio_get_output(aio, 0); - - // ... do something with it here - - // Close the connection when done to avoid leaking it. - nng_http_conn_close(conn); - } ----- - -== SEE ALSO - -[.text-left] -xref:nng_aio_get_output.3.adoc[nng_aio_get_output(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_aio_wait.3.adoc[nng_aio_wait(3)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng_http_client_alloc.3http.adoc[nng_http_client_alloc(3http)], -xref:nng_http_conn_close.3http.adoc[nng_http_conn_close(3http)], -xref:nng_http_conn_read.3http.adoc[nng_http_conn_read(3http)], -xref:nng_http_conn_write.3http.adoc[nng_http_conn_write(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_client_free.3http.adoc b/docs/man/nng_http_client_free.3http.adoc deleted file mode 100644 index 2343672ce..000000000 --- a/docs/man/nng_http_client_free.3http.adoc +++ /dev/null @@ -1,48 +0,0 @@ -= nng_http_client_free(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_client_free - free HTTP client - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_client_free(nng_http_client *client); ----- - -== DESCRIPTION - -The `nng_http_client_free()` frees the HTTP client and any associated -resources referenced by _client_. - -NOTE: Any connections created by -xref:nng_http_client_connect.3http.adoc[`nng_http_client_connect()`] are unaffected, -and so the caller must close those explicitly if desired. - -== RETURN VALUES - -None. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_client_alloc.3http.adoc[nng_http_client_alloc(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_client_get_tls.3http.adoc b/docs/man/nng_http_client_get_tls.3http.adoc deleted file mode 100644 index 89f030297..000000000 --- a/docs/man/nng_http_client_get_tls.3http.adoc +++ /dev/null @@ -1,59 +0,0 @@ -= nng_http_client_get_tls(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_client_get_tls - get HTTP client TLS configuration - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_client_get_tls(nng_http_client *client, nng_tls_config **cfgp); ----- - -== DESCRIPTION - -The `nng_http_client_get_tls()` obtains the TLS configuration of _client_ and -saves a pointer to it in the address referenced by _cfgp_. - -The object will be returned with an extra hold (see -xref:nng_tls_config_hold.3tls.adoc[`nng_tls_config_hold()`]) -placed on it on behalf of the caller. -The caller should free this hold by calling -xref:nng_tls_config_free.3tls.adoc[`nng_tls_config_free()`] with it is done -with the TLS configuration. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_EINVAL`:: TLS not configured on client. -`NNG_ENOMEM`:: Insufficient free memory exists. -`NNG_ENOTSUP`:: Either HTTP or TLS not supported. - -== SEE ALSO - -[.text-left] -xref:nng_http_client_alloc.3http.adoc[nng_http_client_alloc(3http)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_client_set_tls.3http.adoc[nng_http_client_set_tls(3http)], -xref:nng_tls_config_alloc.3tls.adoc[nng_tls_config_alloc(3tls)], -xref:nng_tls_config_free.3tls.adoc[nng_tls_config_free(3tls)], -xref:nng_tls_config_hold.3tls.adoc[nng_tls_config_hold(3tls)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_client_set_tls.3http.adoc b/docs/man/nng_http_client_set_tls.3http.adoc deleted file mode 100644 index 023b8a4ec..000000000 --- a/docs/man/nng_http_client_set_tls.3http.adoc +++ /dev/null @@ -1,57 +0,0 @@ -= nng_http_client_set_tls(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_client_set_tls - set HTTP client TLS configuration - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_client_set_tls(nng_http_client *client, nng_tls_config *cfg); ----- - -== DESCRIPTION - -The `nng_http_client_set_tls()` sets the TLS configuration of _client_ to _cfg_. - -This change overwrites any previous TLS configuration. - -IMPORTANT: This also invalidates any previously obtained values from -xref:nng_http_client_get_tls.3http.adoc[`nng_http_client_get_tls()`]. - -NOTE: Any connections established with -xref:nng_http_client_connect.3http.adoc[`nng_http_client_connect()`] -will continue to use any TLS configuration that they were started with. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient free memory exists. -`NNG_ENOTSUP`:: Either HTTP or TLS not supported. - -== SEE ALSO - -[.text-left] -xref:nng_http_client_alloc.3http.adoc[nng_http_client_alloc(3http)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_client_get_tls.3http.adoc[nng_http_client_get_tls(3http)], -xref:nng_tls_config_alloc.3tls.adoc[nng_tls_config_alloc(3tls)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_client_transact.3http.adoc b/docs/man/nng_http_client_transact.3http.adoc deleted file mode 100644 index 0585fa7eb..000000000 --- a/docs/man/nng_http_client_transact.3http.adoc +++ /dev/null @@ -1,84 +0,0 @@ -= nng_http_client_transact(3http) -// -// Copyright 2020 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_client_transact - perform one HTTP transaction - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_client_transact(nng_http_client *client, nng_http_req *req, - nng_http_res *res, nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_client_transact()` function is used to perform a complete -HTTP exchange. -It creates a new connection using _client_, performs the transaction by -sending the request _req_ -(and attached body data) to the remote server, then reading the response -_res_, and finally closes the connection that it created. -The entire response is read, including any associated body, which can -subsequently be obtained using -xref:nng_http_res_get_data.3http.adoc[`nng_http_res_get_data()`]. - -This function is intended to make creation of client applications easier, -by performing multiple asynchronous operations required to complete an -entire HTTP transaction. - -A similar function, -xref:nng_http_conn_transact.3http.adoc[`nng_http_conn_transact()`], -exists. -That function behaves similarily, but uses an existing connection, which -can be reused. - -WARNING: If the remote server tries to send an extremely large buffer, -then a corresponding allocation will be made, which can lead to denial -of service attacks. -Client applications should take care to use this only with reasonably -trust-worthy servers. - -This function returns immediately, with no return value. -Completion of the operation is signaled via the _aio_, and the final result -may be obtained via xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported, or peer sent chunked encoding. -`NNG_EPROTO`:: An HTTP protocol error occurred. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_conn_transact.3http.adoc[nng_http_conn_transact(3http)], -xref:nng_http_res_get_data.3http.adoc[nng_http_res_get_data(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_close.3http.adoc b/docs/man/nng_http_conn_close.3http.adoc deleted file mode 100644 index 95c266e29..000000000 --- a/docs/man/nng_http_conn_close.3http.adoc +++ /dev/null @@ -1,47 +0,0 @@ -= nng_http_conn_close(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_close - close HTTP connection - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_close(nng_http_conn *conn); ----- - -== DESCRIPTION - -The `nng_http_conn_close()` function closes the supplied HTTP connection _conn_, -including any disposing of any underlying file descriptors or related resources. - -Once this function, no further access to the _conn_ structure may be made. - -== RETURN VALUES - -None. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_handler_alloc.3http.adoc[nng_http_handler_alloc(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_read.3http.adoc b/docs/man/nng_http_conn_read.3http.adoc deleted file mode 100644 index dfb6e08ca..000000000 --- a/docs/man/nng_http_conn_read.3http.adoc +++ /dev/null @@ -1,77 +0,0 @@ -= nng_http_conn_read(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_read - read from HTTP connection - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_read(nng_http_conn *conn, nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_conn_read()` function starts an asynchronous read from the -HTTP connection _conn_, into the scatter/gather vector located in the -asynchronous I/O structure _aio_. - -NOTE: The xref:nng_aio_set_iov.3.adoc[`nng_aio_set_iov()`] function must have been -called first, to set the scatter/gather vector for _aio_. - -This function returns immediately, with no return value. -Completion of the operation is signaled via the _aio_, -and the final result may be obtained via -xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -The I/O operation completes as soon as at least one byte has been -read, or an error has occurred. -Therefore, the number of bytes read may be less than requested. -The actual number of bytes read can be determined with -xref:nng_aio_count.3.adoc[`nng_aio_count()`]. - -TIP: This function is intended to facilitate uses cases that involve changing -the protocol from HTTP, such as WebSocket. -Most applications will never need to use this function. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_EINVAL`:: The _aio_ does not contain a valid scatter/gather vector. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_count.3.adoc[nng_aio_count(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_aio_set_iov.3.adoc[nng_aio_set_iov(3)], -xref:nng_http_handler_alloc.3http.adoc[nng_http_handler_alloc(3http)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_conn_read_all.3http.adoc[nng_http_conn_read_all(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_read_all.3http.adoc b/docs/man/nng_http_conn_read_all.3http.adoc deleted file mode 100644 index 21b892f05..000000000 --- a/docs/man/nng_http_conn_read_all.3http.adoc +++ /dev/null @@ -1,78 +0,0 @@ -= nng_http_conn_read_all(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_read_all - read all from HTTP connection - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_read_all(nng_http_conn *conn, nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_conn_read_all()` function starts an asynchronous read from the -HTTP connection _conn_, into the scatter/gather vector located in the -asynchronous I/O structure _aio_. - -NOTE: The xref:nng_aio_set_iov.3.adoc[`nng_aio_set_iov()`] function must have been -called first, to set the scatter/gather vector for _aio_. - -This function returns immediately, with no return value. -Completion of the operation is signaled via the _aio_, and the final result -may be obtained via xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -The I/O operation completes only when the entire amount of data -requested has been read, or an error has occurred. -If the operation -completes successfully, then the entire requested data has been read. - -It is still possible for a partial read to complete in the event of an error. -The actual number of bytes read can be determined with -xref:nng_aio_count.3.adoc[`nng_aio_count()`]. - -TIP: The main purpose for this function is to facilitate reading HTTP -body content, after first determining the length of the body content -from the relevant HTTP headers (typically `Content-Length`). - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_EINVAL`:: The _aio_ does not contain a valid scatter/gather vector. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_count.3.adoc[nng_aio_count(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_aio_set_iov.3.adoc[nng_aio_set_iov(3)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3)], -xref:nng_http_conn_read.3http.adoc[nng_http_conn_read(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_read_req.3http.adoc b/docs/man/nng_http_conn_read_req.3http.adoc deleted file mode 100644 index 4a8d3e05a..000000000 --- a/docs/man/nng_http_conn_read_req.3http.adoc +++ /dev/null @@ -1,66 +0,0 @@ -= nng_http_conn_read_req(3http) -// -// Copyright 2025 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_read_req - read HTTP request - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_read_req(nng_http_conn *conn, nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_conn_read_req()` function starts an asynchronous read from the -HTTP connection _conn_, reading an HTTP request into the request object -associated with _conn_, including all of the related headers. -(The request object can be obtained via `nng_http_conn_req()`. - -NOTE: Any HTTP entity/body data associated with the request is *not* read -automatically. -The caller should use -xref:nng_http_conn_read_all.3http.adoc[`nng_http_conn_read_all()`] -to read the entity data, based on the details of the request itself. - -This function returns immediately, with no return value. -Completion of the operation is signaled via the _aio_, and the final result -may be obtained via xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_conn_read_all.3http.adoc[nng_http_conn_read_all(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_read_res.3http.adoc b/docs/man/nng_http_conn_read_res.3http.adoc deleted file mode 100644 index ff5cd7a33..000000000 --- a/docs/man/nng_http_conn_read_res.3http.adoc +++ /dev/null @@ -1,75 +0,0 @@ -= nng_http_conn_read_res(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_read_res - read HTTP response - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_read_res(nng_http_conn *conn, nng_http_res *res, - nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_conn_read_res()` function starts an asynchronous read from the -HTTP connection _conn_, reading an HTTP response into the _res_, including all -of the related headers. - -NOTE: Any HTTP entity/body data associated with the response is *not* read -automatically. -The caller should use -xref:nng_http_conn_read_all.3http.adoc[`nng_http_conn_read_all`] to read the entity -data, based on the details of the response itself. - -This function returns immediately, with no return value. -Completion of -the operation is signaled via the _aio_, and the final result may be -obtained via xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -NOTE: Consider using the -xref:nng_http_client_transact.3http.adoc[`nng_http_client_transact()`] or -xref:nng_http_conn_transact.3http.adoc[`nng_http_conn_transact()`] functions, -which provide a simpler interface for performing a complete HTTP client -transaction. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_client_transact.3http.adoc[nng_http_client_transact(3http)], -xref:nng_http_conn_transact.3http.adoc[nng_http_conn_transact(3http)], -xref:nng_http_conn_read_all.3http.adoc[nng_http_conn_read_all(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_transact.3http.adoc b/docs/man/nng_http_conn_transact.3http.adoc deleted file mode 100644 index 7239f6287..000000000 --- a/docs/man/nng_http_conn_transact.3http.adoc +++ /dev/null @@ -1,93 +0,0 @@ -= nng_http_conn_transact(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_transact - perform one HTTP transaction on connection - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_transact(nng_http_conn *conn, nng_http_req *req, - nng_http_res *res, nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_conn_transact()` function is used to perform a complete -HTTP exchange over the connection _conn_, sending the request _req_ -(and attached body data) to the remote server, and reading the response -_res_. -The entire response is read, including any associated body, which can -subsequently be obtained using -xref:nng_http_res_get_data.3http.adoc[`nng_http_res_get_data()`]. - -This function is intended to make creation of client applications easier, -by performing multiple asynchronous operations required to complete an -entire HTTP transaction. - -If an error occurs, the caller should close _conn_ with -xref:nng_http_conn_close.3http.adoc[`nng_http_conn_close()`], as it may not -necessarily be usable with other transactions. - -A similar function, -xref:nng_http_client_transact.3http.adoc[`nng_http_client_transact()`], -exists. -That function behaves similarily, but creates a connection on demand -for the transaction, and disposes of it when finished. - -WARNING: If the remote server tries to send an extremely large buffer, -then a corresponding allocation will be made, which can lead to denial -of service attacks. -Client applications should take care to use this only with reasonably -trust-worthy servers. - -WARNING: A given connection _conn_ should be used with only one -operation or transaction at a time as HTTP/1.1 has no support for -request interleaving. - -This function returns immediately, with no return value. -Completion of the operation is signaled via the _aio_, and the final result -may be obtained via xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported. -`NNG_EPROTO`:: An HTTP protocol error occurred. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_client_transact.3http.adoc[nng_http_client_transact(3http)], -xref:nng_http_conn_read_res.3http.adoc[nng_http_conn_read_res(3http)], -xref:nng_http_conn_read_all.3http.adoc[nng_http_conn_read_all(3http)], -xref:nng_http_conn_write_req.3http.adoc[nng_http_conn_write_req(3http)], -xref:nng_http_res_get_data.3http.adoc[nng_http_res_get_data(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_write.3http.adoc b/docs/man/nng_http_conn_write.3http.adoc deleted file mode 100644 index d2e1ac314..000000000 --- a/docs/man/nng_http_conn_write.3http.adoc +++ /dev/null @@ -1,76 +0,0 @@ -= nng_http_conn_write(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_write - write to HTTP connection - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_write(nng_http_conn *conn, nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_conn_write()` function starts an asynchronous write to the -HTTP connection _conn_ from the scatter/gather vector located in the -asynchronous I/O structure _aio_. - -NOTE: The xref:nng_aio_set_iov.3.adoc[`nng_aio_set_iov()`] function must have been -called first, to set the scatter/gather vector for _aio_. - -This function returns immediately, with no return value. -Completion of the operation is signaled via the _aio_, and the final -result may be obtained via xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -The I/O operation completes as soon as at least one byte has been -written, or an error has occurred. -Therefore, the number of bytes written may be less than requested. -The actual number of bytes written can be determined with -xref:nng_aio_count.3.adoc[`nng_aio_count()`]. - -TIP: This function is intended to facilitate uses cases that involve changing -the protocol from HTTP, such as WebSocket. -Most applications will never need to use this function. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_EINVAL`:: The _aio_ does not contain a valid scatter/gather vector. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_count.3.adoc[nng_aio_count(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_aio_set_iov.3.adoc[nng_aio_set_iov(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_conn_write_all.3http.adoc[nng_http_conn_write_all(3http)], -xref:nng_http_handler_alloc.3http.adoc[nng_http_handler_alloc(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_write_all.3http.adoc b/docs/man/nng_http_conn_write_all.3http.adoc deleted file mode 100644 index 329a83029..000000000 --- a/docs/man/nng_http_conn_write_all.3http.adoc +++ /dev/null @@ -1,96 +0,0 @@ -= nng_http_conn_write_all(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_write_all - write all to HTTP connection - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_write_all(nng_http_conn *conn, nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_conn_write_all()` function starts an asynchronous write to the -HTTP connection _conn_, into the scatter/gather vector located in the -asynchronous I/O structure _aio_. - -NOTE: The xref:nng_aio_set_iov.3.adoc[`nng_aio_set_iov()`] function must have been -called first, to set the scatter/gather vector for _aio_. - -This function returns immediately, with no return value. -Completion of the operation is signaled via the _aio_, and the -final result may be obtained via xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -The I/O operation completes only when the entire amount of data -requested has been written, or an error has occurred. -If the operation completes successfully, then the entire requested data has -been written. - -It is still possible for a partial write to complete in the event of an error. -The actual number of bytes written can be determined with -xref:nng_aio_count.3.adoc[`nng_aio_count()`]. - -TIP: The main purpose for this function is to facilitate writing HTTP -body content. - -TIP: Usually an HTTP request or response will have been written immediately -prior to this with xref:nng_http_conn_write_req.3http.adoc[`http_conn_write_req()`] or -xref:nng_http_conn_write_res.3http.adoc[`http_conn_write_res()`]. -In that case the request or response should have also contained -an `Content-Length` header, and possibly a `Content-Type` header. - -TIP: An easier solution to sending HTTP content data, is to include the -content with the request or reply using a function like -xref:nng_http_req_copy_data.3http.adoc[`nng_http_req_copy_data()`]. -In that case, the body data will be written automatically by the -xref:nng_http_conn_write_req.3http.adoc[`http_conn_write_req()`] or -xref:nng_http_conn_write_req.3http.adoc[`http_conn_write_res()`] function. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_EINVAL`:: The _aio_ does not contain a valid scatter/gather vector. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_count.3.adoc[nng_aio_count(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_aio_set_iov.3.adoc[nng_aio_set_iov(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_conn_write.3http.adoc[nng_http_conn_write(3http)], -xref:nng_http_conn_write_req.3http.adoc[http_conn_write_req(3http)], -xref:nng_http_conn_write_res.3http.adoc[http_conn_write_res(3http)], -xref:nng_http_req_copy_data.3http.adoc[nng_http_req_copy_data(3http)], -xref:nng_http_req_set_data.3http.adoc[nng_http_req_set_data(3http)], -xref:nng_http_res_copy_data.3http.adoc[nng_http_res_copy_data(3http)], -xref:nng_http_res_set_data.3http.adoc[nng_http_res_set_data(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_write_req.3http.adoc b/docs/man/nng_http_conn_write_req.3http.adoc deleted file mode 100644 index faed76040..000000000 --- a/docs/man/nng_http_conn_write_req.3http.adoc +++ /dev/null @@ -1,72 +0,0 @@ -= nng_http_conn_write_req(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_write_req - write HTTP request - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_write_req(nng_http_conn *conn, nng_http_req *req, - nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_conn_write_req()` function starts an asynchronous write of -the HTTP request _req_ to the connection _conn_. -The entire request is sent, -including headers, and if present, the request body data. -(The request body can be set with -xref:nng_http_req_set_data.3http.adoc[`nng_http_req_set_data()`] or -xref:nng_http_req_copy_data.3http.adoc[`nng_http_req_copy_data()`].) - -This function returns immediately, with no return value. -Completion of the operation is signaled via the _aio_, and the final result -may be obtained via xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -NOTE: Consider using the -xref:nng_http_client_transact.3http.adoc[`nng_http_client_transact()`] or -xref:nng_http_conn_transact.3http.adoc[`nng_http_conn_transact()`] functions, -which provide a simpler interface for performing a complete HTTP client -transaction. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_client_transact.3http.adoc[nng_http_client_transact(3http)], -xref:nng_http_conn_read_all.3http.adoc[nng_http_conn_read_all(3http)], -xref:nng_http_conn_transact.3http.adoc[nng_http_conn_transact(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_conn_write_res.3http.adoc b/docs/man/nng_http_conn_write_res.3http.adoc deleted file mode 100644 index e88ad1646..000000000 --- a/docs/man/nng_http_conn_write_res.3http.adoc +++ /dev/null @@ -1,80 +0,0 @@ -= nng_http_conn_write_res(3http) -// -// Copyright 2025 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_conn_write_res - write HTTP response - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_conn_write_res(nng_http_conn *conn, nng_aio *aio); ----- - -== DESCRIPTION - -The `nng_http_conn_write_res()` function starts an asynchronous write of -the HTTP response associated with the connection _conn_. -The entire response is sent, -including headers, and if present, the response body data. -(The response body can be set with -xref:nng_http_res_set_data.3http.adoc[`nng_http_res_set_data()`] or -xref:nng_http_res_copy_data.3http.adoc[`nng_http_res_copy_data()`].) - -This function returns immediately, with no return value. -Completion of the operation is signaled via the _aio_, and the final result -may be obtained via xref:nng_aio_result.3.adoc[`nng_aio_result()`]. -That result will either be zero or an error code. - -=== Persistent Connections - -By default, for `HTTP/1.1` connections, the connection is kept open, and -will be reused to receive new requests. - -If however the _res_ contains a header of `Connection:` with a value -of `Close` (case-insensitive) or the response corresponds to `HTTP/1.0`, -then the connection is immediately after sending the response. - -NOTE: Consider using the -xref:nng_http_client_transact.3http.adoc[`nng_http_client_transact()`] or -xref:nng_http_conn_transact.3http.adoc[`nng_http_conn_transact()`] functions, -which provide a simpler interface for performing a complete HTTP client -transaction. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECANCELED`:: The operation was canceled. -`NNG_ECLOSED`:: The connection was closed. -`NNG_ECONNRESET`:: The peer closed the connection. -`NNG_ENOMEM`:: Insufficient free memory to perform the operation. -`NNG_ENOTSUP`:: HTTP operations are not supported. -`NNG_ETIMEDOUT`:: Timeout waiting for data from the connection. - -== SEE ALSO - -[.text-left] -xref:nng_aio_alloc.3.adoc[nng_aio_alloc(3)], -xref:nng_aio_result.3.adoc[nng_aio_result(3)], -xref:nng_http_client_connect.3http.adoc[nng_http_client_connect(3http)], -xref:nng_http_client_transact.3http.adoc[nng_http_client_transact(3http)], -xref:nng_http_conn_read_all.3http.adoc[nng_http_conn_read_all(3http)], -xref:nng_http_conn_transact.3http.adoc[nng_http_conn_transact(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_handler_alloc.3http.adoc b/docs/man/nng_http_handler_alloc.3http.adoc index 231714500..8d55c7522 100644 --- a/docs/man/nng_http_handler_alloc.3http.adoc +++ b/docs/man/nng_http_handler_alloc.3http.adoc @@ -19,7 +19,7 @@ nng_http_handler_alloc - allocate HTTP server handler [source, c] ---- #include -#include +#include typedef struct nng_http_handler nng_http_handler; @@ -184,8 +184,6 @@ xref:nng_http_handler_set_host.3http.adoc[nng_http_handler_set_host(3http)], xref:nng_http_handler_set_method.3http.adoc[nng_http_handler_set_method(3http)], xref:nng_http_handler_set_tree.3http.adoc[nng_http_handler_set_tree(3http)], xref:nng_http_handler_set_tree.3http.adoc[nng_http_handler_set_tree_exclusive(3http)], -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_alloc_error.3http.adoc[nng_http_res_alloc_error(3http)], xref:nng_http_server_add_handler.3http.adoc[nng_http_server_add_handler(3http)], xref:nng_strerror.3.adoc[nng_strerror(3)], xref:nng_aio.5.adoc[nng_aio(5)], diff --git a/docs/man/nng_http_handler_collect_body.3http.adoc b/docs/man/nng_http_handler_collect_body.3http.adoc index d02919cd4..5012680d4 100644 --- a/docs/man/nng_http_handler_collect_body.3http.adoc +++ b/docs/man/nng_http_handler_collect_body.3http.adoc @@ -18,7 +18,7 @@ nng_http_handler_collect_body - set HTTP handler to collect request body [source, c] ---- #include -#include +#include void nng_http_handler_collect_body(nng_http_handler *handler, bool want, size_t maxsz); ---- diff --git a/docs/man/nng_http_handler_free.3http.adoc b/docs/man/nng_http_handler_free.3http.adoc index c7b30e0e5..0e1a5b1c1 100644 --- a/docs/man/nng_http_handler_free.3http.adoc +++ b/docs/man/nng_http_handler_free.3http.adoc @@ -18,7 +18,7 @@ nng_http_handler_free - free HTTP server handler [source, c] ---- #include -#include +#include void nng_http_handler_free(nng_http_handler *h); ---- diff --git a/docs/man/nng_http_handler_get_data.3http.adoc b/docs/man/nng_http_handler_get_data.3http.adoc index 0467b2b68..0f2396f68 100644 --- a/docs/man/nng_http_handler_get_data.3http.adoc +++ b/docs/man/nng_http_handler_get_data.3http.adoc @@ -18,7 +18,7 @@ nng_http_handler_get_data - return extra data for HTTP handler [source, c] ---- #include -#include +#include void *nng_http_handler_get_data(nng_http_handler *handler); ---- diff --git a/docs/man/nng_http_handler_set_data.3http.adoc b/docs/man/nng_http_handler_set_data.3http.adoc index 94cb9b4c2..e83ecb6b5 100644 --- a/docs/man/nng_http_handler_set_data.3http.adoc +++ b/docs/man/nng_http_handler_set_data.3http.adoc @@ -18,7 +18,7 @@ nng_http_handler_set_data - set extra data for HTTP handler [source, c] ---- #include -#include +#include void nng_http_handler_set_data(nng_http_handler *handler, void *data, void (*dtor)(void *)); diff --git a/docs/man/nng_http_handler_set_host.3http.adoc b/docs/man/nng_http_handler_set_host.3http.adoc index 3f25172ff..e3d5e80af 100644 --- a/docs/man/nng_http_handler_set_host.3http.adoc +++ b/docs/man/nng_http_handler_set_host.3http.adoc @@ -18,7 +18,7 @@ nng_http_handler_set_host - set host for HTTP handler [source, c] ---- #include -#include +#include void nng_http_handler_set_host(nng_http_handler *handler, const char *host); ---- diff --git a/docs/man/nng_http_handler_set_method.3http.adoc b/docs/man/nng_http_handler_set_method.3http.adoc index 17c4481df..e216ab54a 100644 --- a/docs/man/nng_http_handler_set_method.3http.adoc +++ b/docs/man/nng_http_handler_set_method.3http.adoc @@ -18,7 +18,7 @@ nng_http_handler_set_method - set HTTP handler method [source, c] ---- #include -#include +#include void nng_http_handler_set_method(nng_http_handler *handler, const char *method); ---- diff --git a/docs/man/nng_http_handler_set_tree.3http.adoc b/docs/man/nng_http_handler_set_tree.3http.adoc index 3ee73de0e..821a5f7bf 100644 --- a/docs/man/nng_http_handler_set_tree.3http.adoc +++ b/docs/man/nng_http_handler_set_tree.3http.adoc @@ -18,7 +18,7 @@ nng_http_handler_set_tree - set HTTP handler to match trees [source,c] ---- #include -#include +#include void nng_http_handler_set_tree(nng_http_handler *handler); @@ -53,5 +53,5 @@ handling. [.text-left] xref:nng_http_handler_alloc.3http.adoc[nng_http_handler_alloc(3http)], xref:nng_http_server_add_handler.3http.adoc[nng_http_server_add_handler(3http)], -xref:nng_http_req_get_method.3http.adoc[nng_http_req_get_method(3http)], +xref:nng_http_get_method.3http.adoc[nng_http_get_method(3http)], xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_hijack.3http.adoc b/docs/man/nng_http_hijack.3http.adoc deleted file mode 100644 index 51231425d..000000000 --- a/docs/man/nng_http_hijack.3http.adoc +++ /dev/null @@ -1,65 +0,0 @@ -= nng_http_hijack(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_hijack - hijack HTTP server connection - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_hijack(nng_http_conn *conn); ----- - -== DESCRIPTION -(((HTTP, hijack))) -The `nng_http_hijack()` function hijacks the connection _conn_, causing it -to be disassociated from the HTTP server where it was created. - -The purpose of this function is the creation of HTTP upgraders (such as -WebSocket), where the underlying HTTP connection will be taken over for -some other purpose, and should not be used any further by the server. - -This function is most useful when called from a handler function. -(See xref:nng_http_handler_alloc.3http.adoc[`nng_http_handler_alloc()`].) - -NOTE: It is the responsibility of the caller to dispose of the underlying -connection when it is no longer needed. -Furthermore, the HTTP server will no longer send any responses to the -hijacked connection, so the caller should do that as well if appropriate. -(See xref:nng_http_conn_write_res.3http.adoc[`nng_http_conn_write_res()`].) - -TIP: This function is intended to facilitate uses cases that involve changing -the protocol from HTTP, such as WebSocket. -Most applications will never need to use this function. - -== RETURN VALUES - -None. - -== ERRORS - -[horizontal] -`NNG_ECLOSED`:: The connection was closed. -`NNG_ENOMEM`:: Insufficient free memory exists. -`NNG_ENOTSUP`:: HTTP not supported. - -== SEE ALSO - -[.text-left] -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng_http_conn_write_res.3http.adoc[nng_http_conn_write_res(3http)], -xref:nng_http_handler_alloc.3http.adoc[nng_http_handler_alloc(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_add_header.3http.adoc b/docs/man/nng_http_req_add_header.3http.adoc deleted file mode 100644 index bf95254a9..000000000 --- a/docs/man/nng_http_req_add_header.3http.adoc +++ /dev/null @@ -1,65 +0,0 @@ -= nng_http_req_add_header(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_add_header - add HTTP request header - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_req_add_header(nng_http_req *req, const char *key, - const char *val); ----- - -== DESCRIPTION - -The `nng_http_req_add_header()` adds an HTTP header for the request -_req_ and the _key_ to the _val_. The _key_ and _val_ are copied. - -If a header with the value of _key_ already exists, then a comma -and whitespace separate are appended to it, followed by _val_. - -If no such header already exists, then one is created with the value _val_. - -TIP: The HTTP specification requires that duplicate headers be treated -identically to a single header with multiple comma-delimited values. - -TIP: See xref:nng_http_req_set_header.3http.adoc[`nng_http_req_set_header()`] if -replacement of an existing header rather than appending to it is desired. - -The value of _key_ is case insensitive, and should not include the final -colon in an HTTP header. -For example, specifying `Host` or `hOSt` are -equivalent, whereas the value `Host:` is not a legal header key. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_del_header.3http.adoc[nng_http_req_del_header(3http)], -xref:nng_http_req_get_header.3http.adoc[nng_http_req_get_header(3http)], -xref:nng_http_req_set_header.3http.adoc[nng_http_req_set_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_alloc.3http.adoc b/docs/man/nng_http_req_alloc.3http.adoc deleted file mode 100644 index 706ef9d9a..000000000 --- a/docs/man/nng_http_req_alloc.3http.adoc +++ /dev/null @@ -1,68 +0,0 @@ -= nng_http_req_alloc(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_alloc - allocate HTTP request structure - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_req_alloc(nng_http_req **reqp, const nng_url *url); ----- - -== DESCRIPTION - -The `nng_http_req_alloc()` function allocates a new HTTP request structure -and stores a pointer to it in __reqp__. -The request will be initialized -to perform an HTTP/1.1 `GET` operation using the URL specified in __url__. - -TIP: It is possible to specify `NULL` for the URL. -In this case the URI for the request must be specified by a subsequent call -to xref:nng_http_req_set_uri.3http.adoc[`nng_http_req_set_uri()`]. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient free memory exists to allocate a message. -`NNG_ENOTSUP`:: HTTP support not configured. - -== SEE ALSO - -[.text-left] -xref:nng_http_conn_read_req.3http.adoc[nng_http_conn_read_req(3http)], -xref:nng_http_conn_write_req.3http.adoc[nng_http_conn_write_req(3http)], -xref:nng_http_req_add_header.3http.adoc[nng_http_req_add_header(3http)], -xref:nng_http_req_copy_data.3http.adoc[nng_http_req_copy_data(3http)], -xref:nng_http_req_del_header.3http.adoc[nng_http_req_del_header(3http)], -xref:nng_http_req_free.3http.adoc[nng_http_req_free(3http)], -xref:nng_http_req_get_header.3http.adoc[nng_http_req_get_header(3http)], -xref:nng_http_req_get_method.3http.adoc[nng_http_req_get_method(3http)], -xref:nng_http_req_get_uri.3http.adoc[nng_http_req_get_uri(3http)], -xref:nng_http_req_get_version.3http.adoc[nng_http_req_get_version(3http)], -xref:nng_http_req_reset.3http.adoc[nng_http_req_reset(3http)], -xref:nng_http_req_set_data.3http.adoc[nng_http_req_set_data(3http)], -xref:nng_http_req_set_method.3http.adoc[nng_http_req_set_method(3http)], -xref:nng_http_req_set_uri.3http.adoc[nng_http_req_set_uri(3http)], -xref:nng_http_req_set_version.3http.adoc[nng_http_req_set_version(3http)], -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_url_parse.3.adoc[nng_url_parse(3)] -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_copy_data.3http.adoc b/docs/man/nng_http_req_copy_data.3http.adoc deleted file mode 100644 index 7ab864fa3..000000000 --- a/docs/man/nng_http_req_copy_data.3http.adoc +++ /dev/null @@ -1,62 +0,0 @@ -= nng_http_req_copy_data(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_copy_data - copy HTTP request body - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_req_copy_data(nng_http_req *req, const void *body, size_t size); ----- - -== DESCRIPTION - -The `nng_http_req_copy_data()` makes a copy of _body_ (of size __size__) -and sets the HTTP body for the request _req_ to it. -The copy will be deallocated automatically when _req_ is freed. - -The copied body data will be automatically sent with the request when it -is sent using xref:nng_http_conn_write_req.3http.adoc[`nng_http_conn_write_req()`]. - -This also updates the relevant `Content-Length` header of _req_. - -NOTE: The current framework does not support sending data via chunked -transfer-encoding. - -TIP: To avoid copying data, the -xref:nng_http_req_set_data.3http.adoc[`nng_http_req_set_data()`] may be used instead. - -TIP: It is a good idea to also set the `Content-Type` header. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_conn_write_req.3http.adoc[nng_http_conn_write_req(3http)], -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_set_data.3http.adoc[nng_http_req_set_data(3http)], -xref:nng_http_req_set_header.3http.adoc[nng_http_req_set_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_del_header.3http.adoc b/docs/man/nng_http_req_del_header.3http.adoc deleted file mode 100644 index d54f65e74..000000000 --- a/docs/man/nng_http_req_del_header.3http.adoc +++ /dev/null @@ -1,53 +0,0 @@ -= nng_http_req_del_header(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_del_header - delete HTTP request header - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_req_del_header(nng_http_req *req, const char *key); ----- - -== DESCRIPTION - -The `nng_http_req_del_header()` removes all HTTP headers with the -associated _key_ from the request structure _req_. - -The value of _key_ is case insensitive, and should not include the final -colon in an HTTP header. -For example, specifying `Host` or `hOSt` are -equivalent, whereas the value `Host:` is not a legal header key. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOENT`:: No header with the key _key_ was present. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_add_header.3http.adoc[nng_http_req_add_header(3http)], -xref:nng_http_req_del_header.3http.adoc[nng_http_req_del_header(3http)], -xref:nng_http_req_get_header.3http.adoc[nng_http_req_get_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_free.3http.adoc b/docs/man/nng_http_req_free.3http.adoc deleted file mode 100644 index daa858b89..000000000 --- a/docs/man/nng_http_req_free.3http.adoc +++ /dev/null @@ -1,47 +0,0 @@ -= nng_http_req_free(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_free - free HTTP request structure - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_req_free(nng_http_req *req); ----- - -== DESCRIPTION - -The `nng_http_req_free()` function deallocates the HTTP request structure -_req_ entirely. - -TIP: Instead of freeing and reallocating request structures, it is possible -to reuse _req_ with xref:nng_http_req_reset.3http.adoc[`nng_http_req_reset()`]. - -== RETURN VALUES - -None. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_reset.3http.adoc[nng_http_req_reset(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_get_data.3http.adoc b/docs/man/nng_http_req_get_data.3http.adoc deleted file mode 100644 index e006bb1b8..000000000 --- a/docs/man/nng_http_req_get_data.3http.adoc +++ /dev/null @@ -1,50 +0,0 @@ -= nng_http_req_get_data(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_get_data - get HTTP request body - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_req_get_data(nng_http_req *req, void **bodyp, size_t *sizep); ----- - -== DESCRIPTION - -The `nng_http_req_get_data()` gets the HTTP body associated with -the request _req_, storing a pointer to the buffer at the location referenced -by _bodyp_, and the length of the associated buffer at the location referenced -by _sizep_. - -NOTE: The buffer returned is owned by _req_, and will automatically freed -when the request is freed. - -== RETURN VALUES - -None. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_set_data.3http.adoc[nng_http_req_copy_data(3http)], -xref:nng_http_req_copy_data.3http.adoc[nng_http_req_copy_data(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_get_header.3http.adoc b/docs/man/nng_http_req_get_header.3http.adoc deleted file mode 100644 index cbc6ec493..000000000 --- a/docs/man/nng_http_req_get_header.3http.adoc +++ /dev/null @@ -1,52 +0,0 @@ -= nng_http_req_get_header(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_get_header - return HTTP request header - -== SYNOPSIS - -[source, c] ----- -#include -#include - -const char *nng_http_req_get_header(const nng_http_req *req, const char *key); ----- - -== DESCRIPTION - -The `nng_http_req_get_header()` looks for an HTTP header _key_ in -the request _req_, and returns the associated value if found, -or `NULL` if not found. - -The value of _key_ is case insensitive, and should not include the final -colon in an HTTP header. -For example, specifying `Host` or `hOSt` are -equivalent, whereas the value `Host:` will not find anything. - - -== RETURN VALUES - -HTTP header value for _key_, if it exists, or NULL otherwise. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_add_header.3http.adoc[nng_http_req_add_header(3http)], -xref:nng_http_req_set_header.3http.adoc[nng_http_req_set_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_get_method.3http.adoc b/docs/man/nng_http_req_get_method.3http.adoc deleted file mode 100644 index 20f6010b1..000000000 --- a/docs/man/nng_http_req_get_method.3http.adoc +++ /dev/null @@ -1,46 +0,0 @@ -= nng_http_req_get_method(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_get_method - return HTTP request method - -== SYNOPSIS - -[source, c] ----- -#include -#include - -const char *nng_http_req_get_method(const nng_http_req *req); ----- - -== DESCRIPTION - -The `nng_http_req_get_method()` returns the HTTP method associated with -the request _req_. -The value will be a string, such as "GET" or "POST". - - -== RETURN VALUES - -Request method as a string. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_set_method.3http.adoc[nng_http_req_set_method(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_get_uri.3http.adoc b/docs/man/nng_http_req_get_uri.3http.adoc deleted file mode 100644 index 8e664a1fd..000000000 --- a/docs/man/nng_http_req_get_uri.3http.adoc +++ /dev/null @@ -1,47 +0,0 @@ -= nng_http_req_get_uri(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_get_uri - return HTTP request URI - -== SYNOPSIS - -[source, c] ----- -#include -#include - -const char *nng_http_req_get_uri(const nng_http_req *req); ----- - -== DESCRIPTION - -The `nng_http_req_get_uri()` returns the URI (path) associated with the HTTP -request _req_. -The value returned includes the path, as well as any query information or -fragment. The value will look like a file system path -with those optional components appended, such as `/api/get_info.cgi?name=garrett`. - -== RETURN VALUES - -Request URI as a string. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_set_uri.3http.adoc[nng_http_req_set_uri(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_get_version.3http.adoc b/docs/man/nng_http_req_get_version.3http.adoc deleted file mode 100644 index 537f6caf3..000000000 --- a/docs/man/nng_http_req_get_version.3http.adoc +++ /dev/null @@ -1,45 +0,0 @@ -= nng_http_req_get_version(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_get_version - return HTTP request protocol version - -== SYNOPSIS - -[source, c] ----- -#include -#include - -const char *nng_http_req_get_version(const nng_http_req *req); ----- - -== DESCRIPTION - -The `nng_http_req_get_version()` returns a string representing the HTTP -protocol version associated with the request _req_, such as "HTTP/1.1". - - -== RETURN VALUES - -Request version as a string. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_set_version.3http.adoc[nng_http_req_set_version(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_reset.3http.adoc b/docs/man/nng_http_req_reset.3http.adoc deleted file mode 100644 index 58dcc149c..000000000 --- a/docs/man/nng_http_req_reset.3http.adoc +++ /dev/null @@ -1,48 +0,0 @@ -= nng_http_req_reset(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_reset - reset HTTP request structure - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_req_reset(nng_http_req *req); ----- - -== DESCRIPTION - -The `nng_http_req_reset()` function resets the request __req__ so that it -is just as if it had been freshly allocated with -xref:nng_http_req_alloc.3http.adoc[`nng_http_req_alloc()`] with a `NULL` URL. - -NOTE: Before using this with an HTTP operation, the URI must be set using -xref:nng_http_req_set_uri.3http.adoc[`nng_http_req_set_uri()`]. - -== RETURN VALUES - -None. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_set_uri.3http.adoc[nng_http_req_set_uri(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_set_data.3http.adoc b/docs/man/nng_http_req_set_data.3http.adoc deleted file mode 100644 index 583d7a58f..000000000 --- a/docs/man/nng_http_req_set_data.3http.adoc +++ /dev/null @@ -1,64 +0,0 @@ -= nng_http_req_set_data(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_set_data - set HTTP request body - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_req_set_data(nng_http_req *req, const void *body, size_t size); ----- - -== DESCRIPTION - -The `nng_http_req_set_data()` sets the HTTP body associated with -the request _req_ to _body_, and the size of the body to _size_. -This body data will be automatically sent with the request when it -is sent using xref:nng_http_conn_write_req.3http.adoc[`nng_http_conn_write_req()`]. - -This also updates the relevant `Content-Length` header of _req_. - -NOTE: The current framework does not support sending data via chunked -transfer-encoding. - -The _body_ is *not* copied, and the caller must ensure that it is available -until the _req_ is deallocated. - -TIP: To have a local copy allocated with _req_ that will be automatically -deallocated when _req_ is freed, -see xref:nng_http_req_copy_data.3http.adoc[`nng_http_req_copy_data()`]. - -TIP: It is a good idea to also set the `Content-Type` header. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_conn_write_req.3http.adoc[nng_http_conn_write_req(3http)], -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_copy_data.3http.adoc[nng_http_req_copy_data(3http)], -xref:nng_http_req_set_header.3http.adoc[nng_http_req_set_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_set_header.3http.adoc b/docs/man/nng_http_req_set_header.3http.adoc deleted file mode 100644 index e38b56644..000000000 --- a/docs/man/nng_http_req_set_header.3http.adoc +++ /dev/null @@ -1,59 +0,0 @@ -= nng_http_req_set_header(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_set_header - set HTTP request header - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_req_set_header(nng_http_req *req, const char *key, - const char *val); ----- - -== DESCRIPTION - -The `nng_http_req_set_header()` sets the HTTP header for the request -_req_ and the _key_ to the _val_. -The _key_ and _val_ are copied. -Any previous header with the same _key_ is replaced. - -TIP: See xref:nng_http_req_add_header.3http.adoc[`nng_http_req_add_header()`] to -add additional headers with the same _key_ without replacing them. - -The value of _key_ is case insensitive, and should not include the final -colon in an HTTP header. -For example, specifying `Host` or `hOSt` are -equivalent, whereas the value `Host:` is not a legal header key. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_add_header.3http.adoc[nng_http_req_add_header(3http)], -xref:nng_http_req_del_header.3http.adoc[nng_http_req_del_header(3http)], -xref:nng_http_req_get_header.3http.adoc[nng_http_req_get_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_set_uri.3http.adoc b/docs/man/nng_http_req_set_uri.3http.adoc deleted file mode 100644 index fd6961d68..000000000 --- a/docs/man/nng_http_req_set_uri.3http.adoc +++ /dev/null @@ -1,59 +0,0 @@ -= nng_http_req_set_uri(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_set_uri - set HTTP request URI - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_req_set_uri(nng_http_req *req, const char *uri); ----- - -== DESCRIPTION - -The `nng_http_req_set_uri()` sets the Request-URI associated with -the request _req_ to _uri_. -The _uri_ should contain precisely the -string that will be sent to the HTTP server in the request, including -any query information or fragment. - -A local copy of the _uri_ is made in the request _req_. - -NOTE: No validation or canonicalization of the _uri_ is performed. - -TIP: The xref:nng_url_parse.3.adoc[`nng_url_parse()`] function can be used to -perform validation and canonicalization. -The `u_requri` member will -contain a suitable value that can be used with this function. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_get_uri.3http.adoc[nng_http_req_get_uri(3http)], -xref:nng_url_parse.3.adoc[nng_url_parse(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_req_set_version.3http.adoc b/docs/man/nng_http_req_set_version.3http.adoc deleted file mode 100644 index ca41f0ef5..000000000 --- a/docs/man/nng_http_req_set_version.3http.adoc +++ /dev/null @@ -1,57 +0,0 @@ -= nng_http_req_set_version(3http) -// -// Copyright 2024 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_req_set_version - set HTTP request protocol version - -== SYNOPSIS - -[source, c] ----- -#include -#include - -#define NNG_HTTP_VERSION_1_1 "HTTP/1.0" -#define NNG_HTTP_VERSION_1_1 "HTTP/1.1" - -int nng_http_req_set_version(nng_http_req *req, const char *version); ----- - -== DESCRIPTION - -The `nng_http_req_set_version()` sets the HTTP protocol version associated with -the request _req_ to _version_. -The _version_ must be a string containing -a valid HTTP protocol version, such as "HTTP/1.0". -The default value is "HTTP/1.1". - -A local copy of the _version_ is made in the request _req_. - -NOTE: The library does not contain support for versions of HTTP other than -"HTTP/1.0" and "HTTP/1.1". - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library, or no support for the version specified. - -== SEE ALSO - -[.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_get_version.3http.adoc[nng_http_req_get_version(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_add_header.3http.adoc b/docs/man/nng_http_res_add_header.3http.adoc deleted file mode 100644 index eb2a79c1a..000000000 --- a/docs/man/nng_http_res_add_header.3http.adoc +++ /dev/null @@ -1,65 +0,0 @@ -= nng_http_res_add_header(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_add_header - add HTTP response header - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_res_add_header(nng_http_res *res, const char *key, - const char *val); ----- - -== DESCRIPTION - -The `nng_http_res_add_header()` adds an HTTP header for the response -_res_ and the _key_ to the _val_. -The _key_ and _val_ are copied. - -If a header with the value of _key_ already exists, then a comma -and whitespace separate are appended to it, followed by _val_. - -If no such header already exists, then one is created with the value _val_. - -TIP: The HTTP specification requires that duplicate headers be treated -identically to a single header with multiple comma-delimited values. - -TIP: See xref:nng_http_res_set_header.3http.adoc[`nng_http_res_set_header()`] if -replacement of an existing header rather than appending to it is desired. - -The value of _key_ is case insensitive, and should not include the final -colon in an HTTP header. For example, specifying `Host` or `hOSt` are -equivalent, whereas the value `Host:` is not a legal header key. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_del_header.3http.adoc[nng_http_res_del_header(3http)], -xref:nng_http_res_get_header.3http.adoc[nng_http_res_get_header(3http)], -xref:nng_http_res_set_header.3http.adoc[nng_http_res_set_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_alloc.3http.adoc b/docs/man/nng_http_res_alloc.3http.adoc deleted file mode 100644 index f546d1514..000000000 --- a/docs/man/nng_http_res_alloc.3http.adoc +++ /dev/null @@ -1,68 +0,0 @@ -= nng_http_res_alloc(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_alloc - allocate HTTP response structure - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_res_alloc(nng_http_res **resp); ----- - -== DESCRIPTION - -The `nng_http_res_alloc()` function allocates a new HTTP response structure -and stores a pointer to it in __resp__. -The response will be initialized -with status code 200 (`NNG_HTTP_STATUS_OK`), and a reason phrase of `OK`, -and HTTP protocol version `HTTP/1.1`. - -TIP: When an error response is needed, consider using -xref:nng_http_res_alloc_error.3http.adoc[`nng_http_res_alloc_error()`] instead. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient free memory exists to allocate a message. -`NNG_ENOTSUP`:: HTTP support not configured. - -== SEE ALSO - -[.text-left] -xref:nng_http_conn_read_res.3http.adoc[nng_http_conn_read_res(3http)], -xref:nng_http_conn_write_res.3http.adoc[nng_http_conn_write_res(3http)], -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_res_alloc_error.3http.adoc[nng_http_res_alloc_error(3http)], -xref:nng_http_res_add_header.3http.adoc[nng_http_res_add_header(3http)], -xref:nng_http_res_copy_data.3http.adoc[nng_http_res_copy_data(3http)], -xref:nng_http_res_del_header.3http.adoc[nng_http_res_del_header(3http)], -xref:nng_http_res_free.3http.adoc[nng_http_res_free(3http)], -xref:nng_http_res_get_header.3http.adoc[nng_http_res_get_header(3http)], -xref:nng_http_res_get_reason.3http.adoc[nng_http_res_get_reason(3http)], -xref:nng_http_res_get_status.3http.adoc[nng_http_res_get_status(3http)], -xref:nng_http_res_get_version.3http.adoc[nng_http_res_get_version(3http)], -xref:nng_http_res_reset.3http.adoc[nng_http_res_reset(3http)], -xref:nng_http_res_set_data.3http.adoc[nng_http_res_set_data(3http)], -xref:nng_http_res_set_reason.3http.adoc[nng_http_res_set_reason(3http)], -xref:nng_http_res_set_status.3http.adoc[nng_http_res_set_status(3http)], -xref:nng_http_res_set_version.3http.adoc[nng_http_res_set_version(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_alloc_error.3http.adoc b/docs/man/nng_http_res_alloc_error.3http.adoc deleted file mode 100644 index 2c8d729f4..000000000 --- a/docs/man/nng_http_res_alloc_error.3http.adoc +++ /dev/null @@ -1,58 +0,0 @@ -= nng_http_res_alloc_error(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_alloc_error - allocate HTTP error response - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_res_alloc_error(nng_http_res **resp, uint16_t status); ----- - -== DESCRIPTION - -The `nng_http_res_alloc_error()` function allocates a new HTTP response structure -and stores a pointer to it in __resp__. -The response will be initialized -with the status code _status_, a corresponding reason phrase, and -a simple HTML page containing the same information will be generated and -attached to the response. -(Relevant HTTP headers will be set as well, such as `Content-Type` -and `Content-Length`.) -The HTTP protocol version is also set to "HTTP/1.1". - -TIP: This is the simplest way to generate an error response. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient free memory exists to allocate a message. -`NNG_ENOTSUP`:: HTTP support not configured. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_free.3http.adoc[nng_http_res_free(3http)], -xref:nng_http_res_set_reason.3http.adoc[nng_http_res_set_reason(3http)], -xref:nng_http_res_set_status.3http.adoc[nng_http_res_set_status(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_copy_data.3http.adoc b/docs/man/nng_http_res_copy_data.3http.adoc deleted file mode 100644 index b2cea28ae..000000000 --- a/docs/man/nng_http_res_copy_data.3http.adoc +++ /dev/null @@ -1,62 +0,0 @@ -= nng_http_res_copy_data(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_copy_data - copy HTTP response body - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_res_copy_data(nng_http_res *res, const void *body, size_t size); ----- - -== DESCRIPTION - -The `nng_http_res_copy_data()` makes a copy of _body_ (of size __size__) -and sets the HTTP body for the response _res_ to it. -The copy will be deallocated automatically when _res_ is freed. - -The copied body data will be automatically sent with the response when it -is sent using xref:nng_http_conn_write_res.3http.adoc[`nng_http_conn_write_res()`]. - -This also updates the relevant `Content-Length` header of _res_. - -NOTE: The current framework does not support sending data via chunked -transfer-encoding. - -TIP: To avoid copying data, the -xref:nng_http_res_set_data.3http.adoc[`nng_http_res_set_data()`] may be used instead. - -TIP: It is a good idea to also set the `Content-Type` header. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_conn_write_res.3http.adoc[nng_http_conn_write_res(3http)], -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_set_data.3http.adoc[nng_http_res_set_data(3http)], -xref:nng_http_res_set_header.3http.adoc[nng_http_res_set_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_del_header.3http.adoc b/docs/man/nng_http_res_del_header.3http.adoc deleted file mode 100644 index 2a8500ee5..000000000 --- a/docs/man/nng_http_res_del_header.3http.adoc +++ /dev/null @@ -1,52 +0,0 @@ -= nng_http_res_del_header(3http) -// -// Copyright 2020 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_del_header - delete HTTP response header - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_res_del_header(nng_http_res *res, const char *key); ----- - -== DESCRIPTION - -The `nng_http_res_del_header()` removes all HTTP headers with the -associated _key_ from the response structure _res_. - -The value of _key_ is case insensitive, and should not include the final -colon in an HTTP header. For example, specifying `Host` or `hOSt` are -equivalent, whereas the value `Host:` is not a legal header key. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOENT`:: No header with the key _key_ was present. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_add_header.3http.adoc[nng_http_res_add_header(3http)], -xref:nng_http_res_del_header.3http.adoc[nng_http_res_del_header(3http)], -xref:nng_http_res_get_header.3http.adoc[nng_http_res_get_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_free.3http.adoc b/docs/man/nng_http_res_free.3http.adoc deleted file mode 100644 index c278648c9..000000000 --- a/docs/man/nng_http_res_free.3http.adoc +++ /dev/null @@ -1,47 +0,0 @@ -= nng_http_res_free(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_free - free HTTP response structure - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_res_free(nng_http_res *req); ----- - -== DESCRIPTION - -The `nng_http_res_free()` function deallocates the HTTP response structure -_res_ entirely. - -TIP: Instead of freeing and reallocating response structures, it is possible -to reuse _res_ with xref:nng_http_res_reset.3http.adoc[`nng_http_res_reset()`]. - -== RETURN VALUES - -None. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_reset.3http.adoc[nng_http_res_reset(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_get_data.3http.adoc b/docs/man/nng_http_res_get_data.3http.adoc deleted file mode 100644 index 374bce704..000000000 --- a/docs/man/nng_http_res_get_data.3http.adoc +++ /dev/null @@ -1,50 +0,0 @@ -= nng_http_res_get_data(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_get_data - get HTTP response body - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_res_get_data(nng_http_res *res, void **bodyp, size_t *sizep); ----- - -== DESCRIPTION - -The `nng_http_res_get_data()` gets the HTTP body associated with -the request _res_, storing a pointer to the buffer at the location referenced -by _bodyp_, and the length of the associated buffer at the location referenced -by _sizep_. - -NOTE: The buffer returned is owned by _res_, and will automatically freed -when the request is freed. - -== RETURN VALUES - -None. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_res_set_data.3http.adoc[nng_http_req_copy_data(3http)], -xref:nng_http_res_copy_data.3http.adoc[nng_http_req_copy_data(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_get_header.3http.adoc b/docs/man/nng_http_res_get_header.3http.adoc deleted file mode 100644 index 51d37abab..000000000 --- a/docs/man/nng_http_res_get_header.3http.adoc +++ /dev/null @@ -1,52 +0,0 @@ -= nng_http_res_get_header(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_get_header - return HTTP response header - -== SYNOPSIS - -[source, c] ----- -#include -#include - -const char *nng_http_res_get_header(const nng_http_res *res, const char *key); ----- - -== DESCRIPTION - -The `nng_http_res_get_header()` looks for an HTTP header _key_ in -the response _res_, and returns the associated value if found, -or `NULL` if not found. - -The value of _key_ is case insensitive, and should not include the final -colon in an HTTP header. -For example, specifying `Host` or `hOSt` are -equivalent, whereas the value `Host:` will not find anything. - - -== RETURN VALUES - -HTTP header value for _key_, if it exists, or NULL otherwise. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_add_header.3http.adoc[nng_http_res_add_header(3http)], -xref:nng_http_res_set_header.3http.adoc[nng_http_res_set_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_get_reason.3http.adoc b/docs/man/nng_http_res_get_reason.3http.adoc deleted file mode 100644 index 3b9fdd587..000000000 --- a/docs/man/nng_http_res_get_reason.3http.adoc +++ /dev/null @@ -1,48 +0,0 @@ -= nng_http_res_get_reason(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_get_reason - return HTTP response reason - -== SYNOPSIS - -[source, c] ----- -#include -#include - -const char *nng_http_res_get_reason(const nng_http_res *res); ----- - -== DESCRIPTION - -The `nng_http_res_get_reason()` returns a string representing the -reason associated with the response _res_. -This is a human-readable explanation of the status code that -would be obtained from -xref:nng_http_res_get_status.3http.adoc[`nng_http_res_get_status()`]. - -== RETURN VALUES - -Reason as a string. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_get_status.3http.adoc[nng_http_res_get_status(3http)], -xref:nng_http_res_set_reason.3http.adoc[nng_http_res_set_reason(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_get_status.3http.adoc b/docs/man/nng_http_res_get_status.3http.adoc deleted file mode 100644 index 827cfbf6b..000000000 --- a/docs/man/nng_http_res_get_status.3http.adoc +++ /dev/null @@ -1,117 +0,0 @@ -= nng_http_res_get_status(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_get_status - return HTTP status code - -== SYNOPSIS - -[source, c] ----- -#include -#include - -uint16_t nng_http_res_get_status(const nng_http_res *res); ----- - -== DESCRIPTION - -The `nng_http_res_get_status()` returns a numeric code corresponding to -the HTTP status of the response _res_. - -For convenience, a number of predefined symbols corresponding to well-known -HTTP status codes are available. - -[source, c] ----- -enum { - NNG_HTTP_STATUS_CONTINUE = 100, - NNG_HTTP_STATUS_SWITCHING = 101, - NNG_HTTP_STATUS_PROCESSING = 102, - NNG_HTTP_STATUS_OK = 200, - NNG_HTTP_STATUS_CREATED = 201, - NNG_HTTP_STATUS_ACCEPTED = 202, - NNG_HTTP_STATUS_NOT_AUTHORITATIVE = 203, - NNG_HTTP_STATUS_NO_CONTENT = 204, - NNG_HTTP_STATUS_RESET_CONTENT = 205, - NNG_HTTP_STATUS_PARTIAL_CONTENT = 206, - NNG_HTTP_STATUS_MULTI_STATUS = 207, - NNG_HTTP_STATUS_ALREADY_REPORTED = 208, - NNG_HTTP_STATUS_IM_USED = 226, - NNG_HTTP_STATUS_MULTIPLE_CHOICES = 300, - NNG_HTTP_STATUS_STATUS_MOVED_PERMANENTLY = 301, - NNG_HTTP_STATUS_FOUND = 302, - NNG_HTTP_STATUS_SEE_OTHER = 303, - NNG_HTTP_STATUS_NOT_MODIFIED = 304, - NNG_HTTP_STATUS_USE_PROXY = 305, - NNG_HTTP_STATUS_TEMPORARY_REDIRECT = 307, - NNG_HTTP_STATUS_PERMANENT_REDIRECT = 308, - NNG_HTTP_STATUS_BAD_REQUEST = 400, - NNG_HTTP_STATUS_UNAUTHORIZED = 401, - NNG_HTTP_STATUS_PAYMENT_REQUIRED = 402, - NNG_HTTP_STATUS_FORBIDDEN = 403, - NNG_HTTP_STATUS_NOT_FOUND = 404, - NNG_HTTP_STATUS_METHOD_NOT_ALLOWED = 405, - NNG_HTTP_STATUS_NOT_ACCEPTABLE = 406, - NNG_HTTP_STATUS_PROXY_AUTH_REQUIRED = 407, - NNG_HTTP_STATUS_REQUEST_TIMEOUT = 408, - NNG_HTTP_STATUS_CONFLICT = 409, - NNG_HTTP_STATUS_GONE = 410, - NNG_HTTP_STATUS_LENGTH_REQUIRED = 411, - NNG_HTTP_STATUS_PRECONDITION_FAILED = 412, - NNG_HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, - NNG_HTTP_STATUS_ENTITY_TOO_LONG = 414, - NNG_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, - NNG_HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, - NNG_HTTP_STATUS_EXPECTATION_FAILED = 417, - NNG_HTTP_STATUS_TEAPOT = 418, - NNG_HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, - NNG_HTTP_STATUS_LOCKED = 423, - NNG_HTTP_STATUS_FAILED_DEPENDENCY = 424, - NNG_HTTP_STATUS_UPGRADE_REQUIRED = 426, - NNG_HTTP_STATUS_PRECONDITION_REQUIRED = 428, - NNG_HTTP_STATUS_TOO_MANY_REQUESTS = 429, - NNG_HTTP_STATUS_HEADERS_TOO_LARGE = 431, - NNG_HTTP_STATUS_UNAVAIL_LEGAL_REASONS = 451, - NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, - NNG_HTTP_STATUS_NOT_IMPLEMENTED = 501, - NNG_HTTP_STATUS_BAD_GATEWAY = 502, - NNG_HTTP_STATUS_SERVICE_UNAVAILABLE = 503, - NNG_HTTP_STATUS_GATEWAY_TIMEOUT = 504, - NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP = 505, - NNG_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, - NNG_HTTP_STATUS_INSUFFICIENT_STORAGE = 507, - NNG_HTTP_STATUS_LOOP_DETECTED = 508, - NNG_HTTP_STATUS_NOT_EXTENDED = 510, - NNG_HTTP_STATUS_NETWORK_AUTH_REQUIRED = 511, -} ----- - -TIP: When displaying status information to users (or logging such information), -consider also including the reason obtained with -xref:nng_http_res_get_reason.3http.adoc[`nng_http_res_get_reason()`]. - -== RETURN VALUES - -HTTP status code. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_get_reason.3http.adoc[nng_http_res_get_reason(3http)], -xref:nng_http_res_set_status.3http.adoc[nng_http_res_set_status(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_get_version.3http.adoc b/docs/man/nng_http_res_get_version.3http.adoc deleted file mode 100644 index d69e387cd..000000000 --- a/docs/man/nng_http_res_get_version.3http.adoc +++ /dev/null @@ -1,45 +0,0 @@ -= nng_http_res_get_version(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_get_version - return HTTP response protocol version - -== SYNOPSIS - -[source, c] ----- -#include -#include - -const char *nng_http_res_get_version(nng_http_res *res); ----- - -== DESCRIPTION - -The `nng_http_res_get_version()` returns a string representing the HTTP -protocol version associated with the request _res_, such as "HTTP/1.1". - - -== RETURN VALUES - -Response version as a string. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_set_version.3http.adoc[nng_http_res_set_version(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_reset.3http.adoc b/docs/man/nng_http_res_reset.3http.adoc deleted file mode 100644 index f78d29a23..000000000 --- a/docs/man/nng_http_res_reset.3http.adoc +++ /dev/null @@ -1,44 +0,0 @@ -= nng_http_res_reset(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_reset - reset HTTP response structure - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_res_reset(nng_http_res *res); ----- - -== DESCRIPTION - -The `nng_http_res_reset()` function resets the response __res__ so that it -is just as if it had been freshly allocated with -xref:nng_http_res_alloc.3http.adoc[`nng_http_res_alloc()`]. - -== RETURN VALUES - -None. - -== ERRORS - -None. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_set_data.3http.adoc b/docs/man/nng_http_res_set_data.3http.adoc deleted file mode 100644 index 7c4c06bcb..000000000 --- a/docs/man/nng_http_res_set_data.3http.adoc +++ /dev/null @@ -1,64 +0,0 @@ -= nng_http_res_set_data(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_set_data - set HTTP response body - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_res_set_data(nng_http_res *res, const void *body, size_t size); ----- - -== DESCRIPTION - -The `nng_http_res_set_data()` sets the HTTP body associated with -the response _res_ to _body_, and the size of the body to _size_. -This body data will be automatically sent with the response when it -is sent using xref:nng_http_conn_write_res.3http.adoc[`nng_http_conn_write_res()`]. - -This also updates the relevant `Content-Length` header of _res_. - -NOTE: The current framework does not support sending data via chunked -transfer-encoding. - -The _body_ is *not* copied, and the caller must ensure that it is available -until the _res_ is deallocated. - -TIP: To have a local copy allocated with _res_ that will be automatically -deallocated when _res_ is freed, -see xref:nng_http_res_copy_data.3http.adoc[`nng_http_res_copy_data()`]. - -TIP: It is a good idea to also set the `Content-Type` header. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_conn_write_res.3http.adoc[nng_http_conn_write_res(3http)], -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_copy_data.3http.adoc[nng_http_res_copy_data(3http)], -xref:nng_http_res_set_header.3http.adoc[nng_http_res_set_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_set_header.3http.adoc b/docs/man/nng_http_res_set_header.3http.adoc deleted file mode 100644 index 2ad4282e4..000000000 --- a/docs/man/nng_http_res_set_header.3http.adoc +++ /dev/null @@ -1,59 +0,0 @@ -= nng_http_res_set_header(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_set_header - set HTTP response header - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_res_set_header(nng_http_res *res, const char *key, - const char *val); ----- - -== DESCRIPTION - -The `nng_http_res_set_header()` sets the HTTP header for the response -_res_ and the _key_ to the _val_. -The _key_ and _val_ are copied. -Any previous header with the same _key_ is replaced. - -TIP: See xref:nng_http_res_add_header.3http.adoc[`nng_http_res_add_header()`] to -add additional headers with the same _key_ without replacing them. - -The value of _key_ is case insensitive, and should not include the final -colon in an HTTP header. -For example, specifying `Host` or `hOSt` are -equivalent, whereas the value `Host:` is not a legal header key. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_add_header.3http.adoc[nng_http_res_add_header(3http)], -xref:nng_http_res_del_header.3http.adoc[nng_http_res_del_header(3http)], -xref:nng_http_res_get_header.3http.adoc[nng_http_res_get_header(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_set_status.3http.adoc b/docs/man/nng_http_res_set_status.3http.adoc deleted file mode 100644 index a13749414..000000000 --- a/docs/man/nng_http_res_set_status.3http.adoc +++ /dev/null @@ -1,115 +0,0 @@ -= nng_http_res_set_status(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_set_status - set HTTP response status - -== SYNOPSIS - -[source, c] ----- -#include -#include - -void nng_http_res_set_status(nng_http_res *res, uint16_t status); ----- - -== DESCRIPTION - -The `nng_http_res_set_status()` sets the numeric HTTP status code -associated with the response _res_ to _status_. -The default value for a newly allocated response is 200 (`NNG_HTTP_STATUS_OK`). - -The _status_ is not verified, so the caller should take care to ensure -that only a valid code is supplied. - -For convenience, a number of predefined symbols are available. - -[source, c] ----- -enum { - NNG_HTTP_STATUS_CONTINUE = 100, - NNG_HTTP_STATUS_SWITCHING = 101, - NNG_HTTP_STATUS_PROCESSING = 102, - NNG_HTTP_STATUS_OK = 200, - NNG_HTTP_STATUS_CREATED = 201, - NNG_HTTP_STATUS_ACCEPTED = 202, - NNG_HTTP_STATUS_NOT_AUTHORITATIVE = 203, - NNG_HTTP_STATUS_NO_CONTENT = 204, - NNG_HTTP_STATUS_RESET_CONTENT = 205, - NNG_HTTP_STATUS_PARTIAL_CONTENT = 206, - NNG_HTTP_STATUS_MULTI_STATUS = 207, - NNG_HTTP_STATUS_ALREADY_REPORTED = 208, - NNG_HTTP_STATUS_IM_USED = 226, - NNG_HTTP_STATUS_MULTIPLE_CHOICES = 300, - NNG_HTTP_STATUS_STATUS_MOVED_PERMANENTLY = 301, - NNG_HTTP_STATUS_FOUND = 302, - NNG_HTTP_STATUS_SEE_OTHER = 303, - NNG_HTTP_STATUS_NOT_MODIFIED = 304, - NNG_HTTP_STATUS_USE_PROXY = 305, - NNG_HTTP_STATUS_TEMPORARY_REDIRECT = 307, - NNG_HTTP_STATUS_PERMANENT_REDIRECT = 308, - NNG_HTTP_STATUS_BAD_REQUEST = 400, - NNG_HTTP_STATUS_UNAUTHORIZED = 401, - NNG_HTTP_STATUS_PAYMENT_REQUIRED = 402, - NNG_HTTP_STATUS_FORBIDDEN = 403, - NNG_HTTP_STATUS_NOT_FOUND = 404, - NNG_HTTP_STATUS_METHOD_NOT_ALLOWED = 405, - NNG_HTTP_STATUS_NOT_ACCEPTABLE = 406, - NNG_HTTP_STATUS_PROXY_AUTH_REQUIRED = 407, - NNG_HTTP_STATUS_REQUEST_TIMEOUT = 408, - NNG_HTTP_STATUS_CONFLICT = 409, - NNG_HTTP_STATUS_GONE = 410, - NNG_HTTP_STATUS_LENGTH_REQUIRED = 411, - NNG_HTTP_STATUS_PRECONDITION_FAILED = 412, - NNG_HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, - NNG_HTTP_STATUS_ENTITY_TOO_LONG = 414, - NNG_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, - NNG_HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, - NNG_HTTP_STATUS_EXPECTATION_FAILED = 417, - NNG_HTTP_STATUS_TEAPOT = 418, - NNG_HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, - NNG_HTTP_STATUS_LOCKED = 423, - NNG_HTTP_STATUS_FAILED_DEPENDENCY = 424, - NNG_HTTP_STATUS_UPGRADE_REQUIRED = 426, - NNG_HTTP_STATUS_PRECONDITION_REQUIRED = 428, - NNG_HTTP_STATUS_TOO_MANY_REQUESTS = 429, - NNG_HTTP_STATUS_HEADERS_TOO_LARGE = 431, - NNG_HTTP_STATUS_UNAVAIL_LEGAL_REASONS = 451, - NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, - NNG_HTTP_STATUS_NOT_IMPLEMENTED = 501, - NNG_HTTP_STATUS_BAD_GATEWAY = 502, - NNG_HTTP_STATUS_SERVICE_UNAVAILABLE = 503, - NNG_HTTP_STATUS_GATEWAY_TIMEOUT = 504, - NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP = 505, - NNG_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, - NNG_HTTP_STATUS_INSUFFICIENT_STORAGE = 507, - NNG_HTTP_STATUS_LOOP_DETECTED = 508, - NNG_HTTP_STATUS_NOT_EXTENDED = 510, - NNG_HTTP_STATUS_NETWORK_AUTH_REQUIRED = 511, -}; ----- - -Please see the relevant HTTP RFCs for the semantics and correct -use of these status codes. - -TIP: It is a good idea to also set the reason message with -xref:nng_http_res_set_reason.3http.adoc[`nng_http_set_reason()`]. -This will help any humans who may have to diagnose a failure. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_get_status.3http.adoc[nng_http_req_get_status(3http)], -xref:nng_http_res_set_reason.3http.adoc[nng_http_req_set_reason(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_set_version.3http.adoc b/docs/man/nng_http_res_set_version.3http.adoc deleted file mode 100644 index 47ce3cd7e..000000000 --- a/docs/man/nng_http_res_set_version.3http.adoc +++ /dev/null @@ -1,57 +0,0 @@ -= nng_http_res_set_version(3http) -// -// Copyright 2024 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_res_set_version - set HTTP response protocol version - -== SYNOPSIS - -[source, c] ----- -#include -#include - -#define NNG_HTTP_VERSION_1_1 "HTTP/1.0" -#define NNG_HTTP_VERSION_1_1 "HTTP/1.1" - -int nng_http_res_set_version(nng_http_res *res, const char *version); ----- - -== DESCRIPTION - -The `nng_http_res_set_version()` sets the HTTP protocol version associated with -the response _res_ to _version_. -The _version_ must be a string containing -a valid HTTP protocol version, such as "HTTP/1.0". -The default value is "HTTP/1.1". - -A local copy of the _version_ is made in the response _res_. - -NOTE: The library does not contain support for versions of HTTP other than -"HTTP/1.0" and "HTTP/1.1". - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOMEM`:: Insufficient memory to perform the operation. -`NNG_ENOTSUP`:: No support for HTTP in the library, or no support for the version specified. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_req_get_version.3http.adoc[nng_http_req_get_version(3http)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_server_add_handler.3http.adoc b/docs/man/nng_http_server_add_handler.3http.adoc index 5b5c474b6..dc839c3ae 100644 --- a/docs/man/nng_http_server_add_handler.3http.adoc +++ b/docs/man/nng_http_server_add_handler.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_add_handler - add HTTP server handler [source, c] ---- #include -#include +#include int nng_http_server_add_handler(nng_http_server *s, nng_http_handler *h); ---- diff --git a/docs/man/nng_http_server_del_handler.3http.adoc b/docs/man/nng_http_server_del_handler.3http.adoc index 4ff89f7df..a4bb203cf 100644 --- a/docs/man/nng_http_server_del_handler.3http.adoc +++ b/docs/man/nng_http_server_del_handler.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_del_handler - delete HTTP server handler [source, c] ---- #include -#include +#include int nng_http_server_del_handler(nng_http_server *s, nng_http_handler *h); ---- diff --git a/docs/man/nng_http_server_get_addr.3http.adoc b/docs/man/nng_http_server_get_addr.3http.adoc index dc699014c..c640c8faa 100644 --- a/docs/man/nng_http_server_get_addr.3http.adoc +++ b/docs/man/nng_http_server_get_addr.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_get_addr - get HTTP server address [source, c] ---- #include -#include +#include int nng_http_server_get_addr(nng_http_server *server, nng_sockaddr *sap); ---- diff --git a/docs/man/nng_http_server_get_tls.3http.adoc b/docs/man/nng_http_server_get_tls.3http.adoc index 51bc72180..a6268e770 100644 --- a/docs/man/nng_http_server_get_tls.3http.adoc +++ b/docs/man/nng_http_server_get_tls.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_get_tls - get HTTP server TLS configuration [source, c] ---- #include -#include +#include int nng_http_server_get_tls(nng_http_server *s, nng_tls_config **cfgp); ---- diff --git a/docs/man/nng_http_server_hold.3http.adoc b/docs/man/nng_http_server_hold.3http.adoc index 0111d43f6..9c0fcf810 100644 --- a/docs/man/nng_http_server_hold.3http.adoc +++ b/docs/man/nng_http_server_hold.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_hold - get and hold HTTP server instance [source, c] ---- #include -#include +#include int nng_http_server_hold(nng_http_server **serverp, const nng_url *url); ---- diff --git a/docs/man/nng_http_server_release.3http.adoc b/docs/man/nng_http_server_release.3http.adoc index 0d9191917..86471e4cf 100644 --- a/docs/man/nng_http_server_release.3http.adoc +++ b/docs/man/nng_http_server_release.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_release - release HTTP server instance [source, c] ---- #include -#include +#include void nng_http_server_release(nng_http_server *server); ---- diff --git a/docs/man/nng_http_server_res_error.3http.adoc b/docs/man/nng_http_server_res_error.3http.adoc index b669a0617..e3d0271fb 100644 --- a/docs/man/nng_http_server_res_error.3http.adoc +++ b/docs/man/nng_http_server_res_error.3http.adoc @@ -18,9 +18,9 @@ nng_http_server_res_error - use HTTP server error page [source, c] ---- #include -#include +#include -int nng_http_server_res_error(nng_http_server *server, +int nng_http_server_res_error(nng_http_server *server, nng_http_res *response); ---- @@ -33,10 +33,7 @@ or xref:nng_http_server_set_error_page.3http.adoc[`nng_http_server_error_page()`] functions. -The status code of the _response_ should have already been set, either -implicitly by allocating it with -xref:nng_http_res_alloc_error.3http.adoc[`nng_http_res_alloc_error()`], -or by calling +The status code of the _response_ should have already been set by calling xref:nng_http_res_set_status.3http.adoc[`nng_http_res_set_status()`]. Any content body previously set for _response_ will be overridden by @@ -55,7 +52,6 @@ This function returns 0 on success, and non-zero otherwise. == SEE ALSO [.text-left] -xref:nng_http_res_alloc_error.3http.adoc[nng_http_res_alloc_error(3http)], xref:nng_http_server_hold.3http.adoc[nng_http_server_hold(3http)], xref:nng_http_server_set_error_file.3http.adoc[nng_http_server_set_error_file(3http)], xref:nng_http_server_set_error_page.3http.adoc[nng_http_server_set_error_page(3http)], diff --git a/docs/man/nng_http_server_set_error_file.3http.adoc b/docs/man/nng_http_server_set_error_file.3http.adoc deleted file mode 100644 index ac38f6f96..000000000 --- a/docs/man/nng_http_server_set_error_file.3http.adoc +++ /dev/null @@ -1,73 +0,0 @@ -= nng_http_server_set_error_file(3http) -// -// Copyright 2018 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This document 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. -// - -== NAME - -nng_http_server_set_error_file - set custom HTTP error file - -== SYNOPSIS - -[source, c] ----- -#include -#include - -int nng_http_server_set_error_file(nng_http_server *server, - uint16_t code, const char *path); ----- - -== DESCRIPTION - -The `nng_http_server_set_error_file()` sets an error page to be used -for HTTP status _code_ on the server instance _server_. -The body content of the HTTP responses will contain the file contents of -the file located at _path_, which should be an HTML file. - -The custom HTML content will be used when the server is returning an -internally generated error response, or is returning an error response -that was allocated with the -xref:nng_http_res_alloc_error.3http.adoc[`nng_http_res_alloc_error()`] -function. -This HTML content will also be used if the application calls the -xref:nng_http_server_res_error.3http.adoc[`nng_http_server_res_error()`]. -The last custom error page set for _code_ by either this function or -xref:`nng_http_server_set_error_page.3http.adoc[`nng_http_server_error_page()`] -will be used. - -NOTE: Error responses that have their body content changed after allocation, -or that are written directly by the application, will not use the body -content supplied here. - -NOTE: The file contents of _path_ are read when this function is called. -Therefore, if the file contents are changed, then this function should -be called again to update the error page. - -== RETURN VALUES - -This function returns 0 on success, and non-zero otherwise. - -== ERRORS - -[horizontal] -`NNG_ENOENT`:: The file named by _path_ does not exist. -`NNG_EPERM`:: No permission to read the file named by _path_. -`NNG_ENOMEM`:: Insufficient free memory exists. -`NNG_ENOTSUP`:: HTTP not supported. - -== SEE ALSO - -[.text-left] -xref:nng_http_res_alloc_error.3http.adoc[nng_http_res_alloc_error(3http)], -xref:nng_http_server_hold.3http.adoc[nng_http_server_hold(3http)], -xref:nng_http_server_res_error.3http.adoc[nng_http_server_res_error(3http)], -xref:nng_http_server_set_error_page.3http.adoc[nng_http_server_set_error_page(3http)], -xref:nng_strerror.3.adoc[nng_strerror(3)], -xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_server_set_error_page.3http.adoc b/docs/man/nng_http_server_set_error_page.3http.adoc index d3b136d5b..7f414a5a7 100644 --- a/docs/man/nng_http_server_set_error_page.3http.adoc +++ b/docs/man/nng_http_server_set_error_page.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_set_error_page - set custom HTTP error page [source, c] ---- #include -#include +#include int nng_http_server_set_error_page(nng_http_server *server, uint16_t code, const char *html); @@ -31,10 +31,7 @@ for HTTP status _code_ on the server instance _server_. The body content of the HTTP responses will contain _html_. The custom HTML content will be used when the server is returning an -internally generated error response, or is returning an error response -that was allocated with the -xref:nng_http_res_alloc_error.3http.adoc[`nng_http_res_alloc_error()`] -function. +internally generated error response. This HTML content will also be used if the application calls the xref:nng_http_server_res_error.3http.adoc[`nng_http_server_res_error()`]. The last custom error page set for _code_ by either this function or @@ -61,7 +58,6 @@ This function returns 0 on success, and non-zero otherwise. == SEE ALSO [.text-left] -xref:nng_http_res_alloc_error.3http.adoc[nng_http_res_alloc_error(3http)], xref:nng_http_server_hold.3http.adoc[nng_http_server_hold(3http)], xref:nng_http_server_res_error.3http.adoc[nng_http_server_res_error(3http)], xref:nng_http_server_set_error_file.3http.adoc[nng_http_server_set_error_file(3http)], diff --git a/docs/man/nng_http_server_set_tls.3http.adoc b/docs/man/nng_http_server_set_tls.3http.adoc index 1fe8eaa14..9979c7352 100644 --- a/docs/man/nng_http_server_set_tls.3http.adoc +++ b/docs/man/nng_http_server_set_tls.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_set_tls - set HTTP server TLS configuration [source, c] ---- #include -#include +#include int nng_http_server_set_tls(nng_http_server *s, nng_tls_config *cfg); ---- diff --git a/docs/man/nng_http_server_start.3http.adoc b/docs/man/nng_http_server_start.3http.adoc index 31e0f3254..23e4e3769 100644 --- a/docs/man/nng_http_server_start.3http.adoc +++ b/docs/man/nng_http_server_start.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_start - start HTTP server [source, c] ---- #include -#include +#include int nng_http_server_start(nng_http_server *server); ---- diff --git a/docs/man/nng_http_server_stop.3http.adoc b/docs/man/nng_http_server_stop.3http.adoc index 098d7bdfb..6da3b35a9 100644 --- a/docs/man/nng_http_server_stop.3http.adoc +++ b/docs/man/nng_http_server_stop.3http.adoc @@ -18,7 +18,7 @@ nng_http_server_stop - stop HTTP server [source, c] ---- #include -#include +#include void nng_http_server_stop(nng_http_server *server); ---- diff --git a/docs/man/nng_http_req_set_method.3http.adoc b/docs/man/nng_http_set_method.3http.adoc similarity index 52% rename from docs/man/nng_http_req_set_method.3http.adoc rename to docs/man/nng_http_set_method.3http.adoc index 9cd4f638a..893dc8755 100644 --- a/docs/man/nng_http_req_set_method.3http.adoc +++ b/docs/man/nng_http_set_method.3http.adoc @@ -1,6 +1,6 @@ -= nng_http_req_set_method(3http) += nng_http_set_method(3http) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2025 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -11,7 +11,7 @@ == NAME -nng_http_req_set_method - set HTTP request method +nng_http_set_method - set HTTP request method == SYNOPSIS @@ -20,26 +20,25 @@ nng_http_req_set_method - set HTTP request method #include #include -void nng_http_req_set_method(nng_http_req *req, const char *method); +void nng_http_set_method(nng_http *conn, const char *method); ---- == DESCRIPTION -The `nng_http_req_set_method()` sets the HTTP method associated with -the request _req_ to _method_. The _method_ must be a string, -such as "GET" or "POST", and the HTTP specifications indicate that it must -be upper case. +The `nng_http_set_method()` sets the HTTP method associated with +the connection _conn_ to _method_. The _method_ must be a string, +such as "GET" or "POST". The default value method for newly allocated requests is "GET". If the method is longer than 32 bytes, it may be silently truncated. (There are no methods defined that are this long.) -A local copy of the _method_ is made in the request _req_. +The value _method_ is copied, so the caller may dispose of it after +the call completes. == SEE ALSO [.text-left] -xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc(3http)], -xref:nng_http_req_get_method.3http.adoc[nng_http_req_get_method(3http)], +xref:nng_http_get_method.3http.adoc[nng_http_get_method(3http)], xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_http_res_set_reason.3http.adoc b/docs/man/nng_http_set_reason.3http.adoc similarity index 59% rename from docs/man/nng_http_res_set_reason.3http.adoc rename to docs/man/nng_http_set_reason.3http.adoc index 50699de2c..62fb45611 100644 --- a/docs/man/nng_http_res_set_reason.3http.adoc +++ b/docs/man/nng_http_set_reason.3http.adoc @@ -1,6 +1,6 @@ -= nng_http_res_set_reason(3http) += nng_http_set_reason(3http) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2025 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -11,26 +11,26 @@ == NAME -nng_http_res_set_reason - set HTTP response reason +nng_http_set_reason - set HTTP response reason == SYNOPSIS [source, c] ---- #include -#include +#include -int nng_http_res_set_reason(nng_http_res *res, const char *reason); +int nng_http_set_reason(nng_http *conn, const char *reason); ---- == DESCRIPTION -The `nng_http_res_set_reason()` sets the human readable reason -associated with the response _res_ to _reason_. +The `nng_http_set_reason()` sets the human readable reason +associated with the response for _conn_ to _reason_. If the value of _reason_ is `NULL` (the default), then a default reason phrase is supplied based upon the value of the status code (see -xref:nng_http_res_set_status.3http.adoc[`nng_http_res_set_status()`]). +xref:nng_http_set_status.3http.adoc[`nng_http_set_status()`]). TIP: The _reason_ is never parsed automatically, but it can be a hint for humans to help them understand the nature of any erroneous result. @@ -50,7 +50,5 @@ This function returns 0 on success, and non-zero otherwise. == SEE ALSO [.text-left] -xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc(3http)], -xref:nng_http_res_get_reason.3http.adoc[nng_http_req_get_reason(3http)], -xref:nng_http_res_set_status.3http.adoc[nng_http_req_set_status(3http)], -xref:nng.7.adoc[nng(7)] +xref:nng_http_get_reason.3http.adoc[nng_http_get_reason(3http)], +xref:nng_http_set_status.3http.adoc[nng_http_set_status(3http)] diff --git a/docs/man/nng_ws.7.adoc b/docs/man/nng_ws.7.adoc index 938b16a91..497839202 100644 --- a/docs/man/nng_ws.7.adoc +++ b/docs/man/nng_ws.7.adoc @@ -107,19 +107,12 @@ setting these must be done before the transport is started. NOTE: The TLS specific options (beginning with `NNG_OPT_TLS_`) are only available for `wss://` endpoints. -((`NNG_OPT_WS_REQUEST_HEADERS`)):: +((`NNG_OPT_WS_HEADER`)):: -(string) Concatenation of multiple lines terminated -by CRLF sequences, that can be used to add further headers to the -HTTP request sent when connecting. -This option can be set on dialers, and retrieved from pipes. +The actual option is a prefix string, beginning with the the contents of the +macro `NNG_OPT_WS_HEADER`, followed by the name of header field. -((`NNG_OPT_WS_RESPONSE_HEADERS`)):: - -(string) Concatenation of multiple lines terminated -by CRLF sequences, that can be used to add further headers to the -HTTP response sent when connecting. -This option can be set on listeners, and retrieved from pipes. +Such options can be set on dialers and listener, and retrieved from pipes. ((`NNG_OPT_WS_RECV_TEXT`)):: diff --git a/docs/ref/SUMMARY.md b/docs/ref/SUMMARY.md index f36c5086b..1c5ad2a50 100644 --- a/docs/ref/SUMMARY.md +++ b/docs/ref/SUMMARY.md @@ -34,6 +34,8 @@ - [Streams](./api/stream.md) + - [HTTP](./api/http.md) + - [Miscellaneous](./api/misc.md) - [ID Map](./api/id_map.md) diff --git a/docs/ref/api/http.md b/docs/ref/api/http.md new file mode 100644 index 000000000..b2382155d --- /dev/null +++ b/docs/ref/api/http.md @@ -0,0 +1,572 @@ +# HTTP Support + +NNG offers support for creation of HTTP clients, and servers. NNG supports HTTP/1.1 at present, and supports +a subset of functionality, but the support should be sufficient for simple clients, REST API servers, static content servers, +and gateways between HTTP and and other protocols. It also provides support for WebSocket based connections. + +HTTP follows a request/reply model, where a client issues a request, and the server is expected to reply. +Every request is answered with a single reply. + +## Header File + +```c +#include +``` + +Unlike the rest of NNG, the HTTP API in NNG requires including `nng/http.h`. It is not necessary to include +the main `nng/nng.h` header, it will be included transitively by `nng/http.h`. + +## Connection Object + +```c +typedef struct nng_http nng_http; +``` + +The {{i:`nng_http`}} object represents a single logical HTTP connection to the server. +For HTTP/1.1 and earlier, this will correspond to a single TCP connection, but the object +also contains state relating to the transaction, such as the hostname used, HTTP method used, +request headers, response status, response headers, and so forth. + +An `nng_http` object can be reused, unless closed, so that additional transactions can be +performed after the first transaction is complete. + +At any given point in time, an `nng_http` object can only refer to a single HTTP transaction. +In NNG, these `nng_http` objects are used in both the client and server APIs. + +The `nng_http` object is created by either [`nng_http_client_connect`] or by an HTTP server +object which then passes it to an [`nng_http_handler`] callback function. + +### HTTP Method + +```c +void nng_http_set_method(nng_http *conn, const char *method); +const char *nng_http_get_method(nng_http *conn); +``` + +Each HTTP transaction has a single verb, or method, that is used. The most common methods are "GET", "HEAD", and "POST", +but a number of others are possible. + +The {{i:`nng_http_set_method`}} function specifies the HTTP method to use for the transaction. +The default is "GET". HTTP methods are case sensitive, and generally upper-case, such as "GET", "POST", "HEAD", +and so forth. This function silently truncates any method to 32-characters. (There are no defined methods longer than this.) + +The {{i:`nng_http_get_method`}} function is used, typically on a server, to retrieve the method the client +set when issuing the transaction. + +### HTTP URI + +```c +int nng_http_set_uri(nng_http *conn, const char *uri, const char *query); +const char *nng_http_get_uri(nng_http *conn); +``` + +The {{i:`nng_http_set_uri`}} function sets the {{i:URI}}, which normally appears like a path such as "/docs/index.html", +for the next transaction on _conn_. It sets the URI to _uri_, and, if _query_ is not `NULL`, also appends the +contents of _query_, separated by either the '?' or '&' character, depending on whether _uri_ already +contains a query string. It may return [`NNG_ENOMEM`], or [`NNG_EMSGSIZE`] if the the result is too long, +or [`NNG_EINVAL`] if there is some other problem with the URI. + +> [!NOTE] +> The _uri_ and _query_ must be already percent-encoded if necessary. + +The {{i:`nni_http_get_uri`}} function is used to obtain the URI that was previously set by `nng_http_set_uri`. +If the URI is unset (such as for a freshly created connection), then it returns `NULL`. The returned value +will have any query concentated, for example "/api/get_user.cgi?name=garrett". + +### HTTP Version + +```c +int nng_http_set_version(nng_http *conn, const char *version); +const char *nng_http_get_version(nng_http *conn); +``` + +The {{i:`nng_http_set_version`}} function is used to select the HTTP protocol version to use for the +exchange. At present, only the values `NNG_HTTP_VERSION_1_0` and `NNG_HTTP_VERSION_1_1` (corresponding to +"HTTP/1.0" and "HTTP/1.1") are supported. NNG will default to using "HTTP/1.1" if this function is not called. +If an unsupported version is supplied, [`NNG_ENOTSUP`] will be returned, otherwise zero. + +The {{i:`nng_http_get_version`}} function is used to determine the version the client selected. Normally +there is little need to use this, but there are some subtle semantic differences between HTTP/1.0 and HTTP/1.1. + +> [!TIP] +> There are few, if any, remaining HTTP/1.0 implementations that are not also capable of HTTP/1.1. +> It might be easiest to just fail any request coming in that is not HTTP/1.1. + +> [!NOTE] +> NNG does not support HTTP/2 or HTTP/3 at this time. + +### HTTP Status + +```c +uint16_t nng_http_get_status(nng_http *conn); +const char *nng_http_get_reason(nng_http_conn *conn); +void nng_http_set_status(nng_http *conn, uint16_t status, const char *reason); +``` + +The {{i:`nng_http_get_status`}} function obtains the numeric code (typipcally numbered from 100 through 599) returned +by the server in the last exchange on _conn_. (If no exchange has been performed yet, the result is undefined.) + +A descriptive message matching the status code is returned by {{i:`nng_http_get_reason`}}. + +The {{i:`nng_http_set_status`}} function is used on a server in a handler callback to set the status codethat will be +reported to the client to _status_, and the associated text (reason) to _reason_. If _reason_ is `NULL`, +then a built in reason based on the _status_ will be used instead. + +> [!TIP] +> Callbacks used on the server may wish to use [`nng_http_server_set_error`] or [`nng_http_server_set_redirect`] instead of +> `nng_http_set_status`, because those functions will also set the response body to a suitable HTML document +> for display to users. + +Status codes are defined by the IETF. Here are defininitions that NNG provides for convenience: + +| Name | Code | Reason Text | Notes | +| ------------------------------------------------------------------------------------------------ | ---- | ------------------------------- | ----------------------------------------------------- | +| `NNG_HTTP_STATUS_CONTINUE` | 100 | Continue | Partial transfer, client may send body. | +| `NNG_HTTP_STATUS_SWITCHING` | 101 | Switching Protocols | Used when upgrading or hijacking a connection. | +| `NNG_HTTP_STATUS_PROCESSING` | 102 | Processing | +| `NNG_HTTP_STATUS_OK` | 200 | OK | Successful result. | +| `NNG_HTTP_STATUS_CREATED` | 201 | Created | Resource created successfully. | +| `NNG_HTTP_STATUS_ACCEPTED` | 202 | Created | Request accepted for future processing. | +| `NNG_HTTP_STATUS_NOT_AUTHORITATIVE` | 203 | Not Authoritative | Request successful, but modified by proxy. | +| `NNG_HTTP_STATUS_NO_CONTENT` | 204 | No Content | Request successful, no content returned. | +| `NNG_HTTP_STATUS_RESET_CONTENT` | 205 | Reset Content | Request successful, client should reload content. | +| `NNG_HTTP_STATUS_PARTIAL_CONTENT` | 206 | Partial Content | Response to a range request. | +| `NNG_HTTP_STATUS_MULTI_STATUS` | 207 | Multi-Status | Used with WebDAV. | +| `NNG_HTTP_STATUS_ALREADY_REPORTED` | 208 | Already Reported | Used with WebDAV. | +| `NNG_HTTP_STATUS_IM_USED` | 226 | IM Used | Used with delta encodings, rarely supported. | +| `NNG_HTTP_STATUS_MULTIPLE_CHOICES` | 300 | Multiple Choices | Multiple responses possible, client should choose. | +| `NNG_HTTP_STATUS_MOVED_PERMANENTLY` | 301 | Moved Permanently | Permanent redirection, may be saved by client. | +| `NNG_HTTP_STATUS_FOUND` | 302 | Found | Temporary redirection, client may switch to GET. | +| `NNG_HTTP_STATUS_SEE_OTHER` | 303 | See Other | Redirect, perhaps after a success POST or PUT. | +| `NNG_HTTP_STATUS_NOT_MODIFIED` | 304 | Not Modified | Resource not modified, client may use cached version. | +| `NNG_HTTP_STATUS_USE_PROXY` | 305 | Use Proxy | +| `NNG_HTTP_STATUS_TEMPORARY_REDIRECT` | 307 | Temporary Redirect | Temporary redirect, preserves method. | +| `NNG_HTTP_STATUS_PERMANENT_REDIRECT` | 308 | Permanent Redirect | Permanent redirect. | +| `NNG_HTTP_STATUS_BAD_REQUEST` | 400 | Bad Request | Generic problem with the request. | +| `NNG_HTTP_STATUS_UNAUTHORIZED` | 401 | Unauthorized | Indicates a problem with authentication. | +| `NNG_HTTP_STATUS_PAYMENT_REQUIRED` | 402 | Payment Required | +| `NNG_HTTP_STATUS_FORBIDDEN` | 403 | Forbidden | No permission to access resource. | +| `NNG_HTTP_STATUS_NOT_FOUND` | 404 | Not Found | Resource does not exist. | +| `NNG_HTTP_STATUS_METHOD_NOT_ALLOWED` | 405 | Method Not Allowed | Resource does not support the method. | +| `NNG_HTTP_STATUS_METHOD_NOT_ACCEPTABLE` | 406 | Not Acceptable | Could not satisfy accept requirements. | +| `NNG_HTTP_STATUS_PROXY_AUTH_REQUIRED` | 407 | Proxy Authentication Required | Proxy requires authentication. | +| `NNG_HTTP_STATUS_REQUEST_TIMEOUT` | 408 | Request Timeout | Timed out waiting for request. | +| `NNG_HTTP_STATUS_CONFLICT` | 409 | Conflict | Conflicting request. | +| `NNG_HTTP_STATUS_GONE` | 410 | Gone | Resource no longer exists. | +| `NNG_HTTP_STATUS_LENGTH_REQUIRED` | 411 | Length Required | Missing Content-Length. | +| `NNG_HTTP_STATUS_PRECONDITION_FAILED` | 412 | Precondition Failed | | +| `NNG_HTTP_STATUS_CONTENT_TOO_LARGE` | 413 | Content Too Large | | +| `NNG_HTTP_STATUS_URI_TOO_LONG` | 414 | URI Too Long | | +| `NNG_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE` | 415 | Unsupported Media Type | +| `NNG_HTTP_STATUS_RANGE_NOT_SATISFIABLE` | 416 | Range Not Satisfiable | +| `NNG_HTTP_STATUS_EXPECTATION_FAILED` | 417 | Expectation Failed | +| `NNG_HTTP_STATUS_TEAPOT` | 418 | I Am A Teapot | RFC 2324. | +| `NNG_HTTP_STATUS_UNPROCESSABLE_ENTITY` | 422 | Unprocessable Entity | +| `NNG_HTTP_STATUS_LOCKED` | 423 | Locked | +| `NNG_HTTP_STATUS_FAILED_DEPENDENCY` | 424 | Failed Dependency | +| `NNG_HTTP_STATUS_TOO_EARLY` | 425 | Too Early | +| `NNG_HTTP_STATUS_UPGRADE_REQUIRED` | 426 | Upgrade Required | +| `NNG_HTTP_STATUS_PRECONDITION_REQUIRED` | 428 | Precondition Required | | +| `NNG_HTTP_STATUS_TOO_MANY_REQUESTS` | 429 | Too Many Requests | | +| `NNG_HTTP_STATUS_HEADERS_TOO_LARGE` | 431 | Headers Too Large | | +| `NNG_HTTP_STATUS_UNAVAIL_LEGAL_REASONS` | 451 | Unavailabe For Legal Reasons | | +| `NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR` | 500 | Internal Server Error | +| `NNG_HTTP_STATUS_NOT_IMPLEMENTED` | 501 | Not Implemented | Server does not implement method. | +| `NNG_HTTP_STATUS_BAD_GATEWAY` | 502 | Bad Gateway | +| `NNG_HTTP_STATUS_SERVICE_UNAVAILALE` | 503 | Service Unavailable | +| `NNG_HTTP_STATUS_GATEWAY_TIMEOUT` | 504 | Gateway TImeout | +| `NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP` | 505 | HTTP Version Not Supported | +| `NNG_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES` | 506 | Variant Also Negotiates | +| `NNG_HTTP_STATUS_INSUFFICIENT_STORAGE` | 507 | Variant Also Negotiates | +| `NNG_HTTP_STATUS_LOOP_DETECTED` | 508 | Loop Detected | +| `NNG_HTTP_STATUS_NOT_EXTENDED` | 510 | Not Extended | +| `NNG_HTTP_STATUS_NETWORK_AUTH_REQUIRED` | 511 | Network Authentication Required | + +### Retrieving Headers + +```c +const char *nng_http_get_header(nng_http *conn, const char *key); +bool nng_next_header(nng_http *conn, const char **keyp, const char **valuep, void **next); +``` + +The {{i:`nng_http_get_header`}} returns the header value matching _key_ that was received over _conn_, +or `NULL` if no such header exists. + +Thus, if _conn_ is a client connection, then this function returns the the header value +sent by the server as part of a response, whereas if it is a server connection, it returns +the header value sent by the client as part of the request. + +If multiple headers are present with the same key, they may be returned as a combined value, +with individual values separated by commas, but this behavior is not guaranteed. + +The {{i:`nng_http_next_header`}} function iterates over all the headers, using the same list +that `nng_http_get_header` uses. To start, it is called with _next_ initialized to `NULL`. +If a header was found, then it returns `true`, and sets _keyp_ and _valuep_ to values containing +the header name and value. It also updates _next_, which should be used for the next iteration. + +Once `nng_http_next_header` returns `false`, further calls with the same parameters will continue to do so. +The scan can be rest by setting _next_ to `NULL`. + +### Modifying Headers + +```c +int nng_http_add_header(nng_http *conn, const char *key, const char *val); +int nng_http_set_header(nng_http *conn, const char *key, const char *val); +void nng_http_del_header(nng_http *conn, const char *key); +``` + +The {{i:`nng_http_add_header`}}, {{i:`nng_http_set_header`}}, and {{i:`nng_http_del_header`}} functions are +used to add a modify either the request or response headers for _conn_ prior to sending to the connected peer on _conn_. + +Thus, if the _conn_ is a client connection created by [`nng_http_client_connect`], then the request headers are modified. +Conversely, if it is a connection created by an HTTP server and used in a callback function, then the response headers are modified. + +The `nng_http_add_header` function adds a header with the name _key_, and the value _val_, to the list of headers. +In so doing, it may bring collapse multiple headers with the same name into a comma separated list, following +the syntax specified in RFC 9110. The function may return [`NNG_ENOMEM`], [`NNG_EMSGSIZE`], or [`NNG_EINVAL`]. + +The `nng_http_set_header` function adds the header if it does not already exist, but replaces any and all previously existing +headers with the same name _key_, if they exist. In all other respects it behaves similarly to `nng_http_add_header`. + +The `nng_http_del_header` removes all headers with name _key_. + +> [!NOTE] +> Some HTTP headers have special semantics, such as the "Host", "Content-Length", and "Content-Type" headers. +> This implementation may apply those semantics, in order to conform to the specifications for HTTP, such +> as by guaranting that only a single instance of one of these headers is present. + +### Retrieving Body Content + +```c +void nng_http_get_body(nng_http_conn *conn, void **datap, size_t *sizep); +``` + +The {{i:`nng_http_get_data`}} obtains the most recently received request or +response body. This will be `NULL` if the content has not been retrieved +properly yet, or if the peer did not any content. (Some requests are defined +to never have body content, such as "HEAD".) + +### Storing Body Content + +```c +void nng_http_set_body(nng_http_conn *conn, void *data, size_t size); +void nng_http_copy_body(nng_http_conn *conn, const void *data, size_t size); +``` + +The {{i:`nng_http_set_data`}} function sets the outgoing body content to _data_, +which must be _size_ bytes long. The caller must ensure that _data_ remains +valid for the duration of the transaction. + +The {{i:`nng_http_copy_data`}} function makes a copy of _data_, which +will be freed automatically when the transaction is finished, but otherwise +behaves like `nng_http_set_data`. + +On client _conn_ objects, these functions update the request object, but on server +_conn_ objects, they update the response object. + +These functions also update the relevant "Content-Length" header. + +> [!NOTE] +> The current framework does not support sending data via chunked +> transfer-encoding. + +> [!TIP] +> It is a good idea to also set the `Content-Type` header. + +### Closing the Connection + +```c +void nng_http_close(nng_http *conn); +``` + +The {{i:`nng_http_close`}} function closes the supplied HTTP connection _conn_, +including any disposing of any underlying file descriptors or related resources. + +Once this function, no further access to the _conn_ structure may be made. + +### Reset Connection State + +```c +void nng_http_reset(nng_http *conn); +``` + +The {{i:`nng_http_reset`}} function resets the request and response state of the +the connection _conn_, so that it is just as if it had been freshly created with +[`nng_http_client_connect`] or passed into a handler function for a server callback. + +The intended purpose of this function is to clear the object state before reusing the _conn_ for +subsequent transactions. + +### Direct Read and Write + +```c +void nng_http_read(nng_http *conn, nng_aio *aio); +void nng_http_write(nng_http *conn, nng_aio *aio); +void nng_http_read_all(nng_http *conn, nng_aio *aio); +void nng_http_write_all(nng_http *conn, nng_aio *aio); +``` + +The {{i:`nng_http_read`}} and {{i:`nng_http_write`}} functions read or write data asynchronously from or to the +connection _conn_, using the [`nng_iov`] that is set in _aio_ with [`nng_aio_set_iov`]. +These functions will complete as soon as any data is transferred. +Use [`nng_aio_count`] to determine how much data was actually transferred. + +The {{i:`nng_http_read_all`}} and {{i:`nng_http_write_all`}} functions perform the same task, but will keep resubmitting +operations until the the entire amount of data requested by the [`nng_iov`] is transferred. + +> [!NOTE] +> These functions perform no special handling for chunked transfers. + +These functions are most likely to be useful after hijacking the connection with [`nng_http_hijack`]. +They can be used to transfer request or response body data as well. + +### Hijacking Connections + +```c +void nng_http_hijack(nng_http_conn *conn); +``` + +TODO: This API will change to convert the conn into a stream object. + +The {{i:`nng_http_hijack`}} function hijacks the connection _conn_, causing it +to be disassociated from the HTTP server where it was created. + +The purpose of this function is the creation of HTTP upgraders (such as +WebSocket), where the underlying HTTP connection will be taken over for +some other purpose, and should not be used any further by the server. + +This function is most useful when called from a handler function. +(See [`nng_http_handler_alloc`].) + +> [!NOTE] +> It is the responsibility of the caller to dispose of the underlying connection when it is no longer needed. +> Furthermore, the HTTP server will no longer send any responses to the hijacked connection, so the caller should do that as well if appropriate. +> (See [`nng_http_write_response`].) + +> [!TIP] +> This function is intended to facilitate uses cases that involve changing the protocol from HTTP, such as WebSocket. +> Most applications will never need to use this function. + +## Client API + +The NNG client API consists of an API for creating connections, and an API for performing +transactions on those connections. + +### Client Object + +```c +typedef struct nng_http_client nng_http_client; +``` + +The {{i:`nng_http_client`}} object is the client side creator for [`nng_http`] objects. +It is analogous to a [dialer] object used elsewhere in NNG, but it specifically is only for HTTP. + +### Create a Client + +```c +void nng_http_client_alloc(nng_http_client *clientp, const nng_url *url); +``` + +The {{i:`nng_http_client_alloc`}} allocates an HTTP client suitable for +connecting to the server identified by _url_ and stores a pointer to +it in the location referenced by _clientp_. + +### Destroy a Client + +```c +void nng_http_client_free(nng_http_client *client); +``` + +The {{i:`nng_http_client_free`}} connection destroys the client object and any +of its resources. + +> [!NOTE] +> Any connections created by [`nng_http_client_connect`] are not affected by this function, +> and must be closed explicitly as needed. + +### Client TLS + +```c +int nng_http_client_get_tls(nng_http_client *client, nng_tls_config **tlsp); +int nng_http_client_set_tls(nng_http_client *client, nng_tls_config *tls); +``` + +The {{i:`nng_http_client_get_tls`}} and {{i:`nng_http_client_set_tls`}} functions are used to +retrieve or change the [TLS configuration][`nng_tls_config`] used when making outbound connections, enabling +{{i:TLS}} as a result. + +If TLS has not been previously configured on _client_, then `nng_http_client_get_tls` will return [`NNG_EINVAL`]. +Both functions will return [`NNG_ENOTSUP`] if either HTTP or TLS is not supported. + +Calling `nng_http_client_set_tls` invalidates any client previously obtained with +`nng_http_client_get_tls`, unless a separate hold on the object was obtained. + +Once TLS is enabled for an `nng_http_client`, it is not possible to disable TLS. + +> [!NOTE] +> The TLS configuration itself cannnot be changed once it has been used to create a connection, +> such as by calling [`nng_http_client_connect`], but a new one can be installed in the client. +> Existing connections will use the TLS configuration that there were created with. + +### Creating Connections + +```c +#include + +void nng_http_client_connect(nng_http_client *client, nng_aio *aio); +``` + +The {{i:`nng_http_client_connect`}} function makes an outgoing connection to the +server configured for _client_, and creates an [`nng_http`] object for the connection. + +This is done asynchronously, and when the operation succeseds the connection may be +retried from the _aio_ using [`nng_aio_get_output`] with index 0. + +#### Example 1: Connecting to Google + +```c +nng_aio *aio; +nng_url *url; +nng_http_client *client; +nng_http *conn; +int rv; + +// Error checks elided for clarity. +nng_url_parse(&url, "http://www.google.com"); +nng_aio_alloc(&aio, NULL, NULL); +nng_http_client_alloc(&client, url); + +nng_http_client_connect(client, aio); + +// Wait for connection to establish (or attempt to fail). +nng_aio_wait(aio); + +if ((rv = nng_aio_result(aio)) != 0) { + printf("Connection failed: %s\n", nng_strerror(rv)); +} else { + // Connection established, get it. + conn = nng_aio_get_output(aio, 0); + + // ... do something with it here + + // Close the connection when done to avoid leaking it. + nng_http_close(conn); +} +``` + +### Preparing a Transaction + +```c +int nng_http_set_version(nng_http *conn, const char *version); +int nng_http_set_uri(nng_http *conn, const char *uri); +``` + +The {{i:`nng_http_set_uri`}} function provides a URI for the transaction. This will be used to +set the URI for the request. The URI typically appears like a path, starting with "/", although +it may also contain a query string. + +### Request Body + +### Sending the Request + +```c +void nng_http_write_request(nng_http *conn, nng_aio *aio); +``` + +The {{i:`nng_http_write_request`}} function starts an asynchronous write of +the HTTP request associated with _conn_. +The entire request is sent, +including headers, and if present, the request body data. +(The request body can be set with +[`nng_http_set_data`] or [`nng_http_copy_data`].) + +This function returns immediately, with no return value. +Completion of the operation is signaled via the _aio_, and the final result +may be obtained via [`nng_aio_result`]. + +> [!TIP] +> Consider using the [`nng_http_transact`] function, +> which provides a simpler interface for performing a complete HTTP client transaction. + +## Obtaining the Response + +```c +void nng_http_read_response(nng_http *conn, nng_aio *aio); +``` + +The {{i:`nng_http_read_response`}} function starts an asynchronous read from the +HTTP connection _conn_, reading an HTTP response into the response associated with _conn_, including all +of the related headers. + +It does _not_ transfer any response body. To do that, use [`nng_http_read_all`] or [`nng_http_read`]. + +> [!NOTE] +> At this time we have no API support for reading chunked transfers directly. Applications that +> need to do so may use the direct read functions. + +> [!TIP] +> An easier one-shot method for many use cases might be [`nng_http_transact`]. + +### Submitting the Transaction + +```c +int nng_http_transact(nng_http *conn, nng_aio *aio); +``` + +The HTTP request is issued, and the response processed, asynchronously by the {{i:`nng_http_transact`}} function. +When the function is complete, the _aio_ will be notified. + +The {{i:`nng_http_transact`}} function is used to perform a complete +HTTP exchange over the connection _conn_, sending the request +and attached body data to the remote server, and reading the response. + +The entire response is read, including any associated body, which can +subsequently be obtained using [`nng_http_get_data`]. + +This function is intended to make creation of client applications easier, +by performing multiple asynchronous operations required to complete an +entire HTTP transaction. + +If an error occurs, the caller should close _conn_ with [`nng_http_close`], as it may not +necessarily be usable with other transactions. + +> [!WARNING] +> If the remote server tries to send an extremely large buffer, +> then a corresponding allocation will be made, which can lead to denial +> of service attacks. +> Client applications should take care to use this only with reasonably +> trust-worthy servers. + +> [!NOTE] +> A given connection _conn_ should be used with only one +> operation or transaction at a time as HTTP/1.1 has no support for +> request interleaving. + +This function returns immediately, with no return value. +Completion of the operation is signaled via the _aio_, and the final result +may be obtained via [`nng_aio_result()`]. + +### Response Body + +## Server API + +### Handlers + +### Sending the Response + +```c +void nng_http_write_response(nng_http *conn, nng_aio *aio); +``` + +Normally the server will send any attached response, but there are circumstances where +a response must be sent manually, such as when [hijacking][`nng_http_hijack`] a connection. + +In such a case, {{i:`nng_http_write_response`}} can be called, which will send the response and any attached data, asynchronously +using the [`nng_aio`] _aio_. + +By default, for `HTTP/1.1` connections, the connection is kept open, and +will be reused to receive new requests. For `HTTP/1.0`, or if the client has requested +explicitly by setting the "Connection: close" header, the connection will be closed after the +response is fully sent. + +{{#include ../xref.md}} diff --git a/docs/ref/api/index.md b/docs/ref/api/index.md index c154ce400..77cbfca6a 100644 --- a/docs/ref/api/index.md +++ b/docs/ref/api/index.md @@ -25,6 +25,7 @@ include the `nng/nng.h` header file like so: - [Threads](thr.md) - [Logging](logging.md) - [Statistics](stats.md) +- [HTTP](http.md) - [Miscellaneous](misc.md) - [Errors](errors.md) - [ID Map](id_map.md) diff --git a/docs/ref/migrate/nng1.md b/docs/ref/migrate/nng1.md index c203b790f..cc3e76b98 100644 --- a/docs/ref/migrate/nng1.md +++ b/docs/ref/migrate/nng1.md @@ -127,11 +127,6 @@ can be simply removed from your application: Additionally, the header files containing these functions have been removed, such as `nng/transport/ipc/ipc.h`. Simply remove `#include` references to those files. -The `NNG_OPT_WSS_REQUEST_HEADERS` and `NNG_OPT_WSS_RESPONSE_HEADERS` aliases for -`NNG_OPT_WS_OPT_WS_REQUEST_HEADERS` and `NNG_OPT_WS_RESPONSE_HEADERS` have been removed. -Just convert any use of them to `NNG_OPT_WS_REQUEST_HEADERS` or -`NNG_OPT_WS_RESPONSE_HEADERS` as appropriate. - ## TLS Configuration The support for configuring TLS via `NNG_OPT_TLS_CONFIG`, `NNG_TLS_AUTH_MODE`, `NNG_OPT_TLS_CA_FILE`, @@ -332,6 +327,9 @@ accessors functions are provided: ## HTTP API +The entire HTTP API has been refactored and should be much simpler to use and more efficient. +Applications directly using the HTTP API will need to be fully modified. + A few limits on string lengths of certain values are now applied, which allows us to preallocate values and eliminate certain unreasonable error paths. If values longer than these are supplied in certain APIs they may be silently truncated to the limit: @@ -356,6 +354,19 @@ They may silently truncate data. The HTTP handler objects may not be modified once in use. Previously this would fail with `NNG_EBUSY`. These checks are removed now, but debug builds will assert if an application tries to do so. +## WebSocket API + +The `NNG_OPT_WSS_REQUEST_HEADERS`, `NNG_OPT_WSS_RESPONSE_HEADERS` and +`NNG_OPT_WS_OPT_WS_REQUEST_HEADERS`, `NNG_OPT_WS_RESPONSE_HEADERS` have been removed. + +The `NNG_OPT_WS_REQUEST_HEADER` and `NNG_OPT_WS_RESPONSE_HEADER` option prefixes have been +collapsed into just `NNG_OPT_WS_HEADER`, with slightly different semantics. It still is +a prefix (append the name of the header of interest), but setting it can only affect +outbound headers (request header for dialers, response header for listeners), and when +reading it on a pipe, the value returned is the header sent by the remote peer. + +The undocumented hook function signature has changed to reflect changes in the HTTP API. + ## Security Descriptors (Windows Only) The `NNG_OPT_IPC_SECURITY_DESCRIPTOR` option is removed, and replaced diff --git a/docs/ref/xref.md b/docs/ref/xref.md index 85c9f2f6f..bee853ff7 100644 --- a/docs/ref/xref.md +++ b/docs/ref/xref.md @@ -243,6 +243,44 @@ [`nng_sockaddr_inproc`]: /TODO.md [`nng_sockaddr_abstract`]: /TODO.md + + +[`nng_http_client`]: /api/http.md#client-object +[`nng_http`]: /api/http.md#connection-object +[`nng_http_client_alloc`]: /api/http.md#create-a-client +[`nng_http_client_free`]: /api/http.md#destroy-a-client +[`nng_http_client_connect`]: /api/http.md#creating-connections +[`nng_http_client_set_tls`]: /api/http.md#client-tls +[`nng_http_client_get_tls`]: /api/http.md#client-tls +[`nng_http_close`]: /api/http.md#closing-the-connection +[`nng_http_reset`]: /api/http.md#reset-connection-state +[`nng_http_get_version`]: /api/http.md#http-protocol-versions +[`nng_http_set_version`]: /api/http.md#http-protocol-versions +[`nng_http_get_method`]: /api/http.md#http-method +[`nng_http_set_method`]: /api/http.md#http-method +[`nng_http_set_url`]: /api/http.md#preparing-a-transaction +[`nng_http_get_reason`]: /api/http.md#http-status +[`nng_http_get_status`]: /api/http.md#http-status +[`nng_http_set_status`]: /api/http.md#http-status +[`nng_http_get_url`]: /TODO.md +[`nng_http_hijack`]: /api/http.md#hijacking-connections +[`nng_http_get_header`]: /api/http.md#retrieving-headers +[`nng_http_next_header`]: /api/http.md#retrieving-headers +[`nng_http_add_header`]: /api/http.md#modifying-headers +[`nng_http_set_header`]: /api/http.md#modifying-headers +[`nng_http_del_header`]: /api/http.md#modifying-headers +[`nng_http_set_response_body`]: /TODO.md +[`nng_http_get_response_body`]: /TODO.md +[`nng_http_read_response_body`]: /TODO.md +[`nng_http_read_request_body`]: /TODO.md +[`nng_http_server_set_error`]: /TODO.md +[`nng_http_server_set_redirect`]: /TODO.md +[`nng_http_read`]: /api/http.md#direct-read-and-write +[`nng_http_read`]: /api/http.md#direct-read-and-write +[`nng_http_read_all`]: /api/http.md#direct-read-and-write +[`nng_http_write`]: /api/http.md#direct-read-and-write +[`nng_http_write_all`]: /api/http.md#direct-read-and-write + [`NNG_EINTR`]: /api/errors.md#NNG_EINTR diff --git a/include/nng/supplemental/http/http.h b/include/nng/http.h similarity index 62% rename from include/nng/supplemental/http/http.h rename to include/nng/http.h index 344dbbe0f..ec29e56ef 100644 --- a/include/nng/supplemental/http/http.h +++ b/include/nng/http.h @@ -9,8 +9,8 @@ // found online at https://opensource.org/licenses/MIT. // -#ifndef NNG_SUPPLEMENTAL_HTTP_HTTP_H -#define NNG_SUPPLEMENTAL_HTTP_HTTP_H +#ifndef NNG_HTTP_H +#define NNG_HTTP_H // HTTP API. Only present if HTTP support compiled into the library. // Functions will return NNG_ENOTSUP (or NULL or 0 as appropriate) @@ -60,8 +60,8 @@ enum nng_http_status { NNG_HTTP_STATUS_GONE = 410, NNG_HTTP_STATUS_LENGTH_REQUIRED = 411, NNG_HTTP_STATUS_PRECONDITION_FAILED = 412, - NNG_HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, - NNG_HTTP_STATUS_ENTITY_TOO_LONG = 414, + NNG_HTTP_STATUS_CONTENT_TOO_LARGE = 413, + NNG_HTTP_STATUS_URI_TOO_LONG = 414, NNG_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, NNG_HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, NNG_HTTP_STATUS_EXPECTATION_FAILED = 417, @@ -69,6 +69,7 @@ enum nng_http_status { NNG_HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, NNG_HTTP_STATUS_LOCKED = 423, NNG_HTTP_STATUS_FAILED_DEPENDENCY = 424, + NNG_HTTP_STATUS_TOO_EARLY = 425, NNG_HTTP_STATUS_UPGRADE_REQUIRED = 426, NNG_HTTP_STATUS_PRECONDITION_REQUIRED = 428, NNG_HTTP_STATUS_TOO_MANY_REQUESTS = 429, @@ -95,208 +96,124 @@ enum nng_http_status { // nng_http_req represents an HTTP request. typedef struct nng_http_req nng_http_req; -// nng_http_req_alloc creates a vanilla HTTP request object. The object is -// initialized with the given URL object for an HTTP/1.1 GET request by -// default. It also adds the Host: header required for HTTP/1.1. If the -// url is NULL, then the uri and Host: header are uninitialized, and will -// need to be set explicitly. -NNG_DECL int nng_http_req_alloc(nng_http_req **, const nng_url *); - -// nng_http_req_free frees an HTTP request object. -NNG_DECL void nng_http_req_free(nng_http_req *); - -// nng_http_req_get_method returns the method. -NNG_DECL const char *nng_http_req_get_method(const nng_http_req *); - -// nng_http_req_get_version returns the version, usually HTTP/1.1. -NNG_DECL const char *nng_http_req_get_version(const nng_http_req *); - -// nng_http_req_get_uri returns the "abs-uri", which is URL without -// the scheme, host, or port. -NNG_DECL const char *nng_http_req_get_uri(const nng_http_req *); - -// nng_http_req_set_header sets an HTTP header, replacing any previous value -// that might have been present. -NNG_DECL int nng_http_req_set_header( - nng_http_req *, const char *, const char *); - -// nng_http_req_add_header adds an HTTP header, without disrupting any other -// with the same name that might have been present. -NNG_DECL int nng_http_req_add_header( - nng_http_req *, const char *, const char *); - -// nng_http_req_del_header deletes all occurrences of a named header. -NNG_DECL int nng_http_req_del_header(nng_http_req *, const char *); - -// nng_http_req_get_header looks up a header with the named, returns NULL -// if not found. -NNG_DECL const char *nng_http_req_get_header( - const nng_http_req *, const char *); - -// nng_http_req_set_method is used to change the method of a request. -// The method should be an upper case HTTP method, like POST, or DELETE. -// Null sets the default ("GET"). -NNG_DECL void nng_http_req_set_method(nng_http_req *, const char *); - -// nng_http_req_set_version is used to change the version of a request. -// Normally the version is "HTTP/1.1". Note that the framework does -// not support HTTP/2 at all. Null sets the default ("HTTP/1.1"). -NNG_DECL int nng_http_req_set_version(nng_http_req *, const char *); - -// nng_http_req_set_url is used to change the URL of a request. -NNG_DECL int nng_http_req_set_url(nng_http_req *, const nng_url *); - -// nng_http_req_set_uri is used to change the URI of a request. This -// should be an "abs-uri", that is a path, plus query and fragment if -// needed. The scheme, host, and port don't belong here. The URI should -// start with a leading '/' per HTTP. -NNG_DECL int nng_http_req_set_uri(nng_http_req *, const char *); - -// nng_http_req_set_data adds entity data to the request. The -// data object must persist (so only really useful for static data). -// The content-length header is updated as well, but the caller should -// probably set the content-type header. -NNG_DECL int nng_http_req_set_data(nng_http_req *, const void *, size_t); - -// nng_http_req_copy_data adds entity data to the response. A private -// copy of the data is made (will be freed with the request). -// The content-length header is updated as well, but the caller should -// probably set the content-type header. -NNG_DECL int nng_http_req_copy_data(nng_http_req *, const void *, size_t); - -// nng_http_req_get_data gets the data for the response. -NNG_DECL void nng_http_req_get_data(nng_http_req *, void **, size_t *); - // nng_http_res represents an HTTP response. typedef struct nng_http_res nng_http_res; -// nng_http_res_alloc creates a vanilla HTTP response object. The object is -// initialized for an HTTP/1.1 200 OK response by default. -NNG_DECL int nng_http_res_alloc(nng_http_res **); - -// nng_http_res_alloc_error creates an error HTTP response object. The object -// is initialized for an HTTP/1.1 response, and contains an associated -// generic HTML error page. -NNG_DECL int nng_http_res_alloc_error(nng_http_res **, uint16_t); - -// nng_http_res_free frees an HTTP response object. -NNG_DECL void nng_http_res_free(nng_http_res *); - -// nng_http_res_get_status returns the HTTP status code from the server. -NNG_DECL uint16_t nng_http_res_get_status(const nng_http_res *); +// An nng_http represents an underlying "connection". It may be +// a TCP channel, or a TLS channel, but the main thing is that this is +// normally only used for exchanging HTTP requests and responses. +typedef struct nng_http_conn nng_http; -// nng_http_res_set_status sets the HTTP status code. -NNG_DECL void nng_http_res_set_status(nng_http_res *, uint16_t); +// These methods obtain a pointer to the request or response structure +// that is embedded in the conn structure. +NNG_DECL nng_http_res *nng_http_conn_res(nng_http *); -// nng_http_res_get_reason returns the human readable status message -// that the server responds (or responded) with. -NNG_DECL const char *nng_http_res_get_reason(const nng_http_res *); +// nng_http_close closes the underlying channel. Applications should +// not use this channel after this operation is performed. +NNG_DECL void nng_http_close(nng_http *); -// nng_http_res_set_reason sets the human readable status message. -// NULL means that a default reason is used based on the status code. -NNG_DECL int nng_http_res_set_reason(nng_http_res *, const char *); +// nng_http_read attempts to read data from the connection. This +// completes as soon as at least one byte is read; it does not wait +// for the entire aio to be filled. +NNG_DECL void nng_http_read(nng_http *, nng_aio *); -// nng_http_res_set_header sets an HTTP header, replacing any previous value -// that might have been present. -NNG_DECL int nng_http_res_set_header( - nng_http_res *, const char *, const char *); +// nng_http_read_all is like nng_http_read, but it does not +// finish until either all the requested data is read, or an error occurs. +NNG_DECL void nng_http_read_all(nng_http *, nng_aio *); -// nng_http_res_add_header adds an HTTP header, without disrupting any other -// with the same name that might have been present. -NNG_DECL int nng_http_res_add_header( - nng_http_res *, const char *, const char *); +// nng_http_write attempts to write data, but it can write less +// than the amount requested. (It completes as soon as at least one +// byte is written.) +NNG_DECL void nng_http_write(nng_http *, nng_aio *); -// nng_http_res_del_header deletes all occurrences of a named header. -NNG_DECL int nng_http_res_del_header(nng_http_res *, const char *); +// nng_http_write_all is like nng_http_write, but it does not +// finish until either all the requested data is written, or an error occurs. +NNG_DECL void nng_http_write_all(nng_http *, nng_aio *); -// nng_http_res_get_header looks up a header with the named, returns NULL -// if not found. -NNG_DECL const char *nng_http_res_get_header( - const nng_http_res *, const char *); +// nng_http_write_request writes the entire request. It will also write +// any data that has been attached. +NNG_DECL void nng_http_write_request(nng_http *, nng_aio *); -// nng_http_res_set_version is used to change the version of a response. -// Normally the version is "HTTP/1.1". Note that the framework does -// not support HTTP/2 at all. NULL sets the default ("HTTP/1.1"). -NNG_DECL int nng_http_res_set_version(nng_http_res *, const char *); +// nng_http_write_response writes the entire response. It will also write +// any data that has been attached. It uses the res object in the conn. +NNG_DECL void nng_http_write_response(nng_http *, nng_aio *); -// nng_http_res_get_version returns the version, usually HTTP/1.1. -NNG_DECL const char *nng_http_res_get_version(const nng_http_res *); +// nng_http_read_response reads an entire response, EXCEPT for any entity +// data. The caller is responsible for processing the headers in the response +// and reading any submitted entity data itself. +NNG_DECL void nng_http_read_response(nng_http *, nng_aio *); -// nng_http_res_get_data gets the data for the response. -NNG_DECL void nng_http_res_get_data(nng_http_res *, void **, size_t *); +// nng_http_reset resets the transaction (including headers, URI, etc.) +// and the response. It should be used when reusing the connection. +NNG_DECL void nng_http_reset(nng_http *); -// nng_http_res_set_data adds entity data to the response. The -// data object must persist (so only really useful for static data). -// The content-length header is updated as well, but the caller should -// probably set the content-type header. -NNG_DECL int nng_http_res_set_data(nng_http_res *, const void *, size_t); +// nng_http_set_uri sets the URI associated with the request. It can +// include an optional query string, either inline in the URI to start, +// or as a separate argument. If the query string already exists +// and one is also supplied here, it will be appended (separated with &). +NNG_DECL int nng_http_set_uri(nng_http *, const char *, const char *); -// nng_http_res_copy_data adds entity data to the response. A private -// copy of the data is made (will be freed with the request). -// The content-length header is updated as well, but the caller should -// probably set the content-type header. -NNG_DECL int nng_http_res_copy_data(nng_http_res *, const void *, size_t); +// nng_http_get_uri returns the URI. It will be NULL if not set. +NNG_DECL const char *nng_http_get_uri(nng_http *); -// An nng_http_conn represents an underlying "connection". It may be -// a TCP channel, or a TLS channel, but the main thing is that this is -// normally only used for exchanging HTTP requests and responses. -typedef struct nng_http_conn nng_http_conn; +// nng_http_get_status gets the status of the last transaction +NNG_DECL uint16_t nng_http_get_status(nng_http *); -// These methods obtain a pointer to the request or response structure -// that is embedded in the conn structure. -NNG_DECL nng_http_req *nng_http_conn_req(nng_http_conn *); -NNG_DECL nng_http_res *nng_http_conn_res(nng_http_conn *); +// nng_http_reason gets the message associated with status of the last +// transaction +NNG_DECL const char *nng_http_get_reason(nng_http *); -// nng_http_conn_close closes the underlying channel. Applications should -// not use this channel after this operation is performed. -NNG_DECL void nng_http_conn_close(nng_http_conn *); +// nng_http_set_status sets the status for the transaction (server API), +// and also sets the reason (message) for it. (If NULL is used for the reason, +// then a builtin value is used based on the code.) +NNG_DECL int nng_http_set_status(nng_http *, uint16_t, const char *); -// nng_http_conn_read attempts to read data from the connection. This -// completes as soon as at least one byte is read; it does not wait -// for the entire aio to be filled. -NNG_DECL void nng_http_conn_read(nng_http_conn *, nng_aio *); +// nng_http_set_version is used to change the version of a request. +// Normally the version is "HTTP/1.1". Note that the framework does +// not support HTTP/2 at all. Null sets the default ("HTTP/1.1"). +NNG_DECL int nng_http_set_version(nng_http *, const char *); -// nng_http_conn_read_all is like nng_http_conn_read, but it does not -// finish until either all the requested data is read, or an error occurs. -NNG_DECL void nng_http_conn_read_all(nng_http_conn *, nng_aio *); +// nng_http_get_version is used to get the version of a request. +NNG_DECL const char *nng_http_get_version(nng_http *); -// nng_http_conn_write attempts to write data, but it can write less -// than the amount requested. (It completes as soon as at least one -// byte is written.) -NNG_DECL void nng_http_conn_write(nng_http_conn *, nng_aio *); +// nng_http_set_method is used to change the method of a request. +// The method should be an upper case HTTP method, like POST, or DELETE. +// Null sets the default ("GET"). +NNG_DECL void nng_http_set_method(nng_http *, const char *); -// nng_http_conn_write_all is like nng_http_conn_write, but it does not -// finish until either all the requested data is written, or an error occurs. -NNG_DECL void nng_http_conn_write_all(nng_http_conn *, nng_aio *); +// nng_http_get_method returns the method. +NNG_DECL const char *nng_http_get_method(nng_http *); -// nng_http_conn_write_req writes the entire request. It will also write any -// data that has been attached. -NNG_DECL void nng_http_conn_write_req( - nng_http_conn *, nng_http_req *, nng_aio *); +// These functions set (replacing any existing), or add (appending) +// a header to either the request or response. Clients modify the request +// headers, and servers (and callbacks on the server) modify response headers. +// These can return NNG_ENOMEM, NNG_MSGSIZE, etc. +NNG_DECL int nng_http_set_header(nng_http *, const char *, const char *); +NNG_DECL int nng_http_add_header(nng_http *, const char *, const char *); -// nng_http_conn_write_res writes the entire response. It will also write any -// data that has been attached. It uses the res object in the conn. -NNG_DECL void nng_http_conn_write_res(nng_http_conn *, nng_aio *); +// nng_http_del_header removes all of the headers for the given header. +// For clients this is done on the request headers, for servers its the +// response headers. +NNG_DECL void nng_http_del_header(nng_http *, const char *); -// nng_http_conn_read_req reads an entire request, EXCEPT for any entity -// data. The caller is responsible for processing the headers in the request -// and reading any submitted entity data itself. -NNG_DECL void nng_http_conn_read_req(nng_http_conn *, nng_aio *); +// nng_http_get_header returns the value of the given header. For clients, +// it gets the response header, but for servers it gets the request header. +// It returns NULL if no matching header can be found. +NNG_DECL const char *nng_http_get_header(nng_http *, const char *); -// nng_http_conn_read_res reads an entire response, EXCEPT for any entity -// data. The caller is responsible for processing the headers in the response -// and reading any submitted entity data itself. -NNG_DECL void nng_http_conn_read_res( - nng_http_conn *, nng_http_res *, nng_aio *); +// nng_http_get_body returns the body sent by the peer, if one is attached. +NNG_DECL void nng_http_get_body(nng_http *, void **, size_t *); -// nng_http_req_reset resets the request to an initially allocated state. -NNG_DECL void nng_http_req_reset(nng_http_req *); +// nng_http_set_body sets the body to send out in the next exchange. +NNG_DECL void nng_http_set_body(nng_http *, void *, size_t); -// nng_http_res_reset resets the response to an initially allocated state. -NNG_DECL void nng_http_res_reset(nng_http_res *); +// nng_http_copy_body sets the body to send out in the next exchange, but +// makes a local copy. It can fail due to NNG_ENOMEM. +NNG_DECL int nng_http_copy_body(nng_http *, const void *, size_t); // nng_http_handler is a handler used on the server side to handle HTTP // requests coming into a specific URL. +// typedef struct nng_http_handler nng_http_handler; // nng_http_handler_alloc creates a server handler object, for the supplied @@ -308,18 +225,15 @@ typedef struct nng_http_handler nng_http_handler; // is registered with the server, and that a handler can only be registered // once per server. // -// The callback function should obtain the request (if needed), and -// the response from the connection object using nng_http_conn_req -// and nng_http_conn_res. If the connection is hijacked, then the -// response object will not be used, otherwise the server will send it on -// behalf of the client. +// If the connection is hijacked, then the server will not send any response, +// otherwise it does. // // The callback should complete with a result of 0 in most circumstances. // If it completes with an error, then the connection is terminated, after // possibly sending a 500 error response to the client. The callback signals // completion by nng_aio_finish. The second argument to this function is the // handler data that was optionally set by nng_handler_set_data. -typedef void (*nng_http_handler_func)(nng_http_conn *, void *, nng_aio *); +typedef void (*nng_http_handler_func)(nng_http *, void *, nng_aio *); NNG_DECL int nng_http_handler_alloc( nng_http_handler **, const char *, nng_http_handler_func); @@ -462,11 +376,7 @@ NNG_DECL int nng_http_server_get_addr(nng_http_server *, nng_sockaddr *); // nng_http_server_set_error_page sets a custom error page (HTML) content // to be sent for the given error code. This is used when the error is -// generated internally by the framework, or when the application returns -// the response back to the server via the handler's aio, and the response -// was allocated with nng_http_res_alloc_error. If the response was not -// allocated this way, or the application writes the response itself instead -// of letting the server do so, then this setting will be ignored. +// generated internally by the framework. NNG_DECL int nng_http_server_set_error_page( nng_http_server *, uint16_t, const char *); @@ -480,13 +390,13 @@ NNG_DECL int nng_http_server_set_error_file( // nng_http_server_res_error takes replaces the body of the response with // a custom error page previously set for the server, using the status // of the response. The response must have the status set first using -// nng_http_res_set_status or implicitly via nng_http_res_alloc_error. -NNG_DECL int nng_http_server_res_error(nng_http_server *, nng_http_res *); +// nng_http_res_set_status. +NNG_DECL int nng_http_server_error(nng_http_server *, nng_http *); // nng_http_hijack is intended to be called by a handler that wishes to // take over the processing of the HTTP session -- usually to change protocols // (such as in the case of websocket). The caller is responsible for the -// final disposal of the associated nng_http_conn. Also, this completely +// final disposal of the associated nng_http. Also, this completely // disassociates the http session from the server, so the server may be // stopped or destroyed without affecting the hijacked session. Note also // that the hijacker will need to issue any HTTP reply itself. Finally, @@ -494,7 +404,7 @@ NNG_DECL int nng_http_server_res_error(nng_http_server *, nng_http_res *); // of the request structure. (Some hijackers may keep the request for // further processing.) -NNG_DECL int nng_http_hijack(nng_http_conn *); +NNG_DECL int nng_http_hijack(nng_http *); // nng_http_client represents a "client" object. Clients can be used // to create HTTP connections. At present, connections are not cached @@ -522,24 +432,18 @@ NNG_DECL int nng_http_client_get_tls(nng_http_client *, nng_tls_config **); // nng_http_client_connect establishes a new connection with the server // named in the URL used when the client was created. Once the connection -// is established, the associated nng_http_conn object pointer is returned +// is established, the associated nng_http object pointer is returned // in the first (index 0) output for the aio. NNG_DECL void nng_http_client_connect(nng_http_client *, nng_aio *); -// nng_http_conn_transact is used to perform a round-trip exchange (i.e. a +// nng_http_transact is used to perform a round-trip exchange (i.e. a // single HTTP transaction). It will not automatically close the connection, // unless some kind of significant error occurs. The caller should close // the connection if the aio does not complete successfully. -NNG_DECL void nng_http_conn_transact(nng_http_conn *, nng_aio *); - -// nng_http_client_transact is used to execute a single transaction to a -// server. The connection is opened, and will be closed when the transaction is -// complete. -NNG_DECL void nng_http_client_transact( - nng_http_client *, nng_http_req *, nng_http_res *, nng_aio *); +NNG_DECL void nng_http_transact(nng_http *, nng_aio *); #ifdef __cplusplus } #endif -#endif // NNG_H +#endif // NNG_HTTP_H diff --git a/include/nng/nng.h b/include/nng/nng.h index 5a9f5dbc7..6f01363ff 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -809,23 +809,12 @@ NNG_DECL nng_listener nng_pipe_listener(nng_pipe); // WebSocket Options. -// NNG_OPT_WS_REQUEST_HEADERS is a string containing the -// request headers, formatted as CRLF terminated lines. -#define NNG_OPT_WS_REQUEST_HEADERS "ws:request-headers" - -// NNG_OPT_WS_RESPONSE_HEADERS is a string containing the -// response headers, formatted as CRLF terminated lines. -#define NNG_OPT_WS_RESPONSE_HEADERS "ws:response-headers" - -// NNG_OPT_WS_REQUEST_HEADER is a prefix, for a dynamic -// property name. This allows direct access to any named header. -// Concatenate this with the name of the property (case is not sensitive). -// Only the first such header is returned. -#define NNG_OPT_WS_RESPONSE_HEADER "ws:response-header:" - -// NNG_OPT_WS_RESPONSE_HEADER is like NNG_OPT_REQUEST_HEADER, but used for -// accessing the request headers. -#define NNG_OPT_WS_REQUEST_HEADER "ws:request-header:" +// NNG_OPT_WS_HEADER is a prefix, for a dynamic property name. +// This allows direct access to any named header to set a header on +// a dialer or listener. This property can be used to set headers +// on outgoing dialer or listeners, and can be used to return the +// headers from the peer on a pipe. +#define NNG_OPT_WS_HEADER "ws:header:" // NNG_OPT_WS_REQUEST_URI is used to obtain the URI sent by the client. // This can be useful when a handler supports an entire directory tree. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index be3d36059..3cf64f94a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ nng_sources(nng.c nng_legacy.c) nng_headers(nng/args.h) nng_headers(nng/nng.h) +nng_headers(nng/http.h) target_include_directories(nng PRIVATE ${PROJECT_SOURCE_DIR}/src) target_include_directories(nng_testing PRIVATE ${PROJECT_SOURCE_DIR}/src) diff --git a/src/sp/transport/ws/ws_test.c b/src/sp/transport/ws/ws_test.c index 5d6215e6f..98856d4f0 100644 --- a/src/sp/transport/ws/ws_test.c +++ b/src/sp/transport/ws/ws_test.c @@ -231,17 +231,6 @@ check_props_v4(nng_msg *msg) NUTS_PASS(nng_pipe_get_bool(p, NNG_OPT_TCP_NODELAY, &b)); NUTS_TRUE(b); // default - - // Request Header - char *buf = NULL; - NUTS_PASS(nng_pipe_get_string(p, NNG_OPT_WS_REQUEST_HEADERS, &buf)); - NUTS_TRUE(strstr(buf, "Sec-WebSocket-Key") != NULL); - nng_strfree(buf); - - // Response Header - NUTS_PASS(nng_pipe_get_string(p, NNG_OPT_WS_RESPONSE_HEADERS, &buf)); - NUTS_TRUE(strstr(buf, "Sec-WebSocket-Accept") != NULL); - nng_strfree(buf); } void diff --git a/src/supplemental/http/CMakeLists.txt b/src/supplemental/http/CMakeLists.txt index 0e4cc8086..31a544a9f 100644 --- a/src/supplemental/http/CMakeLists.txt +++ b/src/supplemental/http/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2020 Staysail Systems, Inc. +# Copyright 2025 Staysail Systems, Inc. # Copyright 2018 Capitar IT Group BV # # This software is supplied under the terms of the MIT License, a @@ -15,7 +15,6 @@ endif() mark_as_advanced(NNG_ENABLE_HTTP) nng_sources(http_public.c http_api.h) -nng_headers(nng/supplemental/http/http.h) nng_defines_if(NNG_SUPP_HTTP NNG_SUPP_HTTP) nng_sources_if(NNG_SUPP_HTTP diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 1630198dd..b2b07b992 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -13,7 +13,9 @@ #define NNG_SUPPLEMENTAL_HTTP_HTTP_API_H #include "core/nng_impl.h" -#include +#include "nng/http.h" + +#include "http_msg.h" // This represents the "internal" HTTP API. It should not be used // or exposed to applications directly. @@ -32,21 +34,15 @@ typedef struct nng_http_chunks nni_http_chunks; // These functions are private to the internal framework, and really should // not be used elsewhere. -extern const char *nni_http_reason(uint16_t); - -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_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_res *, void **, size_t *); -extern int nni_http_res_parse(nni_http_res *, void *, size_t, size_t *); -extern void nni_http_res_get_data(nni_http_res *, void **, size_t *); -extern char *nni_http_res_headers(nni_http_res *); +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 // API. We can change that later. @@ -99,12 +95,12 @@ extern void *nni_http_conn_get_ctx(nni_http_conn *); // These initialization functions create stream for HTTP transactions. // They should only be used by the server or client HTTP implementations, // and are not for use by other code. -extern int nni_http_conn_init(nni_http_conn **, nng_stream *); +extern int nni_http_conn_init(nng_http **, nng_stream *, bool); -extern void nni_http_conn_close(nni_http_conn *); +extern void nni_http_conn_close(nng_http *); extern void nni_http_conn_fini(nni_http_conn *); extern int nni_http_conn_getopt( - nni_http_conn *, const char *, void *, size_t *, nni_type); + nng_http *, const char *, void *, size_t *, nni_type); // Reading messages -- the caller must supply a preinitialized (but otherwise // idle) message. We recommend the caller store this in the aio's user data. @@ -112,61 +108,40 @@ extern int nni_http_conn_getopt( // must not use them for any other purpose. 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_read_res(nni_http_conn *, nni_http_res *, nni_aio *); +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 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_req_copy_data(nni_http_req *, const void *, size_t); -extern int nni_http_res_copy_data(nni_http_res *, const void *, size_t); -extern int nni_http_req_set_data(nni_http_req *, const void *, size_t); -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 const char *nni_http_req_get_method(const nni_http_req *); -extern const char *nni_http_req_get_version(const nni_http_req *); -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 *); -extern int nni_http_res_set_version(nni_http_res *, const char *); -extern const char *nni_http_res_get_reason(const nni_http_res *); -extern int nni_http_res_set_reason(nni_http_res *, const char *); - -// nni_http_res_is_error is true if the status was allocated as part of -// nni_http_res_alloc_error(). This is a hint to the server to replace -// the HTML body with customized content if it exists. -extern bool nni_http_res_is_error(nni_http_res *); -// nni_http_alloc_html_error allocates a string corresponding to an -// HTML error. This can be set as the body of the res. The status -// will be looked up using HTTP status code lookups, but the details -// will be added if present as further body text. The result can -// be freed with nni_strfree() later. -extern int nni_http_alloc_html_error(char **, uint16_t, const char *); +extern bool nni_http_res_is_error(nni_http_res *); extern void nni_http_read(nni_http_conn *, nni_aio *); extern void nni_http_read_full(nni_http_conn *, nni_aio *); extern void nni_http_write(nni_http_conn *, nni_aio *); extern void nni_http_write_full(nni_http_conn *, nni_aio *); +extern int nni_http_add_header(nng_http *, const char *, const char *); +extern int nni_http_set_header(nng_http *, const char *, const char *); +extern void nni_http_del_header(nng_http *, const char *); +extern const char *nni_http_get_header(nng_http *, const char *); + +extern void nni_http_get_body(nng_http *, void **, size_t *); +extern void nni_http_set_body(nng_http *, void *, size_t); +extern int nni_http_copy_body(nng_http *, const void *, size_t); + +// prune body clears the outgoing body (0 bytes), but leaves content-length +// intact if present for the benefit of HEAD. +extern void nni_http_prune_body(nng_http *); + // nni_http_server will look for an existing server with the same // name and port, or create one if one does not exist. The servers // are reference counted to permit sharing the server object across @@ -232,14 +207,10 @@ extern void nni_http_server_close(nni_http_server *); extern int nni_http_server_set_error_page( nni_http_server *, uint16_t, const char *); -// nni_http_server_set_error_page sets an error file for the named status. -extern int nni_http_server_set_error_file( - nni_http_server *, uint16_t, const char *); - // nni_http_server_res_error takes replaces the body of the res with // a custom error page previously set for the server, using the status // of the res. The res must have the status set first. -extern int nni_http_server_res_error(nni_http_server *, nni_http_res *); +extern int nni_http_server_error(nni_http_server *, nng_http *); // nni_http_hijack is intended to be called by a handler that wishes to // take over the processing of the HTTP session -- usually to change protocols @@ -390,6 +361,44 @@ 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); + +extern void nni_http_set_method(nng_http *conn, const char *method); +extern const char *nni_http_get_method(nng_http *conn); + +extern int nni_http_set_status( + nng_http *conn, uint16_t status, const char *reason); + +extern uint16_t nni_http_get_status(nng_http *); +extern const char *nni_http_get_reason(nng_http *); + +// nni_http_set_error flags an error using the built in HTML page. +// unless body is not NULL. To pass no content, pass an empty string for body. +extern int nni_http_set_error( + nng_http *conn, uint16_t status, const char *reason, const char *body); + +// nni_http_set_redirect is used to set the redirection. +// It uses a built-in error page, with a message about the redirection, and +// sets the response Location: header accordingly. +extern int nni_http_set_redirect( + nng_http *conn, uint16_t status, const char *reason, const char *dest); + +extern int nni_http_set_uri( + nng_http *conn, const char *uri, const char *query); +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_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 diff --git a/src/supplemental/http/http_client.c b/src/supplemental/http/http_client.c index 8701a96b7..7062ae3cb 100644 --- a/src/supplemental/http/http_client.c +++ b/src/supplemental/http/http_client.c @@ -10,12 +10,14 @@ // #include +#include #include #include #include "core/nng_impl.h" #include "http_api.h" +#include "http_msg.h" static nni_mtx http_txn_lk = NNI_MTX_INITIALIZER; @@ -24,6 +26,7 @@ struct nng_http_client { nni_mtx mtx; bool closed; nni_aio aio; + char host[260]; nng_stream_dialer *dialer; }; @@ -70,7 +73,9 @@ http_dial_cb(void *arg) stream = nni_aio_get_output(&c->aio, 0); NNI_ASSERT(stream != NULL); - rv = nni_http_conn_init(&conn, stream); + rv = nni_http_conn_init(&conn, stream, true); + + // set up the host header http_dial_start(c); nni_mtx_unlock(&c->mtx); @@ -79,7 +84,7 @@ http_dial_cb(void *arg) nni_aio_finish_error(aio, rv); return; } - + nni_http_set_host(conn, c->host); nni_aio_set_output(aio, 0, conn); nni_aio_finish(aio, 0, 0); } @@ -110,7 +115,8 @@ nni_http_client_init(nni_http_client **cp, const nng_url *url) memcpy(&my_url, url, sizeof(my_url)); my_url.u_scheme = (char *) scheme; - if (strlen(url->u_hostname) == 0) { + if ((strlen(url->u_hostname) == 0) || + (strlen(url->u_hostname) > 253)) { // We require a valid hostname. return (NNG_EADDRINVAL); } @@ -122,6 +128,16 @@ nni_http_client_init(nni_http_client **cp, const nng_url *url) nni_aio_list_init(&c->aios); nni_aio_init(&c->aio, http_dial_cb, c); + if (nni_url_default_port(url->u_scheme) == url->u_port) { + snprintf(c->host, sizeof(c->host), "%s", url->u_hostname); + } else if (strchr(url->u_hostname, ':') != NULL) { + // IPv6 address, needs [wrapping] + snprintf(c->host, sizeof(c->host), "[%s]:%d", url->u_hostname, + url->u_port); + } else { + snprintf(c->host, sizeof(c->host), "%s:%d", url->u_hostname, + url->u_port); + } if ((rv = nng_stream_dialer_alloc_url(&c->dialer, &my_url)) != 0) { nni_http_client_fini(c); return (rv); @@ -190,7 +206,6 @@ nni_http_client_connect(nni_http_client *c, nni_aio *aio) } typedef enum http_txn_state { - HTTP_CONNECTING, HTTP_SENDING, HTTP_RECVING, HTTP_RECVING_BODY, @@ -198,7 +213,7 @@ typedef enum http_txn_state { } http_txn_state; typedef struct http_txn { - nni_aio *aio; // lower level aio + nni_aio aio; // lower level aio nni_list aios; // upper level aio(s) -- maximum one nni_http_client *client; nni_http_conn *conn; @@ -206,12 +221,15 @@ typedef struct http_txn { nni_http_res *res; nni_http_chunks *chunks; http_txn_state state; + nni_reap_node reap; } http_txn; static void -http_txn_fini(void *arg) +http_txn_reap(void *arg) { http_txn *txn = arg; + + nni_aio_stop(&txn->aio); if (txn->client != NULL) { // We only close the connection if we created it. if (txn->conn != NULL) { @@ -220,10 +238,21 @@ http_txn_fini(void *arg) } } nni_http_chunks_free(txn->chunks); - nni_aio_reap(txn->aio); + nni_aio_fini(&txn->aio); NNI_FREE_STRUCT(txn); } +static nni_reap_list http_txn_reaplist = { + .rl_offset = offsetof(http_txn, reap), + .rl_func = (nni_cb) http_txn_reap, +}; + +static void +http_txn_fini(http_txn *txn) +{ + nni_reap(&http_txn_reaplist, txn); +} + static void http_txn_finish_aios(http_txn *txn, int rv) { @@ -248,31 +277,26 @@ http_txn_cb(void *arg) nni_http_chunk *chunk = NULL; nni_mtx_lock(&http_txn_lk); - if ((rv = nni_aio_result(txn->aio)) != 0) { + if ((rv = nni_aio_result(&txn->aio)) != 0) { http_txn_finish_aios(txn, rv); nni_mtx_unlock(&http_txn_lk); http_txn_fini(txn); return; } switch (txn->state) { - case HTTP_CONNECTING: - txn->conn = nni_aio_get_output(txn->aio, 0); - txn->state = HTTP_SENDING; - nni_http_write_req(txn->conn, txn->req, txn->aio); - nni_mtx_unlock(&http_txn_lk); - return; - case HTTP_SENDING: txn->state = HTTP_RECVING; - nni_http_read_res(txn->conn, txn->res, txn->aio); + nni_http_read_res(txn->conn, &txn->aio); nni_mtx_unlock(&http_txn_lk); return; case HTTP_RECVING: - // Detect chunked encoding. You poor bastard. - if (((str = nni_http_res_get_header( - txn->res, "Transfer-Encoding")) != NULL) && + // Detect chunked encoding. You poor bastard. (Only if not + // HEAD.) + if ((strcmp(nni_http_get_method(txn->conn), "HEAD") != 0) && + ((str = nni_http_get_header( + txn->conn, "Transfer-Encoding")) != NULL) && (strstr(str, "chunked") != NULL)) { if ((rv = nni_http_chunks_init(&txn->chunks, 0)) != @@ -280,15 +304,15 @@ http_txn_cb(void *arg) goto error; } txn->state = HTTP_RECVING_CHUNKS; - nni_http_read_chunks(txn->conn, txn->chunks, txn->aio); + nni_http_read_chunks( + txn->conn, txn->chunks, &txn->aio); nni_mtx_unlock(&http_txn_lk); return; } - str = nni_http_req_get_method(txn->req); - if ((nni_strcasecmp(str, "HEAD") == 0) || - ((str = nni_http_res_get_header( - txn->res, "Content-Length")) == NULL) || + if ((strcmp(nni_http_get_method(txn->conn), "HEAD") == 0) || + ((str = nni_http_get_header( + txn->conn, "Content-Length")) == NULL) || ((len = (uint64_t) strtoull(str, &end, 10)) == 0) || (end == NULL) || (*end != '\0')) { // If no content-length, or HEAD (which per RFC @@ -303,10 +327,10 @@ http_txn_cb(void *arg) 0) { goto error; } - nni_http_res_get_data(txn->res, &iov.iov_buf, &iov.iov_len); - nni_aio_set_iov(txn->aio, 1, &iov); + nni_http_get_body(txn->conn, &iov.iov_buf, &iov.iov_len); + nni_aio_set_iov(&txn->aio, 1, &iov); txn->state = HTTP_RECVING_BODY; - nni_http_read_full(txn->conn, txn->aio); + nni_http_read_full(txn->conn, &txn->aio); nni_mtx_unlock(&http_txn_lk); return; @@ -324,7 +348,7 @@ http_txn_cb(void *arg) if ((rv = nni_http_res_alloc_data(txn->res, sz)) != 0) { goto error; } - nni_http_res_get_data(txn->res, (void **) &dst, &sz); + nni_http_get_body(txn->conn, (void **) &dst, &sz); while ((chunk = nni_http_chunks_iter(txn->chunks, chunk)) != NULL) { memcpy(dst, nni_http_chunk_data(chunk), @@ -350,7 +374,7 @@ http_txn_cancel(nni_aio *aio, void *arg, int rv) http_txn *txn = arg; nni_mtx_lock(&http_txn_lk); if (nni_aio_list_active(aio)) { - nni_aio_abort(txn->aio, rv); + nni_aio_abort(&txn->aio, rv); } nni_mtx_unlock(&http_txn_lk); } @@ -364,18 +388,13 @@ void nni_http_transact_conn(nni_http_conn *conn, nni_aio *aio) { http_txn *txn; - int rv; nni_aio_reset(aio); if ((txn = NNI_ALLOC_STRUCT(txn)) == NULL) { nni_aio_finish_error(aio, NNG_ENOMEM); return; } - if ((rv = nni_aio_alloc(&txn->aio, http_txn_cb, txn)) != 0) { - NNI_FREE_STRUCT(txn); - nni_aio_finish_error(aio, rv); - return; - } + nni_aio_init(&txn->aio, http_txn_cb, txn); nni_aio_list_init(&txn->aios); txn->client = NULL; txn->conn = conn; @@ -391,55 +410,7 @@ nni_http_transact_conn(nni_http_conn *conn, nni_aio *aio) http_txn_fini(txn); return; } - nni_http_res_reset(txn->res); - nni_list_append(&txn->aios, aio); - nni_http_write_req(conn, txn->req, txn->aio); - nni_mtx_unlock(&http_txn_lk); -} - -// nni_http_transact_simple does a single transaction, creating a connection -// just for the purpose, and closing it when done. (No connection caching.) -// The reason we require a client to be created first is to deal with TLS -// settings. A single global client (per server) may be used. -void -nni_http_transact(nni_http_client *client, nni_http_req *req, - nni_http_res *res, nni_aio *aio) -{ - http_txn *txn; - int rv; - - nni_aio_reset(aio); - if ((txn = NNI_ALLOC_STRUCT(txn)) == NULL) { - nni_aio_finish_error(aio, NNG_ENOMEM); - return; - } - if ((rv = nni_aio_alloc(&txn->aio, http_txn_cb, txn)) != 0) { - NNI_FREE_STRUCT(txn); - nni_aio_finish_error(aio, rv); - return; - } - - if ((rv = nni_http_req_set_header(req, "Connection", "close")) != 0) { - nni_aio_finish_error(aio, rv); - http_txn_fini(txn); - return; - } - - nni_aio_list_init(&txn->aios); - txn->client = client; - txn->conn = NULL; - txn->req = req; - txn->res = res; - txn->state = HTTP_CONNECTING; - - nni_mtx_lock(&http_txn_lk); - if (!nni_aio_start(aio, http_txn_cancel, txn)) { - nni_mtx_unlock(&http_txn_lk); - http_txn_fini(txn); - return; - } - nni_http_res_reset(txn->res); nni_list_append(&txn->aios, aio); - nni_http_client_connect(client, txn->aio); + nni_http_write_req(conn, &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 9ed882f13..20ae2f053 100644 --- a/src/supplemental/http/http_conn.c +++ b/src/supplemental/http/http_conn.c @@ -1,5 +1,5 @@ // -// Copyright 2024 Staysail Systems, Inc. +// Copyright 2025 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2019 Devolutions // @@ -11,9 +11,12 @@ #include #include +#include #include +#include "core/list.h" #include "core/nng_impl.h" +#include "nng/http.h" #include "supplemental/tls/tls_api.h" #include "http_api.h" @@ -62,20 +65,20 @@ struct nng_http_conn { size_t rd_put; size_t rd_bufsz; bool rd_buffered; - - bool res_sent; + bool client; // true if this is a client's connection + bool res_sent; enum write_flavor wr_flavor; }; nng_http_req * -nni_http_conn_req(nng_http_conn *conn) +nni_http_conn_req(nng_http *conn) { return (&conn->req); } nng_http_res * -nni_http_conn_res(nng_http_conn *conn) +nni_http_conn_res(nng_http *conn) { return (&conn->res); } @@ -138,6 +141,20 @@ 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 +// 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) +{ + if (conn->rd_get != 0) { + memmove(conn->rd_buf, conn->rd_buf + conn->rd_get, + conn->rd_put - conn->rd_get); + conn->rd_put -= conn->rd_get; + conn->rd_get = 0; + } +} + // http_rd_buf attempts to satisfy the read from data in the buffer. static int http_rd_buf(nni_http_conn *conn, nni_aio *aio) @@ -196,34 +213,44 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio) return (NNG_EAGAIN); case HTTP_RD_REQ: - rv = nni_http_req_parse( - nni_aio_get_prov_data(aio), 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; } 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; conn->rd_buffered = true; + if (iov1.iov_len == 0) { + return (NNG_EMSGSIZE); + } nni_aio_set_iov(&conn->rd_aio, 1, &iov1); nng_stream_recv(conn->sock, &conn->rd_aio); } return (rv); case HTTP_RD_RES: - rv = nni_http_res_parse( - nni_aio_get_prov_data(aio), 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; } 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; conn->rd_buffered = true; + if (iov1.iov_len == 0) { + return (NNG_EMSGSIZE); + } nni_aio_set_iov(&conn->rd_aio, 1, &iov1); nng_stream_recv(conn->sock, &conn->rd_aio); } @@ -511,23 +538,29 @@ http_wr_submit(nni_http_conn *conn, nni_aio *aio, enum write_flavor flavor) } void -nni_http_read_req(nni_http_conn *conn, nni_aio *aio) +nni_http_conn_reset(nng_http *conn) { - nni_aio_set_prov_data(aio, &conn->req); + 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 +nni_http_read_req(nni_http_conn *conn, nni_aio *aio) +{ // clear the sent flag (used for the server) conn->res_sent = false; - nni_http_req_reset(&conn->req); + nni_http_conn_reset(conn); nni_mtx_lock(&conn->mtx); http_rd_submit(conn, aio, HTTP_RD_REQ); nni_mtx_unlock(&conn->mtx); } void -nni_http_read_res(nni_http_conn *conn, nni_http_res *res, nni_aio *aio) +nni_http_read_res(nni_http_conn *conn, nni_aio *aio) { - nni_aio_set_prov_data(aio, res); - nni_mtx_lock(&conn->mtx); http_rd_submit(conn, aio, HTTP_RD_RES); nni_mtx_unlock(&conn->mtx); @@ -564,28 +597,25 @@ nni_http_read(nni_http_conn *conn, nni_aio *aio) } void -nni_http_write_req(nni_http_conn *conn, nni_http_req *req, nni_aio *aio) +nni_http_write_req(nni_http_conn *conn, nni_aio *aio) { int rv; void *buf; size_t bufsz; - void *data; - size_t size; nni_iov iov[2]; int niov; - if ((rv = nni_http_req_get_buf(req, &buf, &bufsz)) != 0) { + if ((rv = nni_http_req_get_buf(&conn->req, &buf, &bufsz)) != 0) { nni_aio_finish_error(aio, rv); return; } - nni_http_req_get_data(req, &data, &size); niov = 1; iov[0].iov_len = bufsz; iov[0].iov_buf = buf; - if ((size > 0) && (data != NULL)) { + iov[1].iov_len = conn->req.data.size; + iov[1].iov_buf = conn->req.data.data; + if ((iov[1].iov_len > 0) && (iov[1].iov_buf != NULL)) { niov++; - iov[1].iov_len = size; - iov[1].iov_buf = data; } nni_aio_set_iov(aio, niov, iov); @@ -597,28 +627,24 @@ 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_aio *aio) { - 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); + int rv; + void *buf; + size_t bufsz; + nni_iov iov[2]; + int nio; conn->res_sent = true; - if ((rv = nni_http_res_get_buf(res, &buf, &bufsz)) != 0) { + if ((rv = nni_http_res_get_buf(conn, &buf, &bufsz)) != 0) { nni_aio_finish_error(aio, rv); return; } - nni_http_res_get_data(res, &data, &size); nio = 1; iov[0].iov_len = bufsz; iov[0].iov_buf = buf; - if ((size > 0) && (data != NULL)) { + iov[1].iov_len = conn->res.data.size; + iov[1].iov_buf = conn->res.data.data; + if ((iov[1].iov_len > 0) && (iov[1].iov_buf != NULL)) { nio++; - iov[1].iov_len = size; - iov[1].iov_buf = data; } nni_aio_set_iov(aio, nio, iov); @@ -643,6 +669,632 @@ nni_http_write_full(nni_http_conn *conn, nni_aio *aio) nni_mtx_unlock(&conn->mtx); } +const char * +nni_http_get_version(nng_http *conn) +{ + return (conn->req.vers); +} + +int +nni_http_set_version(nng_http *conn, const char *vers) +{ + static const char *http_versions[] = { + // for efficiency, we order in most likely first + "HTTP/1.1", + "HTTP/2", + "HTTP/3", + "HTTP/1.0", + "HTTP/0.9", + NULL, + }; + + 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]; + return (0); + } + } + return (NNG_ENOTSUP); +} + +void +nni_http_set_method(nng_http *conn, const char *method) +{ + if (method == NULL) { + method = "GET"; + } + // this may truncate the method, but nobody should be sending + // methods so long. + (void) snprintf(conn->req.meth, sizeof(conn->req.meth), "%s", method); +} + +const char * +nni_http_get_method(nng_http *conn) +{ + return (conn->req.meth); +} + +uint16_t +nni_http_get_status(nng_http *conn) +{ + return (conn->res.code); +} + +const char * +nni_http_reason(uint16_t code) +{ + static struct { + uint16_t code; + const char *mesg; + } http_status[] = { + // 200, listed first because most likely + { NNG_HTTP_STATUS_OK, "OK" }, + + // 100 series -- informational + { NNG_HTTP_STATUS_CONTINUE, "Continue" }, + { NNG_HTTP_STATUS_SWITCHING, "Switching Protocols" }, + { NNG_HTTP_STATUS_PROCESSING, "Processing" }, + + // 200 series -- successful + { NNG_HTTP_STATUS_CREATED, "Created" }, + { NNG_HTTP_STATUS_ACCEPTED, "Accepted" }, + { NNG_HTTP_STATUS_NOT_AUTHORITATIVE, "Not Authoritative" }, + { NNG_HTTP_STATUS_NO_CONTENT, "No Content" }, + { NNG_HTTP_STATUS_RESET_CONTENT, "Reset Content" }, + { NNG_HTTP_STATUS_PARTIAL_CONTENT, "Partial Content" }, + { NNG_HTTP_STATUS_MULTI_STATUS, "Multi-Status" }, + { NNG_HTTP_STATUS_ALREADY_REPORTED, "Already Reported" }, + { NNG_HTTP_STATUS_IM_USED, "IM Used" }, + + // 300 series -- redirection + { NNG_HTTP_STATUS_MULTIPLE_CHOICES, "Multiple Choices" }, + { NNG_HTTP_STATUS_STATUS_MOVED_PERMANENTLY, + "Moved Permanently" }, + { NNG_HTTP_STATUS_FOUND, "Found" }, + { NNG_HTTP_STATUS_SEE_OTHER, "See Other" }, + { NNG_HTTP_STATUS_NOT_MODIFIED, "Not Modified" }, + { NNG_HTTP_STATUS_USE_PROXY, "Use Proxy" }, + { NNG_HTTP_STATUS_TEMPORARY_REDIRECT, "Temporary Redirect" }, + { NNG_HTTP_STATUS_PERMANENT_REDIRECT, "Permanent Redirect" }, + + // 400 series -- client errors + { NNG_HTTP_STATUS_BAD_REQUEST, "Bad Request" }, + { NNG_HTTP_STATUS_UNAUTHORIZED, "Unauthorized" }, + { NNG_HTTP_STATUS_PAYMENT_REQUIRED, "Payment Required" }, + { NNG_HTTP_STATUS_FORBIDDEN, "Forbidden" }, + { NNG_HTTP_STATUS_NOT_FOUND, "Not Found" }, + { NNG_HTTP_STATUS_METHOD_NOT_ALLOWED, "Method Not Allowed" }, + { NNG_HTTP_STATUS_NOT_ACCEPTABLE, "Not Acceptable" }, + { NNG_HTTP_STATUS_PROXY_AUTH_REQUIRED, + "Proxy Authentication Required" }, + { NNG_HTTP_STATUS_REQUEST_TIMEOUT, "Request Timeout" }, + { NNG_HTTP_STATUS_CONFLICT, "Conflict" }, + { NNG_HTTP_STATUS_GONE, "Gone" }, + { NNG_HTTP_STATUS_LENGTH_REQUIRED, "Length Required" }, + { NNG_HTTP_STATUS_PRECONDITION_FAILED, "Precondition Failed" }, + { NNG_HTTP_STATUS_CONTENT_TOO_LARGE, "Content Too Large" }, + { NNG_HTTP_STATUS_URI_TOO_LONG, "URI Too Long" }, + { NNG_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, + "Unsupported Media Type" }, + { NNG_HTTP_STATUS_RANGE_NOT_SATISFIABLE, + "Range Not Satisfiable" }, + { NNG_HTTP_STATUS_EXPECTATION_FAILED, "Expectation Failed" }, + { NNG_HTTP_STATUS_TEAPOT, "I Am A Teapot" }, + { NNG_HTTP_STATUS_LOCKED, "Locked" }, + { NNG_HTTP_STATUS_FAILED_DEPENDENCY, "Failed Dependency" }, + { NNG_HTTP_STATUS_UPGRADE_REQUIRED, "Upgrade Required" }, + { NNG_HTTP_STATUS_PRECONDITION_REQUIRED, + "Precondition Required" }, + { NNG_HTTP_STATUS_TOO_MANY_REQUESTS, "Too Many Requests" }, + { NNG_HTTP_STATUS_HEADERS_TOO_LARGE, "Headers Too Large" }, + { NNG_HTTP_STATUS_UNAVAIL_LEGAL_REASONS, + "Unavailable For Legal Reasons" }, + + // 500 series -- server errors + { NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR, + "Internal Server Error" }, + { NNG_HTTP_STATUS_NOT_IMPLEMENTED, "Not Implemented" }, + { NNG_HTTP_STATUS_BAD_REQUEST, "Bad Gateway" }, + { NNG_HTTP_STATUS_SERVICE_UNAVAILABLE, "Service Unavailable" }, + { NNG_HTTP_STATUS_GATEWAY_TIMEOUT, "Gateway Timeout" }, + { NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP, + "HTTP Version Not Supported" }, + { NNG_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES, + "Variant Also Negotiates" }, + { NNG_HTTP_STATUS_INSUFFICIENT_STORAGE, + "Insufficient Storage" }, + { NNG_HTTP_STATUS_LOOP_DETECTED, "Loop Detected" }, + { NNG_HTTP_STATUS_NOT_EXTENDED, "Not Extended" }, + { NNG_HTTP_STATUS_NETWORK_AUTH_REQUIRED, + "Network Authentication Required" }, + + // Terminator + { 0, NULL }, + }; + + for (int i = 0; http_status[i].code != 0; i++) { + if (http_status[i].code == code) { + return (http_status[i].mesg); + } + } + return ("Unknown HTTP Status"); +} + +const char * +nni_http_get_reason(nng_http *conn) +{ +#ifdef NNG_SUPP_HTTP + return ( + conn->res.rsn ? conn->res.rsn : nni_http_reason(conn->res.code)); +#else + return (NULL); +#endif +} + +int +nni_http_set_status(nng_http *conn, uint16_t status, const char *reason) +{ + conn->res.code = status; + char *dup = NULL; + if ((reason != NULL) && + (strcmp(reason, nni_http_reason(conn->res.code)) == 0)) { + reason = NULL; + return (0); + } + if ((reason != NULL) && (dup = nni_strdup(reason)) == NULL) { + return (NNG_ENOMEM); + } + if (conn->res.rsn != NULL) { + nni_strfree(conn->res.rsn); + } + conn->res.rsn = dup; + return (0); +} + +static int +http_conn_set_error(nng_http *conn, uint16_t status, const char *reason, + const char *body, const char *redirect) +{ + int rv; + char content[1024]; + const char *prefix = "\n" + "%d %s\n" + "" + "

 

" + "

%d

" + "

%s

"; + const char *suffix = "

"; + + conn->res.iserr = true; + + if ((rv = nni_http_set_status(conn, status, reason)) != 0) { + return (rv); + } + reason = nni_http_get_reason(conn); + + if (body == NULL) { + snprintf(content, sizeof(content), prefix, status, reason, + status, reason); + size_t avail = sizeof(content) - strlen(content); + + if (redirect != NULL && strlen(redirect) > 200 && + strlen(reason) < 40) { + // URL is too long for buffer and unlikely to be useful + // to humans anyway. 600 bytes will fit in the 1K + // buffer without issue. (Our prelude and trailer are + // less than 400 bytes.) + snprintf(content + strlen(content), avail, + "You should be automatically redirected."); + avail = sizeof(content) - strlen(content); + } else if (redirect != NULL) { + // TODO: redirect should be URL encoded. + snprintf(content + strlen(content), avail, + "You should be automatically redirected to %s.", + redirect, redirect); + avail = sizeof(content) - strlen(content); + } + snprintf(content + strlen(content), avail, "%s", suffix); + body = content; + } + if (strlen(body) > 0) { + nni_http_set_content_type(conn, "text/html; charset=UTF-8"); + return (nni_http_copy_body(conn, body, strlen(body))); + } + return (0); +} + +int +nni_http_set_error( + nng_http *conn, uint16_t status, const char *reason, const char *body) +{ + return (http_conn_set_error(conn, status, reason, body, NULL)); +} + +int +nni_http_set_redirect( + nng_http *conn, uint16_t status, const char *reason, const char *redirect) +{ + char *loc; + if ((loc = nni_strdup(redirect)) == NULL) { + return (NNG_ENOMEM); + } + (void) nni_http_del_header(conn, "Location"); + nni_list_node_remove(&conn->res.location.node); + nni_http_free_header(&conn->res.location); + conn->res.location.name = "Location"; + conn->res.location.value = loc; + conn->res.location.static_name = true; + conn->res.location.static_value = false; + nni_list_prepend(&conn->res.data.hdrs, &conn->res.location); + return (http_conn_set_error(conn, status, reason, NULL, 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); + } + 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.static_name = true; + conn->req.host_header.static_value = true; + conn->req.host_header.alloc_header = false; + 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 * +nni_http_get_uri(nng_http *conn) +{ + return (conn->req.uri); +} + +int +nni_http_set_uri(nng_http *conn, const char *uri, const char *query) +{ + size_t needed; + const char *fmt; + + if (query != NULL) { + fmt = strchr(uri, '?') != NULL ? "%s&%s" : "%s?%s"; + needed = strlen(uri) + strlen(query) + 1; + } else { + fmt = "%s%s"; + query = ""; + needed = strlen(uri); + } + + if (conn->req.uri != NULL && (strcmp(uri, conn->req.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); + } + + // 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; + return (0); + } + + // too big, we have to allocate it (slow path) + if (nni_asprintf(&conn->req.uri, fmt, uri, query) != 0) { + return (NNG_ENOMEM); + } + return (0); +} + +static int +http_set_header(nng_http *conn, const char *key, const char *val) +{ + 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; + if ((news = nni_strdup(val)) == NULL) { + return (NNG_ENOMEM); + } + if (!h->static_value) { + nni_strfree(h->value); + h->value = NULL; + } + h->value = news; + return (0); + } + } + + if ((h = NNI_ALLOC_STRUCT(h)) == NULL) { + return (NNG_ENOMEM); + } + h->alloc_header = true; + if ((h->name = nni_strdup(key)) == NULL) { + NNI_FREE_STRUCT(h); + return (NNG_ENOMEM); + } + if ((h->value = nni_strdup(val)) == NULL) { + nni_strfree(h->name); + NNI_FREE_STRUCT(h); + return (NNG_ENOMEM); + } + nni_list_append(&data->hdrs, h); + return (0); +} + +static int +http_add_header(nng_http *conn, const char *key, const char *val) +{ + 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); + if (rv != 0) { + return (rv); + } + if (!h->static_value) { + nni_strfree(h->value); + } + h->value = news; + return (0); + } + } + + if ((h = NNI_ALLOC_STRUCT(h)) == NULL) { + return (NNG_ENOMEM); + } + h->alloc_header = true; + if ((h->name = nni_strdup(key)) == NULL) { + NNI_FREE_STRUCT(h); + return (NNG_ENOMEM); + } + if ((h->value = nni_strdup(val)) == NULL) { + nni_strfree(h->name); + NNI_FREE_STRUCT(h); + return (NNG_ENOMEM); + } + nni_list_append(&data->hdrs, h); + return (0); +} + +static bool +http_set_known_header(nng_http *conn, const char *key, const char *val) +{ + if (nni_strcasecmp(key, "Content-Type") == 0) { + nni_http_set_content_type(conn, val); + return (true); + } + 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); + } + + if (conn->client) { + if (nni_strcasecmp(key, "Host") == 0) { + nni_http_set_host(conn, val); + return (true); + } + } + return (false); +} + +int +nni_http_add_header(nng_http *conn, const char *key, const char *val) +{ + if (http_set_known_header(conn, key, val)) { + return (0); + } + + return (http_add_header(conn, key, val)); +} + +void +nni_http_set_static_header( + nng_http *conn, nni_http_header *h, const char *key, const char *val) +{ + nni_list *headers; + if (conn->client) { + headers = &conn->req.data.hdrs; + } else { + headers = &conn->res.data.hdrs; + } + + nni_http_del_header(conn, key); + nni_list_node_remove(&h->node); + h->alloc_header = false; + h->static_name = true; + h->static_value = true; + h->name = (char *) key; + h->value = (char *) val; + nni_list_append(headers, h); +} + +int +nni_http_set_header(nng_http *conn, const char *key, const char *val) +{ + if (http_set_known_header(conn, key, val)) { + return (0); + } + return (http_set_header(conn, key, val)); +} + +static bool +http_del_header_one(nni_list *hdrs, const char *key) +{ + 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) +{ + nni_list *hdrs = + conn->client ? &conn->req.data.hdrs : &conn->res.data.hdrs; + while (http_del_header_one(hdrs, key)) { + continue; + } +} + +static const char * +http_get_header(const nni_list *hdrs, const char *key) +{ + http_header *h; + NNI_LIST_FOREACH (hdrs, h) { + if (nni_strcasecmp(h->name, key) == 0) { + return (h->value); + } + } + return (NULL); +} + +const char * +nni_http_get_header(nng_http *conn, const char *key) +{ + if (conn->client) { + return (http_get_header(&conn->res.data.hdrs, key)); + } else { + return (http_get_header(&conn->req.data.hdrs, key)); + } +} + +void +nni_http_get_body(nng_http *conn, void **datap, size_t *sizep) +{ + if (conn->client) { + *datap = conn->res.data.data; + *sizep = conn->res.data.size; + } else { + *datap = conn->req.data.data; + *sizep = conn->req.data.size; + } +} + +static void +http_set_data(nni_http_entity *entity, const void *data, size_t size) +{ + if (entity->own) { + nni_free(entity->data, entity->size); + } + entity->data = (void *) data; + entity->size = size; + entity->own = false; +} + +static int +http_alloc_data(nni_http_entity *entity, size_t size) +{ + void *newdata; + if (size != 0) { + if ((newdata = nni_zalloc(size)) == NULL) { + return (NNG_ENOMEM); + } + } + http_set_data(entity, newdata, size); + entity->own = true; + return (0); +} + +static int +http_copy_data(nni_http_entity *entity, const void *data, size_t size) +{ + int rv; + if ((rv = http_alloc_data(entity, size)) == 0) { + memcpy(entity->data, data, size); + } + return (rv); +} + +void +nni_http_set_body(nng_http *conn, void *data, size_t size) +{ + if (conn->client) { + http_set_data(&conn->req.data, data, size); + } else { + http_set_data(&conn->res.data, data, size); + } + nni_http_set_content_length(conn, size); +} + +void +nni_http_prune_body(nng_http *conn) +{ + // prune body but leave content-length header intact. + // This is for HEAD. + if (conn->client) { + http_set_data(&conn->req.data, NULL, 0); + } else { + http_set_data(&conn->res.data, NULL, 0); + } +} + +int +nni_http_copy_body(nng_http *conn, const void *data, size_t size) +{ + int rv; + if (conn->client) { + rv = http_copy_data(&conn->req.data, data, size); + } else { + rv = http_copy_data(&conn->res.data, data, size); + } + if (rv == 0) { + nni_http_set_content_length(conn, size); + } + return (rv); +} + int nni_http_conn_getopt( nni_http_conn *conn, const char *name, void *buf, size_t *szp, nni_type t) @@ -674,26 +1326,28 @@ 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_http_conn_reset(conn); nni_free(conn->rd_buf, conn->rd_bufsz); nni_mtx_fini(&conn->mtx); NNI_FREE_STRUCT(conn); } static int -http_init(nni_http_conn **connp, nng_stream *data) +http_init(nni_http_conn **connp, nng_stream *data, bool client) { nni_http_conn *conn; if ((conn = NNI_ALLOC_STRUCT(conn)) == NULL) { return (NNG_ENOMEM); } + conn->client = client; 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); + nni_http_set_version(conn, NNG_HTTP_VERSION_1_1); + nni_http_set_method(conn, NULL); if ((conn->rd_buf = nni_alloc(HTTP_BUFSIZE)) == NULL) { nni_http_conn_fini(conn); @@ -712,10 +1366,10 @@ http_init(nni_http_conn **connp, nng_stream *data) } int -nni_http_conn_init(nni_http_conn **connp, nng_stream *stream) +nni_http_conn_init(nni_http_conn **connp, nng_stream *stream, bool client) { int rv; - if ((rv = http_init(connp, stream)) != 0) { + if ((rv = http_init(connp, stream, client)) != 0) { nng_stream_free(stream); } return (rv); @@ -723,7 +1377,13 @@ nni_http_conn_init(nni_http_conn **connp, nng_stream *stream) // 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) +{ + return (conn->client ? conn->res.data.parsed : conn->req.data.parsed); +} diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c index 6b12496c4..988bb37e6 100644 --- a/src/supplemental/http/http_msg.c +++ b/src/supplemental/http/http_msg.c @@ -14,23 +14,27 @@ #include #include +#include "core/list.h" #include "core/nng_impl.h" #include "http_api.h" #include "http_msg.h" -#include "nng/supplemental/http/http.h" +#include "nng/http.h" -static int -http_set_string(char **strp, const char *val) +void +nni_http_free_header(http_header *h) { - char *news; - if (val == NULL) { - news = NULL; - } else if ((news = nni_strdup(val)) == NULL) { - return (NNG_ENOMEM); + nni_list_node_remove(&h->node); + if (!h->static_name) { + nni_strfree(h->name); + h->name = NULL; + } + if (!h->static_value) { + nni_strfree(h->value); + h->value = NULL; + } + if (h->alloc_header) { + NNI_FREE_STRUCT(h); } - nni_strfree(*strp); - *strp = news; - return (0); } static void @@ -38,10 +42,7 @@ http_headers_reset(nni_list *hdrs) { http_header *h; while ((h = nni_list_first(hdrs)) != NULL) { - nni_list_remove(hdrs, h); - nni_strfree(h->name); - nni_strfree(h->value); - NNI_FREE_STRUCT(h); + nni_http_free_header(h); } } @@ -51,57 +52,35 @@ http_entity_reset(nni_http_entity *entity) if (entity->own && entity->size) { nni_free(entity->data, entity->size); } - entity->data = NULL; - entity->size = 0; - entity->own = false; + http_headers_reset(&entity->hdrs); + nni_free(entity->buf, entity->bufsz); + entity->data = NULL; + entity->size = 0; + entity->own = false; + entity->parsed = false; + entity->buf = NULL; + entity->bufsz = 0; } void nni_http_req_reset(nni_http_req *req) { - http_headers_reset(&req->hdrs); http_entity_reset(&req->data); - nni_strfree(req->uri); + if (req->uri != req->ubuf) { + nni_strfree(req->uri); + } req->uri = NULL; - nni_free(req->buf, req->bufsz); - nni_http_req_set_method(req, NULL); - nni_http_req_set_version(req, NNG_HTTP_VERSION_1_1); - req->bufsz = 0; - req->buf = NULL; - req->parsed = false; + (void) snprintf(req->meth, sizeof(req->meth), "GET"); } void nni_http_res_reset(nni_http_res *res) { - http_headers_reset(&res->hdrs); http_entity_reset(&res->data); nni_strfree(res->rsn); - res->vers = NNG_HTTP_VERSION_1_1; - res->rsn = NULL; - res->code = 0; - res->parsed = false; - nni_free(res->buf, res->bufsz); - res->buf = NULL; - res->bufsz = 0; -} - -void -nni_http_req_free(nni_http_req *req) -{ - if (req != NULL) { - nni_http_req_reset(req); - NNI_FREE_STRUCT(req); - } -} - -void -nni_http_res_free(nni_http_res *res) -{ - if (res != NULL) { - nni_http_res_reset(res); - NNI_FREE_STRUCT(res); - } + res->vers = NNG_HTTP_VERSION_1_1; + res->rsn = NULL; + res->code = 0; } static int @@ -110,10 +89,7 @@ http_del_header(nni_list *hdrs, const char *key) http_header *h; NNI_LIST_FOREACH (hdrs, h) { if (nni_strcasecmp(key, h->name) == 0) { - nni_list_remove(hdrs, h); - nni_strfree(h->name); - nni_free(h->value, strlen(h->value) + 1); - NNI_FREE_STRUCT(h); + nni_http_free_header(h); return (0); } } @@ -123,127 +99,21 @@ http_del_header(nni_list *hdrs, const char *key) int nni_http_req_del_header(nni_http_req *req, const char *key) { - return (http_del_header(&req->hdrs, key)); -} - -int -nni_http_res_del_header(nni_http_res *res, const char *key) -{ - return (http_del_header(&res->hdrs, key)); -} - -static int -http_set_header(nni_list *hdrs, const char *key, const char *val) -{ - http_header *h; - NNI_LIST_FOREACH (hdrs, h) { - if (nni_strcasecmp(key, h->name) == 0) { - char *news; - if ((news = nni_strdup(val)) == NULL) { - return (NNG_ENOMEM); - } - nni_strfree(h->value); - h->value = news; - return (0); - } - } - - if ((h = NNI_ALLOC_STRUCT(h)) == NULL) { - return (NNG_ENOMEM); - } - if ((h->name = nni_strdup(key)) == NULL) { - NNI_FREE_STRUCT(h); - return (NNG_ENOMEM); - } - if ((h->value = nni_strdup(val)) == NULL) { - nni_strfree(h->name); - NNI_FREE_STRUCT(h); - return (NNG_ENOMEM); - } - nni_list_append(hdrs, h); - return (0); -} - -int -nni_http_req_set_header(nni_http_req *req, const char *key, const char *val) -{ - return (http_set_header(&req->hdrs, key, val)); -} - -int -nni_http_res_set_header(nni_http_res *res, const char *key, const char *val) -{ - return (http_set_header(&res->hdrs, key, val)); -} - -static int -http_add_header(nni_list *hdrs, const char *key, const char *val) -{ - http_header *h; - NNI_LIST_FOREACH (hdrs, h) { - if (nni_strcasecmp(key, h->name) == 0) { - char *news; - int rv; - rv = nni_asprintf(&news, "%s, %s", h->value, val); - if (rv != 0) { - return (rv); - } - nni_strfree(h->value); - h->value = news; - return (0); - } - } - - if ((h = NNI_ALLOC_STRUCT(h)) == NULL) { - return (NNG_ENOMEM); - } - if ((h->name = nni_strdup(key)) == NULL) { - NNI_FREE_STRUCT(h); - return (NNG_ENOMEM); + int rv = NNG_ENOENT; + while (http_del_header(&req->data.hdrs, key) == 0) { + rv = 0; } - if ((h->value = nni_strdup(val)) == NULL) { - nni_strfree(h->name); - NNI_FREE_STRUCT(h); - return (NNG_ENOMEM); - } - nni_list_append(hdrs, h); - return (0); -} - -int -nni_http_req_add_header(nni_http_req *req, const char *key, const char *val) -{ - return (http_add_header(&req->hdrs, key, val)); + return (rv); } int -nni_http_res_add_header(nni_http_res *res, const char *key, const char *val) -{ - return (http_add_header(&res->hdrs, key, val)); -} - -static const char * -http_get_header(const nni_list *hdrs, const char *key) +nni_http_res_del_header(nni_http_res *res, const char *key) { - http_header *h; - NNI_LIST_FOREACH (hdrs, h) { - if (nni_strcasecmp(h->name, key) == 0) { - return (h->value); - } + int rv = NNG_ENOENT; + while (http_del_header(&res->data.hdrs, key) == 0) { + rv = 0; } - return (NULL); -} - -const char * -nni_http_req_get_header(const nni_http_req *req, const char *key) -{ - return (http_get_header(&req->hdrs, key)); -} - -const char * -nni_http_res_get_header(const nni_http_res *res, const char *key) -{ - return (http_get_header(&res->hdrs, key)); + return (rv); } // http_entity_set_data sets the entity, but does not update the @@ -273,81 +143,6 @@ http_entity_alloc_data(nni_http_entity *entity, size_t size) return (0); } -static int -http_entity_copy_data(nni_http_entity *entity, const void *data, size_t size) -{ - int rv; - if ((rv = http_entity_alloc_data(entity, size)) == 0) { - memcpy(entity->data, data, size); - } - return (rv); -} - -static int -http_set_content_length(nni_http_entity *entity, nni_list *hdrs) -{ - char buf[16]; - (void) snprintf(buf, sizeof(buf), "%u", (unsigned) entity->size); - return (http_set_header(hdrs, "Content-Length", buf)); -} - -static void -http_entity_get_data(nni_http_entity *entity, void **datap, size_t *sizep) -{ - *datap = entity->data; - *sizep = entity->size; -} - -void -nni_http_req_get_data(nni_http_req *req, void **datap, size_t *sizep) -{ - http_entity_get_data(&req->data, datap, sizep); -} - -void -nni_http_res_get_data(nni_http_res *res, void **datap, size_t *sizep) -{ - http_entity_get_data(&res->data, datap, sizep); -} - -int -nni_http_req_set_data(nni_http_req *req, const void *data, size_t size) -{ - int rv; - - http_entity_set_data(&req->data, data, size); - if ((rv = http_set_content_length(&req->data, &req->hdrs)) != 0) { - http_entity_set_data(&req->data, NULL, 0); - } - return (rv); -} - -int -nni_http_res_set_data(nni_http_res *res, const void *data, size_t size) -{ - int rv; - - http_entity_set_data(&res->data, data, size); - if ((rv = http_set_content_length(&res->data, &res->hdrs)) != 0) { - http_entity_set_data(&res->data, NULL, 0); - } - res->iserr = false; - return (rv); -} - -int -nni_http_req_copy_data(nni_http_req *req, const void *data, size_t size) -{ - int rv; - - if (((rv = http_entity_copy_data(&req->data, data, size)) != 0) || - ((rv = http_set_content_length(&req->data, &req->hdrs)) != 0)) { - http_entity_set_data(&req->data, NULL, 0); - return (rv); - } - return (0); -} - int nni_http_req_alloc_data(nni_http_req *req, size_t size) { @@ -359,20 +154,6 @@ nni_http_req_alloc_data(nni_http_req *req, size_t size) return (0); } -int -nni_http_res_copy_data(nni_http_res *res, const void *data, size_t size) -{ - int rv; - - if (((rv = http_entity_copy_data(&res->data, data, size)) != 0) || - ((rv = http_set_content_length(&res->data, &res->hdrs)) != 0)) { - http_entity_set_data(&res->data, NULL, 0); - return (rv); - } - res->iserr = false; - return (0); -} - // nni_http_res_alloc_data allocates the data region, but does not update any // headers. The intended use is for client implementations that want to // allocate a buffer to receive the entity into. @@ -394,7 +175,7 @@ nni_http_res_is_error(nni_http_res *res) } static int -http_parse_header(nni_list *hdrs, void *line) +http_parse_header(nng_http *conn, void *line) { char *key = line; char *val; @@ -418,7 +199,7 @@ http_parse_header(nni_list *hdrs, void *line) end--; } - return (http_add_header(hdrs, key, val)); + return (nni_http_add_header(conn, key, val)); } // http_sprintf_headers makes headers for an HTTP request or an HTTP response @@ -494,258 +275,77 @@ http_req_prepare(nni_http_req *req) if (req->uri == NULL) { return (NNG_EINVAL); } - rv = http_asprintf(&req->buf, &req->bufsz, &req->hdrs, "%s %s %s\r\n", - req->meth, req->uri, req->vers); + 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(nni_http_res *res) +http_res_prepare(nng_http *conn) { - int rv; + 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->buf, &res->bufsz, &res->hdrs, "%s %d %s\r\n", - res->vers, nni_http_res_get_status(res), - nni_http_res_get_reason(res)); + 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); } -char * -nni_http_req_headers(nni_http_req *req) -{ - char *s; - size_t len; - - len = http_sprintf_headers(NULL, 0, &req->hdrs) + 1; - if ((s = nni_alloc(len)) != NULL) { - http_sprintf_headers(s, len, &req->hdrs); - } - return (s); -} - -char * -nni_http_res_headers(nni_http_res *res) -{ - char *s; - size_t len; - - len = http_sprintf_headers(NULL, 0, &res->hdrs) + 1; - if ((s = nni_alloc(len)) != NULL) { - http_sprintf_headers(s, len, &res->hdrs); - } - return (s); -} - int nni_http_req_get_buf(nni_http_req *req, void **data, size_t *szp) { int rv; - if ((req->buf == NULL) && (rv = http_req_prepare(req)) != 0) { + if ((req->data.buf == NULL) && (rv = http_req_prepare(req)) != 0) { return (rv); } - *data = req->buf; - *szp = req->bufsz - 1; // exclude terminating NUL + *data = req->data.buf; + *szp = req->data.bufsz - 1; // exclude terminating NUL return (0); } int -nni_http_res_get_buf(nni_http_res *res, void **data, size_t *szp) +nni_http_res_get_buf(nng_http *conn, void **data, size_t *szp) { - int rv; + int rv; + nni_http_res *res = nni_http_conn_res(conn); - if ((res->buf == NULL) && (rv = http_res_prepare(res)) != 0) { + if ((res->data.buf == NULL) && (rv = http_res_prepare(conn)) != 0) { return (rv); } - *data = res->buf; - *szp = res->bufsz - 1; // exclude terminating NUL + *data = res->data.buf; + *szp = res->data.bufsz - 1; // exclude terminating NUL return (0); } void nni_http_req_init(nni_http_req *req) { - NNI_LIST_INIT(&req->hdrs, http_header, node); - req->buf = NULL; - req->bufsz = 0; - req->data.data = NULL; - req->data.size = 0; - req->data.own = false; - req->uri = NULL; - nni_http_req_set_version(req, NNG_HTTP_VERSION_1_1); - nni_http_req_set_method(req, "GET"); -} - -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; - } 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; - } - 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); - } - } - *reqp = req; - return (0); + NNI_LIST_INIT(&req->data.hdrs, http_header, node); + req->data.buf = NULL; + req->data.bufsz = 0; + req->data.data = NULL; + req->data.size = 0; + req->data.own = false; + req->uri = NULL; + (void) snprintf(req->meth, sizeof(req->meth), "GET"); } void nni_http_res_init(nni_http_res *res) { - NNI_LIST_INIT(&res->hdrs, http_header, node); - res->buf = NULL; - res->bufsz = 0; - 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; -} - -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); -} - -const char * -nni_http_req_get_method(const nni_http_req *req) -{ - return (req->meth); -} - -const char * -nni_http_req_get_uri(const nni_http_req *req) -{ - return (req->uri != NULL ? req->uri : ""); -} - -const char * -nni_http_req_get_version(const nni_http_req *req) -{ - return (req->vers); -} - -const char * -nni_http_res_get_version(const nni_http_res *res) -{ - return (res->vers); -} - -static const char *http_versions[] = { - // for efficiency, we order in most likely first - "HTTP/1.1", - "HTTP/2", - "HTTP/3", - "HTTP/1.0", - "HTTP/0.9", - NULL, -}; - -static int -http_set_version(const char **ptr, 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) { - *ptr = http_versions[i]; - return (0); - } - } - return (NNG_ENOTSUP); -} - -int -nni_http_req_set_version(nni_http_req *req, const char *vers) -{ - return (http_set_version(&req->vers, vers)); -} - -int -nni_http_res_set_version(nni_http_res *res, const char *vers) -{ - return (http_set_version(&res->vers, vers)); -} - -int -nni_http_req_set_uri(nni_http_req *req, const char *uri) -{ - return (http_set_string(&req->uri, uri)); -} - -void -nni_http_req_set_method(nni_http_req *req, const char *meth) -{ - if (meth == NULL) { - meth = "GET"; - } - // this may truncate the method, but nobody should be sending - // methods so long. - (void) snprintf(req->meth, sizeof(req->meth), "%s", meth); -} - -void -nni_http_res_set_status(nni_http_res *res, uint16_t status) -{ - res->code = status; -} - -uint16_t -nni_http_res_get_status(const nni_http_res *res) -{ - return (res->code); + NNI_LIST_INIT(&res->data.hdrs, http_header, node); + res->data.buf = NULL; + res->data.bufsz = 0; + 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; } static int @@ -782,7 +382,7 @@ http_scan_line(void *vbuf, size_t n, size_t *lenp) } static int -http_req_parse_line(nni_http_req *req, void *line) +http_req_parse_line(nng_http *conn, void *line) { int rv; char *method; @@ -802,17 +402,16 @@ http_req_parse_line(nni_http_req *req, void *line) *version = '\0'; version++; - nni_http_req_set_method(req, method); - if (((rv = nni_http_req_set_uri(req, uri)) != 0) || - ((rv = nni_http_req_set_version(req, version)) != 0)) { + nni_http_set_method(conn, method); + if (((rv = nni_http_set_uri(conn, uri, NULL)) != 0) || + ((rv = nni_http_set_version(conn, version)) != 0)) { return (rv); } - req->parsed = true; return (0); } static int -http_res_parse_line(nni_http_res *res, uint8_t *line) +http_res_parse_line(nng_http *conn, uint8_t *line) { int rv; char *reason; @@ -838,13 +437,13 @@ http_res_parse_line(nni_http_res *res, uint8_t *line) return (NNG_EPROTO); } - nni_http_res_set_status(res, (uint16_t) status); + if ((rv = nni_http_set_status(conn, (uint16_t) status, reason)) != 0) { + return (rv); + } - if (((rv = nni_http_res_set_version(res, version)) != 0) || - ((rv = nni_http_res_set_reason(res, reason)) != 0)) { + if ((rv = nni_http_set_version(conn, version)) != 0) { return (rv); } - res->parsed = true; return (0); } @@ -855,12 +454,13 @@ http_res_parse_line(nni_http_res *res, uint8_t *line) // be updated even in the face of errors (esp. NNG_EAGAIN, which is // not an error so much as a request for more data.) int -nni_http_req_parse(nni_http_req *req, void *buf, size_t n, size_t *lenp) +nni_http_req_parse(nng_http *conn, void *buf, size_t n, size_t *lenp) { - size_t len = 0; - size_t cnt; - int rv = 0; + size_t len = 0; + size_t cnt; + int rv = 0; + nni_http_req *req = nni_http_conn_req(conn); for (;;) { uint8_t *line; @@ -877,10 +477,10 @@ nni_http_req_parse(nni_http_req *req, void *buf, size_t n, size_t *lenp) break; } - if (req->parsed) { - rv = http_parse_header(&req->hdrs, line); - } else { - rv = http_req_parse_line(req, line); + if (req->data.parsed) { + rv = http_parse_header(conn, line); + } else if ((rv = http_req_parse_line(conn, line)) == 0) { + req->data.parsed = true; } if (rv != 0) { @@ -888,17 +488,21 @@ nni_http_req_parse(nni_http_req *req, void *buf, size_t n, size_t *lenp) } } + if (rv == 0) { + req->data.parsed = false; + } *lenp = len; return (rv); } int -nni_http_res_parse(nni_http_res *res, void *buf, size_t n, size_t *lenp) +nni_http_res_parse(nng_http *conn, void *buf, size_t n, size_t *lenp) { - size_t len = 0; - size_t cnt; - int rv = 0; + size_t len = 0; + size_t cnt; + int rv = 0; + nng_http_res *res = nni_http_conn_res(conn); for (;;) { uint8_t *line; if ((rv = http_scan_line(buf, n, &cnt)) != 0) { @@ -914,10 +518,10 @@ nni_http_res_parse(nni_http_res *res, void *buf, size_t n, size_t *lenp) break; } - if (res->parsed) { - rv = http_parse_header(&res->hdrs, line); - } else { - rv = http_res_parse_line(res, line); + if (res->data.parsed) { + rv = http_parse_header(conn, line); + } else if ((rv = http_res_parse_line(conn, line)) == 0) { + res->data.parsed = true; } if (rv != 0) { @@ -925,171 +529,9 @@ nni_http_res_parse(nni_http_res *res, void *buf, size_t n, size_t *lenp) } } + if (rv == 0) { + res->data.parsed = false; + } *lenp = len; return (rv); } - -static struct { - uint16_t code; - const char *mesg; -} http_status[] = { - // 200, listed first because most likely - { NNG_HTTP_STATUS_OK, "OK" }, - - // 100 series -- informational - { NNG_HTTP_STATUS_CONTINUE, "Continue" }, - { NNG_HTTP_STATUS_SWITCHING, "Switching Protocols" }, - { NNG_HTTP_STATUS_PROCESSING, "Processing" }, - - // 200 series -- successful - { NNG_HTTP_STATUS_CREATED, "Created" }, - { NNG_HTTP_STATUS_ACCEPTED, "Accepted" }, - { NNG_HTTP_STATUS_NOT_AUTHORITATIVE, "Not Authoritative" }, - { NNG_HTTP_STATUS_NO_CONTENT, "No Content" }, - { NNG_HTTP_STATUS_RESET_CONTENT, "Reset Content" }, - { NNG_HTTP_STATUS_PARTIAL_CONTENT, "Partial Content" }, - - // 300 series -- redirection - { NNG_HTTP_STATUS_MULTIPLE_CHOICES, "Multiple Choices" }, - { NNG_HTTP_STATUS_STATUS_MOVED_PERMANENTLY, "Moved Permanently" }, - { NNG_HTTP_STATUS_FOUND, "Found" }, - { NNG_HTTP_STATUS_SEE_OTHER, "See Other" }, - { NNG_HTTP_STATUS_NOT_MODIFIED, "Not Modified" }, - { NNG_HTTP_STATUS_USE_PROXY, "Use Proxy" }, - { NNG_HTTP_STATUS_TEMPORARY_REDIRECT, "Temporary Redirect" }, - - // 400 series -- client errors - { NNG_HTTP_STATUS_BAD_REQUEST, "Bad Request" }, - { NNG_HTTP_STATUS_UNAUTHORIZED, "Unauthorized" }, - { NNG_HTTP_STATUS_PAYMENT_REQUIRED, "Payment Required" }, - { NNG_HTTP_STATUS_FORBIDDEN, "Forbidden" }, - { NNG_HTTP_STATUS_NOT_FOUND, "Not Found" }, - { NNG_HTTP_STATUS_METHOD_NOT_ALLOWED, "Method Not Allowed" }, - { NNG_HTTP_STATUS_NOT_ACCEPTABLE, "Not Acceptable" }, - { NNG_HTTP_STATUS_PROXY_AUTH_REQUIRED, - "Proxy Authentication Required" }, - { NNG_HTTP_STATUS_REQUEST_TIMEOUT, "Request Timeout" }, - { NNG_HTTP_STATUS_CONFLICT, "Conflict" }, - { NNG_HTTP_STATUS_GONE, "Gone" }, - { NNG_HTTP_STATUS_LENGTH_REQUIRED, "Length Required" }, - { NNG_HTTP_STATUS_PRECONDITION_FAILED, "Precondition Failed" }, - { NNG_HTTP_STATUS_ENTITY_TOO_LONG, "Request Entity Too Long" }, - { NNG_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type" }, - { NNG_HTTP_STATUS_RANGE_NOT_SATISFIABLE, - "Requested Range Not Satisfiable" }, - { NNG_HTTP_STATUS_EXPECTATION_FAILED, "Expectation Failed" }, - { NNG_HTTP_STATUS_TEAPOT, "I Am A Teapot" }, - { NNG_HTTP_STATUS_LOCKED, "Locked" }, - { NNG_HTTP_STATUS_FAILED_DEPENDENCY, "Failed Dependency" }, - { NNG_HTTP_STATUS_UPGRADE_REQUIRED, "Upgrade Required" }, - { NNG_HTTP_STATUS_PRECONDITION_REQUIRED, "Precondition Required" }, - { NNG_HTTP_STATUS_TOO_MANY_REQUESTS, "Too Many Requests" }, - { NNG_HTTP_STATUS_HEADERS_TOO_LARGE, "Headers Too Large" }, - { NNG_HTTP_STATUS_UNAVAIL_LEGAL_REASONS, - "Unavailable For Legal Reasons" }, - - // 500 series -- server errors - { NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR, "Internal Server Error" }, - { NNG_HTTP_STATUS_NOT_IMPLEMENTED, "Not Implemented" }, - { NNG_HTTP_STATUS_BAD_REQUEST, "Bad Gateway" }, - { NNG_HTTP_STATUS_SERVICE_UNAVAILABLE, "Service Unavailable" }, - { NNG_HTTP_STATUS_GATEWAY_TIMEOUT, "Gateway Timeout" }, - { NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP, - "HTTP Version Not Supported" }, - { NNG_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates" }, - { NNG_HTTP_STATUS_INSUFFICIENT_STORAGE, "Insufficient Storage" }, - { NNG_HTTP_STATUS_LOOP_DETECTED, "Loop Detected" }, - { NNG_HTTP_STATUS_NOT_EXTENDED, "Not Extended" }, - { NNG_HTTP_STATUS_NETWORK_AUTH_REQUIRED, - "Network Authentication Required" }, - - // Terminator - { 0, NULL }, -}; - -const char * -nni_http_reason(uint16_t code) -{ - for (int i = 0; http_status[i].code != 0; i++) { - if (http_status[i].code == code) { - return (http_status[i].mesg); - } - } - return ("Unknown HTTP Status"); -} - -const char * -nni_http_res_get_reason(const nni_http_res *res) -{ - return (res->rsn ? res->rsn : nni_http_reason(res->code)); -} - -int -nni_http_res_set_reason(nni_http_res *res, const char *reason) -{ - if ((reason != NULL) && - (strcmp(reason, nni_http_reason(res->code)) == 0)) { - reason = NULL; - } - return (http_set_string(&res->rsn, reason)); -} - -int -nni_http_alloc_html_error(char **html, uint16_t code, const char *details) -{ - const char *rsn = nni_http_reason(code); - - return (nni_asprintf(html, - "\n" - "%d %s\n" - "" - "

 

" - "

%d

" - "

%s

" - "

%s

" - "", - code, rsn, code, rsn, details != NULL ? details : "")); -} - -int -nni_http_res_set_error(nni_http_res *res, uint16_t err) -{ - 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); - return (rv); - } - nni_strfree(html); - res->code = err; - res->iserr = true; - return (0); -} - -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_msg.h b/src/supplemental/http/http_msg.h index 7d9e7dcf3..e08dab8a7 100644 --- a/src/supplemental/http/http_msg.h +++ b/src/supplemental/http/http_msg.h @@ -22,36 +22,45 @@ typedef struct http_header { char *name; char *value; nni_list_node node; + bool static_name : 1; // name is static, do not free it + bool static_value : 1; // value is static, do not free it + bool alloc_header : 1; // header is heap allocated } http_header; +typedef struct http_header nni_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 + char *data; + size_t size; + bool own; // if true, data is "ours", and should be freed + char clen[24]; // 64-bit lengths, in decimal + char ctype[128]; // 63+63+; per RFC 6838 + http_header content_type; + http_header content_length; + nni_list hdrs; + char *buf; + size_t bufsz; + bool parsed; } nni_http_entity; struct nng_http_req { - nni_list hdrs; 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; - char *buf; - size_t bufsz; - bool parsed; + http_header host_header; }; 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; + http_header location; }; +extern void nni_http_free_header(http_header *); + #endif diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index dd35151a3..ef0008022 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -1,5 +1,5 @@ // -// Copyright 2024 Staysail Systems, Inc. +// Copyright 2025 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -10,123 +10,30 @@ #include "core/nng_impl.h" #include "http_api.h" -#include "nng/supplemental/http/http.h" +#include "nng/http.h" // Symbols in this file are "public" versions of the HTTP API. // These are suitable for exposure to applications. -int -nng_http_req_alloc(nng_http_req **reqp, const nng_url *url) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_req_alloc(reqp, url)); -#else - NNI_ARG_UNUSED(reqp); - NNI_ARG_UNUSED(url); - return (NNG_ENOTSUP); -#endif -} - -void -nng_http_req_free(nng_http_req *req) -{ -#ifdef NNG_SUPP_HTTP - nni_http_req_free(req); -#else - NNI_ARG_UNUSED(req); -#endif -} - -void -nng_http_res_free(nng_http_res *res) -{ -#ifdef NNG_SUPP_HTTP - nni_http_res_free(res); -#else - NNI_ARG_UNUSED(res); -#endif -} - -int -nng_http_res_alloc(nng_http_res **resp) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_res_alloc(resp)); -#else - NNI_ARG_UNUSED(resp); - return (NNG_ENOTSUP); -#endif -} - -int -nng_http_res_alloc_error(nng_http_res **resp, uint16_t code) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_res_alloc_error(resp, code)); -#else - NNI_ARG_UNUSED(resp); - NNI_ARG_UNUSED(code); - return (NNG_ENOTSUP); -#endif -} - const char * -nng_http_req_get_header(const nng_http_req *req, const char *key) +nng_http_get_header(nng_http *conn, const char *key) { #ifdef NNG_SUPP_HTTP - return (nni_http_req_get_header(req, key)); + return (nni_http_get_header(conn, key)); #else - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(key); - return (NULL); -#endif -} - -const char * -nng_http_res_get_header(const nng_http_res *res, const char *key) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_res_get_header(res, key)); -#else - NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(conn); NNI_ARG_UNUSED(key); return (NULL); #endif } int -nng_http_req_add_header(nng_http_req *req, const char *key, const char *val) +nng_http_set_header(nng_http *conn, const char *key, const char *val) { #ifdef NNG_SUPP_HTTP - return (nni_http_req_add_header(req, key, val)); + return (nni_http_set_header(conn, key, val)); #else - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(key); - NNI_ARG_UNUSED(val); - return (NNG_ENOTSUP); -#endif -} - -int -nng_http_res_add_header(nng_http_res *res, const char *key, const char *val) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_res_add_header(res, key, val)); -#else - NNI_ARG_UNUSED(res); - NNI_ARG_UNUSED(key); - NNI_ARG_UNUSED(val); - return (NNG_ENOTSUP); -#endif -} - -int -nng_http_req_set_header(nng_http_req *req, const char *key, const char *val) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_req_set_header(req, key, val)); -#else - NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(conn); NNI_ARG_UNUSED(key); NNI_ARG_UNUSED(val); return (NNG_ENOTSUP); @@ -134,75 +41,37 @@ nng_http_req_set_header(nng_http_req *req, const char *key, const char *val) } int -nng_http_res_set_header(nng_http_res *res, const char *key, const char *val) +nng_http_add_header(nng_http *conn, const char *key, const char *val) { #ifdef NNG_SUPP_HTTP - return (nni_http_res_set_header(res, key, val)); + return (nni_http_add_header(conn, key, val)); #else - NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(conn); NNI_ARG_UNUSED(key); NNI_ARG_UNUSED(val); return (NNG_ENOTSUP); #endif } -int -nng_http_req_del_header(nng_http_req *req, const char *key) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_req_del_header(req, key)); -#else - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(key); - return (NNG_ENOTSUP); -#endif -} - -int -nng_http_res_del_header(nng_http_res *res, const char *key) +void +nng_http_del_header(nng_http *conn, const char *key) { #ifdef NNG_SUPP_HTTP - return (nni_http_res_del_header(res, key)); + nni_http_del_header(conn, key); #else - NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(conn); NNI_ARG_UNUSED(key); return (NNG_ENOTSUP); #endif } -int -nng_http_req_copy_data(nng_http_req *req, const void *data, size_t sz) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_req_copy_data(req, data, sz)); -#else - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(data); - NNI_ARG_UNUSED(sz); - return (NNG_ENOTSUP); -#endif -} - -int -nng_http_res_copy_data(nng_http_res *res, const void *data, size_t sz) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_res_copy_data(res, data, sz)); -#else - NNI_ARG_UNUSED(res); - NNI_ARG_UNUSED(data); - NNI_ARG_UNUSED(sz); - return (NNG_ENOTSUP); -#endif -} - -int -nng_http_req_set_data(nng_http_req *req, const void *data, size_t sz) +void +nng_http_set_body(nng_http *conn, void *data, size_t sz) { #ifdef NNG_SUPP_HTTP - return (nni_http_req_set_data(req, data, sz)); + nni_http_set_body(conn, data, sz); #else - NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(conn); NNI_ARG_UNUSED(data); NNI_ARG_UNUSED(sz); return (NNG_ENOTSUP); @@ -210,212 +79,146 @@ nng_http_req_set_data(nng_http_req *req, const void *data, size_t sz) } int -nng_http_res_set_data(nng_http_res *res, const void *data, size_t sz) +nng_http_copy_body(nng_http *conn, const void *data, size_t len) { #ifdef NNG_SUPP_HTTP - return (nni_http_res_set_data(res, data, sz)); + return (nni_http_copy_body(conn, data, len)); #else - NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(conn); NNI_ARG_UNUSED(data); - NNI_ARG_UNUSED(sz); + NNI_ARG_UNUSED(len); return (NNG_ENOTSUP); #endif } void -nng_http_req_get_data(nng_http_req *req, void **datap, size_t *lenp) +nng_http_get_body(nng_http *conn, void **datap, size_t *lenp) { #ifdef NNG_SUPP_HTTP - nni_http_req_get_data(req, datap, lenp); + nni_http_get_body(conn, datap, lenp); #else - NNI_ARG_UNUSED(req); - *datap = NULL; - *lenp = 0; -#endif -} - -void -nng_http_res_get_data(nng_http_res *res, void **datap, size_t *lenp) -{ -#ifdef NNG_SUPP_HTTP - nni_http_res_get_data(res, datap, lenp); -#else - NNI_ARG_UNUSED(res); - *datap = NULL; - *lenp = 0; + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(datap); + NNI_ARG_UNUSED(lenp); #endif } const char * -nng_http_req_get_method(const nng_http_req *req) +nng_http_get_uri(nng_http *conn) { #ifdef NNG_SUPP_HTTP - return (nni_http_req_get_method(req)); + return (nni_http_get_uri(conn)); #else NNI_ARG_UNUSED(req); return (NULL); #endif } -const char * -nng_http_req_get_version(const nng_http_req *req) +int +nng_http_set_uri(nng_http *conn, const char *uri, const char *query) { #ifdef NNG_SUPP_HTTP - return (nni_http_req_get_version(req)); + return (nni_http_set_uri(conn, uri, query)); #else - NNI_ARG_UNUSED(req); - return (NULL); + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(uri); + NNI_ARG_UNUSED(query); + return (NNG_ENOTSUP); #endif } const char * -nng_http_req_get_uri(const nng_http_req *req) +nng_http_get_version(nng_http *conn) { #ifdef NNG_SUPP_HTTP - return (nni_http_req_get_uri(req)); + return (nni_http_get_version(conn)); #else - NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(res); return (NULL); #endif } -void -nng_http_req_set_method(nng_http_req *req, const char *meth) -{ -#ifdef NNG_SUPP_HTTP - nni_http_req_set_method(req, meth); -#else - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(meth); -#endif -} - -int -nng_http_req_set_version(nng_http_req *req, const char *vers) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_req_set_version(req, vers)); -#else - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(vers); - return (NNG_ENOTSUP); -#endif -} - -int -nng_http_req_set_url(nng_http_req *req, const nng_url *url) +nng_http_res * +nng_http_conn_res(nng_http *conn) { #ifdef NNG_SUPP_HTTP - return (nni_http_req_set_url(req, url)); + return (nni_http_conn_res(conn)); #else - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(url); - return (NNG_ENOTSUP); + return (NULL); #endif } int -nng_http_req_set_uri(nng_http_req *req, const char *uri) +nng_http_set_status(nng_http *conn, uint16_t status, const char *reason) { #ifdef NNG_SUPP_HTTP - return (nni_http_req_set_uri(req, uri)); + return (nni_http_set_status(conn, status, reason)); #else - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(uri); + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(status); + NNI_ARG_UNUSED(reason); return (NNG_ENOTSUP); #endif } uint16_t -nng_http_res_get_status(const nng_http_res *res) +nng_http_get_status(nng_http *conn) { #ifdef NNG_SUPP_HTTP - return (nni_http_res_get_status(res)); + return (nni_http_get_status(conn)); #else NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(status); return (0); #endif } const char * -nng_http_res_get_version(const nng_http_res *res) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_res_get_version(res)); -#else - NNI_ARG_UNUSED(res); - return (NULL); -#endif -} - -const char * -nng_http_res_get_reason(const nng_http_res *res) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_res_get_reason(res)); -#else - NNI_ARG_UNUSED(res); - return (NULL); -#endif -} - -void -nng_http_res_set_status(nng_http_res *res, uint16_t status) +nng_http_get_reason(nng_http *conn) { #ifdef NNG_SUPP_HTTP - nni_http_res_set_status(res, status); + return (nni_http_get_reason(conn)); #else NNI_ARG_UNUSED(res); NNI_ARG_UNUSED(status); + return (0); #endif } int -nng_http_res_set_version(nng_http_res *res, const char *vers) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_res_set_version(res, vers)); -#else - NNI_ARG_UNUSED(res); - NNI_ARG_UNUSED(vers); - return (NNG_ENOTSUP); -#endif -} - -int -nng_http_res_set_reason(nng_http_res *res, const char *rsn) +nng_http_set_version(nng_http *conn, const char *version) { #ifdef NNG_SUPP_HTTP - return (nni_http_res_set_reason(res, rsn)); + return (nni_http_set_version(conn, version)); #else - NNI_ARG_UNUSED(res); - NNI_ARG_UNUSED(rsn); return (NNG_ENOTSUP); #endif } -nng_http_req * -nng_http_conn_req(nng_http_conn *conn) +void +nng_http_set_method(nng_http *conn, const char *method) { #ifdef NNG_SUPP_HTTP - return (nni_http_conn_req(conn)); + nni_http_set_method(conn, method); #else - return (NULL); + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(method); #endif } -nng_http_res * -nng_http_conn_res(nng_http_conn *conn) +const char * +nng_http_get_method(nng_http *conn) { #ifdef NNG_SUPP_HTTP - return (nni_http_conn_res(conn)); + return (nni_http_get_method(conn)); #else + NNI_ARG_UNUSED(conn); return (NULL); #endif } void -nng_http_conn_close(nng_http_conn *conn) +nng_http_close(nng_http *conn) { #ifdef NNG_SUPP_HTTP // API version of this closes *and* frees the structure. @@ -426,7 +229,7 @@ nng_http_conn_close(nng_http_conn *conn) } void -nng_http_conn_read(nng_http_conn *conn, nng_aio *aio) +nng_http_read(nng_http *conn, nng_aio *aio) { #ifdef NNG_SUPP_HTTP nni_http_read(conn, aio); @@ -437,7 +240,7 @@ nng_http_conn_read(nng_http_conn *conn, nng_aio *aio) } void -nng_http_conn_read_all(nng_http_conn *conn, nng_aio *aio) +nng_http_read_all(nng_http *conn, nng_aio *aio) { #ifdef NNG_SUPP_HTTP nni_http_read_full(conn, aio); @@ -448,7 +251,7 @@ nng_http_conn_read_all(nng_http_conn *conn, nng_aio *aio) } void -nng_http_conn_write(nng_http_conn *conn, nng_aio *aio) +nng_http_write(nng_http *conn, nng_aio *aio) { #ifdef NNG_SUPP_HTTP nni_http_write(conn, aio); @@ -459,7 +262,7 @@ nng_http_conn_write(nng_http_conn *conn, nng_aio *aio) } void -nng_http_conn_write_all(nng_http_conn *conn, nng_aio *aio) +nng_http_write_all(nng_http *conn, nng_aio *aio) { #ifdef NNG_SUPP_HTTP nni_http_write_full(conn, aio); @@ -470,19 +273,18 @@ nng_http_conn_write_all(nng_http_conn *conn, nng_aio *aio) } void -nng_http_conn_write_req(nng_http_conn *conn, nng_http_req *req, nng_aio *aio) +nng_http_write_request(nng_http *conn, nng_aio *aio) { #ifdef NNG_SUPP_HTTP - nni_http_write_req(conn, req, aio); + nni_http_write_req(conn, aio); #else NNI_ARG_UNUSED(conn); - NNI_ARG_UNUSED(req); nni_aio_finish_error(aio, NNG_ENOTSUP); #endif } void -nng_http_conn_write_res(nng_http_conn *conn, nng_aio *aio) +nng_http_write_response(nng_http *conn, nng_aio *aio) { #ifdef NNG_SUPP_HTTP nni_http_write_res(conn, aio); @@ -493,21 +295,10 @@ nng_http_conn_write_res(nng_http_conn *conn, nng_aio *aio) } void -nng_http_conn_read_req(nng_http_conn *conn, nng_aio *aio) -{ -#ifdef NNG_SUPP_HTTP - nni_http_read_req(conn, aio); -#else - NNI_ARG_UNUSED(conn); - nni_aio_finish_error(aio, NNG_ENOTSUP); -#endif -} - -void -nng_http_conn_read_res(nng_http_conn *conn, nng_http_res *res, nng_aio *aio) +nng_http_read_response(nng_http *conn, nng_aio *aio) { #ifdef NNG_SUPP_HTTP - nni_http_read_res(conn, res, aio); + nni_http_read_res(conn, aio); #else NNI_ARG_UNUSED(conn); NNI_ARG_UNUSED(res); @@ -756,20 +547,6 @@ nng_http_server_set_error_page( #endif } -int -nng_http_server_set_error_file( - nng_http_server *srv, uint16_t code, const char *path) -{ -#ifdef NNG_SUPP_HTTP - return (nni_http_server_set_error_file(srv, code, path)); -#else - NNI_ARG_UNUSED(srv); - NNI_ARG_UNUSED(code); - NNI_ARG_UNUSED(path); - return (NNG_ENOTSUP); -#endif -} - int nng_http_server_set_tls(nng_http_server *srv, nng_tls_config *cfg) { @@ -811,10 +588,10 @@ nng_http_server_get_addr(nng_http_server *srv, nng_sockaddr *addr) } int -nng_http_server_res_error(nng_http_server *srv, nng_http_res *res) +nng_http_server_error(nng_http_server *srv, nng_http *conn) { #ifdef NNG_SUPP_HTTP - return (nni_http_server_res_error(srv, res)); + return (nni_http_server_error(srv, conn)); #else NNI_ARG_UNUSED(srv); NNI_ARG_UNUSED(res); @@ -823,7 +600,7 @@ nng_http_server_res_error(nng_http_server *srv, nng_http_res *res) } int -nng_http_hijack(nng_http_conn *conn) +nng_http_hijack(nng_http *conn) { #ifdef NNG_SUPP_HTTP return (nni_http_hijack(conn)); @@ -891,21 +668,7 @@ nng_http_client_connect(nng_http_client *cli, nng_aio *aio) } void -nng_http_client_transact( - nng_http_client *cli, nng_http_req *req, nng_http_res *res, nng_aio *aio) -{ -#ifdef NNG_SUPP_HTTP - nni_http_transact(cli, req, res, aio); -#else - NNI_ARG_UNUSED(cli); - NNI_ARG_UNUSED(req); - NNI_ARG_UNUSED(res); - nni_aio_finish_error(aio, NNG_ENOTSUP); -#endif -} - -void -nng_http_conn_transact(nng_http_conn *conn, nng_aio *aio) +nng_http_transact(nng_http *conn, nng_aio *aio) { #ifdef NNG_SUPP_HTTP nni_http_transact_conn(conn, aio); @@ -916,21 +679,11 @@ nng_http_conn_transact(nng_http_conn *conn, nng_aio *aio) } void -nng_http_req_reset(nng_http_req *req) +nng_http_reset(nng_http *conn) { #ifdef NNG_SUPP_HTTP - nni_http_req_reset(req); + nni_http_conn_reset(conn); #else NNI_ARG_UNUSED(req); #endif } - -void -nng_http_res_reset(nng_http_res *res) -{ -#ifdef NNG_SUPP_HTTP - nni_http_res_reset(res); -#else - NNI_ARG_UNUSED(res); -#endif -} diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 872854175..7fbd7a56d 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -20,7 +20,9 @@ #include "core/nng_impl.h" #include "http_api.h" -#include "nng/supplemental/http/http.h" +#include "http_msg.h" +#include "nng/http.h" +#include "nng/nng.h" #ifndef NNG_HTTP_MAX_URI #define NNG_HTTP_MAX_URI 1024 @@ -59,13 +61,13 @@ typedef struct http_sconn { nni_aio txdataio; nni_reap_node reap; nni_atomic_flag closed; + nni_http_header close_header; } http_sconn; typedef struct http_error { nni_list_node node; uint16_t code; - void *body; - size_t len; + char *body; } http_error; struct nng_http_server { @@ -414,20 +416,15 @@ http_uri_canonify(char *path) static void http_sconn_error(http_sconn *sc, uint16_t err) { - nni_http_res *res; - - res = nng_http_conn_res(sc->conn); - nni_http_res_set_status(res, err); - if (nni_http_server_res_error(sc->server, res) != 0) { + nng_http_set_status(sc->conn, err, NULL); + if (nni_http_server_error(sc->server, sc->conn) != 0) { http_sconn_close(sc); return; } if (sc->close) { - if (nni_http_res_set_header(res, "Connection", "close") != 0) { - http_sconn_close(sc); - return; - } + nni_http_set_static_header( + sc->conn, &sc->close_header, "Connection", "close"); } nni_http_write_res(sc->conn, &sc->txaio); } @@ -515,7 +512,7 @@ http_sconn_rxdone(void *arg) nni_http_handler *h = NULL; nni_http_handler *head = NULL; const char *val; - nni_http_req *req = nng_http_conn_req(sc->conn); + nni_http_req *req = nni_http_conn_req(sc->conn); char *uri; size_t urisz; char *path; @@ -525,7 +522,15 @@ http_sconn_rxdone(void *arg) const char *cls; if ((rv = nni_aio_result(aio)) != 0) { - http_sconn_close(sc); + if (rv == NNG_EMSGSIZE) { + sc->close = true; + http_sconn_error(sc, + nni_http_parsed(sc->conn) + ? NNG_HTTP_STATUS_HEADERS_TOO_LARGE + : NNG_HTTP_STATUS_URI_TOO_LONG); + } else { + http_sconn_close(sc); + } return; } @@ -537,7 +542,7 @@ http_sconn_rxdone(void *arg) // Validate the request -- it has to at least look like HTTP // 1.x. We flatly refuse to deal with HTTP 0.9, and we can't // cope with HTTP/2. - if ((val = nni_http_req_get_version(req)) == NULL) { + if ((val = nni_http_get_version(sc->conn)) == NULL) { sc->close = true; http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST); return; @@ -557,7 +562,7 @@ http_sconn_rxdone(void *arg) // If the connection was 1.0, or a connection: close was // requested, then mark this close on our end. - if ((val = nni_http_req_get_header(req, "Connection")) != NULL) { + if ((val = nni_http_get_header(sc->conn, "Connection")) != NULL) { // HTTP 1.1 says these have to be case insensitive if (nni_strcasestr(val, "close") != NULL) { // In theory this could falsely match some other weird @@ -569,7 +574,7 @@ http_sconn_rxdone(void *arg) } } - val = nni_http_req_get_uri(req); + val = nni_http_get_uri(sc->conn); urisz = strlen(val) + 1; if ((uri = nni_alloc(urisz)) == NULL) { http_sconn_close(sc); // out of memory @@ -578,7 +583,7 @@ http_sconn_rxdone(void *arg) strncpy(uri, val, urisz); path = http_uri_canonify(uri); - host = nni_http_req_get_header(req, "Host"); + host = nni_http_get_header(sc->conn, "Host"); if ((host == NULL) && (needhost)) { // Per RFC 2616 14.23 we have to send 400 status here. http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST); @@ -616,7 +621,7 @@ http_sconn_rxdone(void *arg) break; } // So, what about the method? - val = nni_http_req_get_method(req); + val = nni_http_get_method(sc->conn); if (strcmp(val, h->method) == 0) { break; } @@ -646,7 +651,8 @@ http_sconn_rxdone(void *arg) } if ((h->getbody) && - ((cls = nni_http_req_get_header(req, "Content-Length")) != NULL)) { + ((cls = nni_http_get_header(sc->conn, "Content-Length")) != + NULL)) { uint64_t len; char *end; @@ -665,7 +671,8 @@ http_sconn_rxdone(void *arg) sc, NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR); return; } - nng_http_req_get_data(req, &iov.iov_buf, &iov.iov_len); + iov.iov_buf = req->data.data; + iov.iov_len = req->data.size; sc->handler = h; nni_mtx_unlock(&s->mtx); nni_aio_set_iov(&sc->rxaio, 1, &iov); @@ -725,28 +732,25 @@ http_sconn_cbdone(void *arg) return; } res = nni_http_conn_res(sc->conn); - if (!nni_http_conn_res_sent(sc->conn)) { + if (!nni_http_res_sent(sc->conn)) { const char *val; - val = nni_http_res_get_header(res, "Connection"); + const char *method; + uint16_t status; + val = nni_http_get_header(sc->conn, "Connection"); + status = nni_http_get_status(sc->conn); + method = nni_http_get_method(sc->conn); if ((val != NULL) && (strstr(val, "close") != NULL)) { sc->close = true; } if (sc->close) { - nni_http_res_set_header(res, "Connection", "close"); + nni_http_set_header(sc->conn, "Connection", "close"); } - 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 - // header. By passing NULL here, we leave off the old - // data, but the non-zero size means we don't clobber - // the HTTP header. - nni_http_res_get_data(res, &data, &size); - nni_http_res_set_data(res, NULL, size); + if ((strcmp(method, "HEAD") == 0) && status >= 200 && + status <= 299) { + // prune off data, preserving content-length header. + nni_http_prune_body(sc->conn); } else if (nni_http_res_is_error(res)) { - (void) nni_http_server_res_error(s, res); + (void) nni_http_server_error(s, sc->conn); } nni_http_write_res(sc->conn, &sc->txaio); } else if (sc->close) { @@ -775,7 +779,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_conn_init(&sc->conn, stream)) != 0) { + if ((rv = nni_http_conn_init(&sc->conn, stream, false)) != 0) { // Can't even accept the incoming request. Hard close. http_sconn_close(sc); return (rv); @@ -847,7 +851,7 @@ http_server_fini(nni_http_server *s) nni_mtx_lock(&s->errors_mtx); while ((epage = nni_list_first(&s->errors)) != NULL) { nni_list_remove(&s->errors, epage); - nni_free(epage->body, epage->len); + nni_strfree(epage->body); NNI_FREE_STRUCT(epage); } nni_mtx_unlock(&s->errors_mtx); @@ -1026,7 +1030,7 @@ nni_http_server_close(nni_http_server *s) } static int -http_server_set_err(nni_http_server *s, uint16_t code, void *body, size_t len) +http_server_set_err(nni_http_server *s, uint16_t code, char *body) { http_error *epage; @@ -1044,11 +1048,8 @@ http_server_set_err(nni_http_server *s, uint16_t code, void *body, size_t len) epage->code = code; nni_list_append(&s->errors, epage); } - if (epage->len != 0) { - nni_free(epage->body, epage->len); - } + nni_strfree(epage->body); epage->body = body; - epage->len = len; nni_mtx_unlock(&s->errors_mtx); return (0); } @@ -1057,75 +1058,36 @@ int nni_http_server_set_error_page( nni_http_server *s, uint16_t code, const char *html) { - char *body; - int rv; - size_t len; + char *body; + int rv; // We copy the content, without the trailing NUL. - len = strlen(html); - if ((body = nni_alloc(len)) == NULL) { + if ((body = nni_strdup(html)) == NULL) { return (NNG_ENOMEM); } - memcpy(body, html, len); - if ((rv = http_server_set_err(s, code, body, len)) != 0) { - nni_free(body, len); - } - return (rv); -} - -int -nni_http_server_set_error_file( - nni_http_server *s, uint16_t code, const char *path) -{ - void *body; - size_t len; - int rv; - if ((rv = nni_file_get(path, &body, &len)) != 0) { - return (rv); - } - if ((rv = http_server_set_err(s, code, body, len)) != 0) { - nni_free(body, len); + if ((rv = http_server_set_err(s, code, body)) != 0) { + nni_strfree(body); } return (rv); } int -nni_http_server_res_error(nni_http_server *s, nni_http_res *res) +nni_http_server_error(nni_http_server *s, nng_http *conn) { http_error *epage; char *body = NULL; - char *html = NULL; - size_t len = 0; - uint16_t code = nni_http_res_get_status(res); + uint16_t code = nni_http_get_status(conn); int rv; nni_mtx_lock(&s->errors_mtx); NNI_LIST_FOREACH (&s->errors, epage) { if (epage->code == code) { body = epage->body; - len = epage->len; break; } } + rv = nni_http_set_error(conn, code, NULL, body); nni_mtx_unlock(&s->errors_mtx); - - if (body == NULL) { - if ((rv = nni_http_alloc_html_error(&html, code, NULL)) != 0) { - return (rv); - } - body = html; - len = strlen(body); - } - - // NB: The server lock has to be held here to guard against the - // error page being tossed or changed. - if (((rv = nni_http_res_copy_data(res, body, len)) == 0) && - ((rv = nni_http_res_set_header( - res, "Content-Type", "text/html; charset=UTF-8")) == 0)) { - nni_http_res_set_status(res, code); - } - nni_strfree(html); - return (rv); } @@ -1322,14 +1284,13 @@ typedef struct http_file { } http_file; static void -http_handle_file(nni_http_conn *conn, void *arg, nni_aio *aio) +http_handle_file(nng_http *conn, void *arg, nni_aio *aio) { - nni_http_res *res = nng_http_conn_res(conn); - void *data; - size_t size; - int rv; - http_file *hf = arg; - const char *ctype; + void *data; + size_t size; + int rv; + http_file *hf = arg; + const char *ctype; if ((ctype = hf->ctype) == NULL) { ctype = "application/octet-stream"; @@ -1356,26 +1317,23 @@ http_handle_file(nni_http_conn *conn, void *arg, nni_aio *aio) status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; break; } - if ((rv = nni_http_res_set_error(res, status)) != 0) { + if ((rv = nni_http_set_error(conn, status, NULL, NULL)) != 0) { nni_aio_finish_error(aio, rv); return; } - nni_aio_set_output(aio, 0, res); nni_aio_finish(aio, 0, 0); return; } - if (((rv = nni_http_res_set_header(res, "Content-Type", ctype)) != - 0) || - ((rv = nni_http_res_copy_data(res, data, size)) != 0)) { + if (((rv = nni_http_set_header(conn, "Content-Type", ctype)) != 0) || + ((rv = nni_http_copy_body(conn, data, size)) != 0)) { nni_free(data, size); nni_aio_finish_error(aio, rv); return; } - nni_http_res_set_status(res, NNG_HTTP_STATUS_OK); + nng_http_set_status(conn, NNG_HTTP_STATUS_OK, NULL); nni_free(data, size); - nni_aio_set_output(aio, 0, res); nni_aio_finish(aio, 0, 0); } @@ -1439,22 +1397,20 @@ nni_http_handler_init_file( } static void -http_handle_dir(nng_http_conn *conn, void *arg, nng_aio *aio) +http_handle_dir(nng_http *conn, void *arg, nng_aio *aio) { - 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; + 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_get_uri(conn); + const char *ctype; + char *dst; + size_t len; + size_t pnsz; + char *pn; len = strlen(base); if (base[1] != '\0' && // Allows "/" as base @@ -1544,27 +1500,24 @@ http_handle_dir(nng_http_conn *conn, void *arg, nng_aio *aio) status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; break; } - if ((rv = nni_http_res_set_error(res, status)) != 0) { + if ((rv = nni_http_set_error(conn, status, NULL, NULL)) != 0) { nni_aio_finish_error(aio, rv); return; } - nni_aio_set_output(aio, 0, res); nni_aio_finish(aio, 0, 0); return; } - if (((rv = nni_http_res_set_header(res, "Content-Type", ctype)) != - 0) || - ((rv = nni_http_res_copy_data(res, data, size)) != 0)) { + if (((rv = nng_http_set_header(conn, "Content-Type", ctype)) != 0) || + ((rv = nng_http_copy_body(conn, data, size)) != 0)) { nni_free(data, size); nni_aio_finish_error(aio, rv); return; } - nni_http_res_set_status(res, NNG_HTTP_STATUS_OK); + nng_http_set_status(conn, NNG_HTTP_STATUS_OK, NULL); nni_free(data, size); - nni_aio_set_output(aio, 0, res); nni_aio_finish(aio, 0, 0); } @@ -1605,20 +1558,17 @@ typedef struct http_redirect { } http_redirect; static void -http_handle_redirect(nng_http_conn *conn, void *data, nng_aio *aio) +http_handle_redirect(nng_http *conn, void *data, nng_aio *aio) { - 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; + nni_http_res *res = nni_http_conn_res(conn); + 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); + uri = nni_http_get_uri(conn); // If we are doing a full tree, then include the entire suffix. if (strncmp(uri, base, strlen(base)) == 0) { @@ -1631,39 +1581,24 @@ http_handle_redirect(nng_http_conn *conn, void *data, nng_aio *aio) loc = hr->where; } - // Builtin redirect page - rv = nni_asprintf(&msg, - "You should be automatically redirected to %s.", - loc, loc); - // Build a response. We always close the connection for redirects, // 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_alloc_html_error(&html, hr->code, msg)) != 0) || - ((rv = nni_http_res_set_header(res, "Connection", "close")) != - 0) || - ((rv = nni_http_res_set_header( - 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 (((rv = nni_http_set_redirect(conn, hr->code, NULL, loc)) != 0) || + ((rv = nni_http_set_header(conn, "Connection", "close")) != 0)) { if (loc != hr->where) { nni_strfree(loc); } - nni_strfree(msg); - nni_strfree(html); nni_aio_finish_error(aio, rv); return; } - nni_http_res_set_status(res, hr->code); + nng_http_set_status(conn, hr->code, NULL); if (loc != hr->where) { nni_strfree(loc); } - nni_strfree(msg); - nni_strfree(html); nni_aio_set_output(aio, 0, res); nni_aio_finish(aio, 0, 0); } @@ -1725,28 +1660,21 @@ typedef struct http_static { } http_static; static void -http_handle_static(nng_http_conn *conn, void *data, nni_aio *aio) +http_handle_static(nng_http *conn, void *data, nni_aio *aio) { - http_static *hs = data; - const char *ctype; - nni_http_res *r = NULL; - int rv; + http_static *hs = data; + const char *ctype; if ((ctype = hs->ctype) == NULL) { ctype = "application/octet-stream"; } - 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_aio_finish_error(aio, rv); - return; - } + // this cannot fail (no dynamic allocation) + (void) nni_http_set_header(conn, "Content-Type", ctype); + nni_http_set_body(conn, hs->data, hs->size); - nni_http_res_set_status(r, NNG_HTTP_STATUS_OK); + nng_http_set_status(conn, NNG_HTTP_STATUS_OK, NULL); - nni_aio_set_output(aio, 0, r); nni_aio_finish(aio, 0, 0); } diff --git a/src/supplemental/http/http_server_test.c b/src/supplemental/http/http_server_test.c index 914114990..7a38a3964 100644 --- a/src/supplemental/http/http_server_test.c +++ b/src/supplemental/http/http_server_test.c @@ -11,8 +11,9 @@ // Basic HTTP server tests. #include "core/defs.h" +#include +#include #include -#include #include @@ -27,49 +28,31 @@ struct server_test { nng_http_server *s; nng_http_handler *h; nng_http_client *cli; - nng_http_conn *conn; - nng_http_req *req; - nng_http_res *res; + nng_http *conn; char urlstr[2048]; }; static int -httpdo(nng_url *url, nng_http_req *req, nng_http_res *res, void **datap, - size_t *sizep) +httpdo(struct server_test *st, void **datap, size_t *sizep) { - int rv; - nng_aio *aio = NULL; - nng_http_client *cli = NULL; - nng_http_conn *h = NULL; - size_t clen = 0; - void *data = NULL; - const char *ptr; - - if (((rv = nng_aio_alloc(&aio, NULL, NULL)) != 0) || - ((rv = nng_http_client_alloc(&cli, url)) != 0)) { - goto fail; - } - nng_http_client_connect(cli, aio); - nng_aio_wait(aio); - if ((rv = nng_aio_result(aio)) != 0) { - goto fail; - } - - h = nng_aio_get_output(aio, 0); + int rv; + size_t clen = 0; + void *data = NULL; + const char *ptr; - nng_http_conn_write_req(h, req, aio); - nng_aio_wait(aio); - if ((rv = nng_aio_result(aio)) != 0) { - goto fail; + nng_http_write_request(st->conn, st->aio); + nng_aio_wait(st->aio); + if ((rv = nng_aio_result(st->aio)) != 0) { + return (rv); } - nng_http_conn_read_res(h, res, aio); - nng_aio_wait(aio); - if ((rv = nng_aio_result(aio)) != 0) { - goto fail; + nng_http_read_response(st->conn, st->aio); + nng_aio_wait(st->aio); + if ((rv = nng_aio_result(st->aio)) != 0) { + return (rv); } clen = 0; - if ((ptr = nng_http_res_get_header(res, "Content-Length")) != NULL) { + if ((ptr = nng_http_get_header(st->conn, "Content-Length")) != NULL) { clen = atoi(ptr); } @@ -78,28 +61,17 @@ httpdo(nng_url *url, nng_http_req *req, nng_http_res *res, void **datap, data = nng_alloc(clen); iov.iov_buf = data; iov.iov_len = clen; - nng_aio_set_iov(aio, 1, &iov); - nng_http_conn_read_all(h, aio); - nng_aio_wait(aio); - if ((rv = nng_aio_result(aio)) != 0) { - goto fail; + nng_aio_set_iov(st->aio, 1, &iov); + nng_http_read_all(st->conn, st->aio); + nng_aio_wait(st->aio); + if ((rv = nng_aio_result(st->aio)) != 0) { + return (rv); } } *datap = data; *sizep = clen; -fail: - if (aio != NULL) { - nng_aio_free(aio); - } - if (h != NULL) { - nng_http_conn_close(h); - } - if (cli != NULL) { - nng_http_client_free(cli); - } - return (rv); } @@ -111,16 +83,17 @@ httpget(struct server_test *st, void **datap, size_t *sizep, uint16_t *statp, size_t clen = 0; void *data = NULL; char *ctype = NULL; + nng_http *conn = st->conn; const char *ptr; - if ((rv = httpdo(st->url, st->req, st->res, &data, &clen)) != 0) { + if ((rv = httpdo(st, &data, &clen)) != 0) { goto fail; } - *statp = nng_http_res_get_status(st->res); + *statp = nng_http_get_status(conn); if (clen > 0) { - if ((ptr = nng_http_res_get_header(st->res, "Content-Type")) != + if ((ptr = nng_http_get_header(conn, "Content-Type")) != NULL) { ctype = nng_strdup(ptr); } @@ -142,25 +115,22 @@ httpget(struct server_test *st, void **datap, size_t *sizep, uint16_t *statp, } static void -httpecho(nng_http_conn *conn, void *arg, nng_aio *aio) +httpecho(nng_http *conn, void *arg, nng_aio *aio) { - 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; + int rv; + void *body; + size_t len; NNI_ARG_UNUSED(arg); - nng_http_req_get_data(req, &body, &len); + nng_http_get_body(conn, &body, &len); - if (((rv = nng_http_res_copy_data(res, body, len)) != 0) || - ((rv = nng_http_res_set_header( - res, "Content-type", "text/plain")) != 0)) { + if (((rv = nng_http_copy_body(conn, body, len)) != 0) || + ((rv = nng_http_set_header(conn, "Content-type", "text/plain")) != + 0)) { nng_aio_finish(aio, rv); return; } - nng_http_res_set_status(res, NNG_HTTP_STATUS_OK); - nng_aio_set_output(aio, 0, res); + nng_http_set_status(conn, NNG_HTTP_STATUS_OK, NULL); nng_aio_finish(aio, 0); } @@ -188,17 +158,20 @@ server_setup(struct server_test *st, nng_http_handler *h) NUTS_PASS(nng_aio_result(st->aio)); st->conn = nng_aio_get_output(st->aio, 0); NUTS_TRUE(st->conn != NULL); - NUTS_PASS(nng_http_req_alloc(&st->req, st->url)); - NUTS_PASS(nng_http_res_alloc(&st->res)); + NUTS_PASS(nng_http_set_uri(st->conn, "/", NULL)); } static void server_reset(struct server_test *st) { - nng_http_req_free(st->req); - nng_http_res_free(st->res); - nng_http_req_alloc(&st->req, st->url); - nng_http_res_alloc(&st->res); + if (st->conn) { + nng_http_close(st->conn); + } + nng_http_client_connect(st->cli, st->aio); + nng_aio_wait(st->aio); + NUTS_PASS(nng_aio_result(st->aio)); + st->conn = nng_aio_get_output(st->aio, 0); + NUTS_PASS(nng_http_set_uri(st->conn, "/", NULL)); } static void @@ -211,7 +184,7 @@ server_free(struct server_test *st) nng_http_client_free(st->cli); } if (st->conn != NULL) { - nng_http_conn_close(st->conn); + nng_http_close(st->conn); } if (st->s != NULL) { nng_http_server_release(st->s); @@ -219,12 +192,6 @@ server_free(struct server_test *st) if (st->url != NULL) { nng_url_free(st->url); } - if (st->req != NULL) { - nng_http_req_free(st->req); - } - if (st->res != NULL) { - nng_http_res_free(st->res); - } } static void @@ -241,26 +208,26 @@ test_server_basic(void) server_setup(&st, h); - NUTS_PASS(nng_http_req_set_uri(st.req, "/home.html")); - nng_http_conn_write_req(st.conn, st.req, st.aio); + NUTS_PASS(nng_http_set_uri(st.conn, "/home.html", NULL)); + nng_http_write_request(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - nng_http_conn_read_res(st.conn, st.res, st.aio); + nng_http_read_response(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - NUTS_TRUE(nng_http_res_get_status(st.res) == NNG_HTTP_STATUS_OK); + NUTS_TRUE(nng_http_get_status(st.conn) == NNG_HTTP_STATUS_OK); - ptr = nng_http_res_get_header(st.res, "Content-Length"); + ptr = nng_http_get_header(st.conn, "Content-Length"); NUTS_TRUE(ptr != NULL); NUTS_TRUE(atoi(ptr) == (int) strlen(doc1)); iov.iov_len = strlen(doc1); iov.iov_buf = chunk; NUTS_PASS(nng_aio_set_iov(st.aio, 1, &iov)); - nng_http_conn_read_all(st.conn, st.aio); + nng_http_read_all(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); NUTS_TRUE(nng_aio_count(st.aio) == strlen(doc1)); @@ -276,18 +243,17 @@ test_server_404(void) server_setup(&st, NULL); - NUTS_PASS(nng_http_req_set_uri(st.req, "/bogus")); - nng_http_conn_write_req(st.conn, st.req, st.aio); + NUTS_PASS(nng_http_set_uri(st.conn, "/bogus", NULL)); + nng_http_write_request(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - nng_http_conn_read_res(st.conn, st.res, st.aio); + nng_http_read_response(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - NUTS_TRUE( - nng_http_res_get_status(st.res) == NNG_HTTP_STATUS_NOT_FOUND); + NUTS_TRUE(nng_http_get_status(st.conn) == NNG_HTTP_STATUS_NOT_FOUND); server_free(&st); } @@ -299,18 +265,19 @@ test_server_bad_version(void) server_setup(&st, NULL); - NUTS_PASS(nng_http_req_set_version(st.req, "HTTP/0.9")); - NUTS_PASS(nng_http_req_set_uri(st.req, "/bogus")); - nng_http_conn_write_req(st.conn, st.req, st.aio); + NUTS_PASS(nng_http_set_version(st.conn, "HTTP/0.9")); + NUTS_PASS(nng_http_set_uri(st.conn, "/bogus", NULL)); + nng_http_write_request(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - nng_http_conn_read_res(st.conn, st.res, st.aio); + nng_http_read_response(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - NUTS_TRUE(nng_http_res_get_status(st.res) == 505); + NUTS_TRUE(nng_http_get_status(st.conn) == + NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP); server_free(&st); } @@ -321,18 +288,18 @@ test_server_missing_host(void) struct server_test st; server_setup(&st, NULL); - nng_http_req_del_header(st.req, "Host"); - NUTS_PASS(nng_http_req_set_uri(st.req, "/bogus")); - nng_http_conn_write_req(st.conn, st.req, st.aio); + nng_http_del_header(st.conn, "Host"); + NUTS_PASS(nng_http_set_uri(st.conn, "/bogus", NULL)); + nng_http_write_request(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - nng_http_conn_read_res(st.conn, st.res, st.aio); + nng_http_read_response(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - NUTS_TRUE(nng_http_res_get_status(st.res) == 400); + NUTS_TRUE(nng_http_get_status(st.conn) == 400); server_free(&st); } @@ -363,21 +330,21 @@ test_server_wrong_method(void) server_setup(&st, h); - nng_http_req_set_method(st.req, "POST"); - NUTS_PASS(nng_http_req_set_uri(st.req, "/home.html")); - nng_http_conn_write_req(st.conn, st.req, st.aio); + nng_http_set_method(st.conn, "POST"); + NUTS_PASS(nng_http_set_uri(st.conn, "/home.html", NULL)); + nng_http_write_request(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - nng_http_conn_read_res(st.conn, st.res, st.aio); + nng_http_read_response(st.conn, st.aio); nng_aio_wait(st.aio); NUTS_PASS(nng_aio_result(st.aio)); - NUTS_TRUE(nng_http_res_get_status(st.res) == + NUTS_TRUE(nng_http_get_status(st.conn) == NNG_HTTP_STATUS_METHOD_NOT_ALLOWED); - NUTS_MSG("Got result %d: %s", nng_http_res_get_status(st.res), - nng_http_res_get_reason(st.res)); + NUTS_MSG("Got result %d: %s", nng_http_get_status(st.conn), + nng_http_get_reason(st.conn)); server_free(&st); } @@ -398,25 +365,26 @@ test_server_post_handler(void) server_setup(&st, h); snprintf(txdata, sizeof(txdata), "1234"); - nng_http_req_set_uri(st.req, "/post"); - nng_http_req_set_data(st.req, txdata, strlen(txdata)); - nng_http_req_set_method(st.req, "POST"); - NUTS_PASS(httpdo(st.url, st.req, st.res, (void **) &rxdata, &size)); - NUTS_TRUE(nng_http_res_get_status(st.res) == NNG_HTTP_STATUS_OK); + + NUTS_PASS(nng_http_set_uri(st.conn, "/post", NULL)); + nng_http_set_body(st.conn, txdata, strlen(txdata)); + nng_http_set_method(st.conn, "POST"); + NUTS_PASS(httpdo(&st, (void **) &rxdata, &size)); + NUTS_TRUE(nng_http_get_status(st.conn) == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(txdata)); NUTS_TRUE(strncmp(txdata, rxdata, size) == 0); nng_free(rxdata, size); server_reset(&st); - NUTS_PASS(nng_http_req_set_uri(st.req, "/post")); - nng_http_req_set_method(st.req, "GET"); - NUTS_PASS(nng_http_req_set_data(st.req, txdata, strlen(txdata))); + NUTS_PASS(nng_http_set_uri(st.conn, "/post", NULL)); + nng_http_set_method(st.conn, "GET"); + nng_http_set_body(st.conn, txdata, strlen(txdata)); - NUTS_PASS(httpdo(st.url, st.req, st.res, &data, &size)); - NUTS_TRUE(nng_http_res_get_status(st.res) == + NUTS_PASS(httpdo(&st, &data, &size)); + NUTS_TRUE(nng_http_get_status(st.conn) == NNG_HTTP_STATUS_METHOD_NOT_ALLOWED); - NUTS_MSG("HTTP status was %u", nng_http_res_get_status(st.res)); + NUTS_MSG("HTTP status was %u", nng_http_get_status(st.conn)); nng_free(data, size); server_free(&st); @@ -437,15 +405,14 @@ test_server_get_redirect(void) &h, "/here", 303, "http://127.0.0.1/there")); server_setup(&st, h); - NUTS_PASS(nng_http_req_set_uri(st.req, "/here")); - nng_http_req_set_method(st.req, "GET"); + NUTS_PASS(nng_http_set_uri(st.conn, "/here", NULL)); + nng_http_set_method(st.conn, "GET"); - NUTS_PASS(httpdo(st.url, st.req, st.res, &data, &size)); - NUTS_TRUE(nng_http_res_get_status(st.res) == 303); + NUTS_PASS(httpdo(&st, &data, &size)); + NUTS_TRUE(nng_http_get_status(st.conn) == 303); NUTS_MSG("HTTP status got %d, expected %d (url %s)", - nng_http_res_get_status(st.res), 303, fullurl); - NUTS_TRUE( - (dest = nng_http_res_get_header(st.res, "Location")) != NULL); + nng_http_get_status(st.conn), 303, fullurl); + NUTS_TRUE((dest = nng_http_get_header(st.conn, "Location")) != NULL); NUTS_MATCH(dest, "http://127.0.0.1/there"); nng_free(data, size); @@ -468,15 +435,14 @@ test_server_tree_redirect(void) nng_http_handler_set_tree(h); server_setup(&st, h); - NUTS_PASS(nng_http_req_set_uri(st.req, "/here/i/go/again")); - nng_http_req_set_method(st.req, "GET"); + NUTS_PASS(nng_http_set_uri(st.conn, "/here/i/go/again", NULL)); + nng_http_set_method(st.conn, "GET"); - NUTS_PASS(httpdo(st.url, st.req, st.res, &data, &size)); - NUTS_TRUE(nng_http_res_get_status(st.res) == 303); + NUTS_PASS(httpdo(&st, &data, &size)); + NUTS_TRUE(nng_http_get_status(st.conn) == 303); NUTS_MSG("HTTP status got %d, expected %d (url %s)", - nng_http_res_get_status(st.res), 303, fullurl); - NUTS_TRUE( - (dest = nng_http_res_get_header(st.res, "Location")) != NULL); + nng_http_get_status(st.conn), 303, fullurl); + NUTS_TRUE((dest = nng_http_get_header(st.conn, "Location")) != NULL); NUTS_MATCH(dest, "http://127.0.0.1/there/i/go/again"); nng_free(data, size); @@ -499,12 +465,12 @@ test_server_post_redirect(void) server_setup(&st, h); snprintf(txdata, sizeof(txdata), "1234"); - NUTS_PASS(nng_http_req_set_uri(st.req, "/here")); - nng_http_req_set_data(st.req, txdata, strlen(txdata)); - nng_http_req_set_method(st.req, "POST"); - NUTS_PASS(httpdo(st.url, st.req, st.res, (void **) &data, &size)); - NUTS_TRUE(nng_http_res_get_status(st.res) == 301); - dest = nng_http_res_get_header(st.res, "Location"); + NUTS_PASS(nng_http_set_uri(st.conn, "/here", NULL)); + nng_http_set_body(st.conn, txdata, strlen(txdata)); + nng_http_set_method(st.conn, "POST"); + NUTS_PASS(httpdo(&st, (void **) &data, &size)); + NUTS_TRUE(nng_http_get_status(st.conn) == 301); + dest = nng_http_get_header(st.conn, "Location"); NUTS_TRUE(dest != NULL); NUTS_MATCH(dest, "http://127.0.0.1/there"); nng_free(data, size); @@ -527,11 +493,11 @@ test_server_post_echo_tree(void) server_setup(&st, h); snprintf(txdata, sizeof(txdata), "1234"); - nng_http_req_set_data(st.req, txdata, strlen(txdata)); - nng_http_req_set_method(st.req, "POST"); - NUTS_PASS(nng_http_req_set_uri(st.req, "/some_sub/directory")); - NUTS_PASS(httpdo(st.url, st.req, st.res, (void **) &rxdata, &size)); - NUTS_TRUE(nng_http_res_get_status(st.res) == NNG_HTTP_STATUS_OK); + nng_http_set_body(st.conn, txdata, strlen(txdata)); + nng_http_set_method(st.conn, "POST"); + NUTS_PASS(nng_http_set_uri(st.conn, "/some_sub/directory", NULL)); + NUTS_PASS(httpdo(&st, (void **) &rxdata, &size)); + NUTS_TRUE(nng_http_get_status(st.conn) == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(txdata)); NUTS_TRUE(strncmp(txdata, rxdata, size) == 0); nng_free(rxdata, size); @@ -613,7 +579,7 @@ test_server_multiple_trees(void) char *ctype; NUTS_CASE("Directory 1"); - NUTS_PASS(nng_http_req_set_uri(st.req, "/file1.txt")); + NUTS_PASS(nng_http_set_uri(st.conn, "/file1.txt", NULL)); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(doc1)); @@ -625,7 +591,7 @@ test_server_multiple_trees(void) server_reset(&st); NUTS_CASE("Directory 2"); - NUTS_PASS(nng_http_req_set_uri(st.req, "/subdir/file2.txt")); + NUTS_PASS(nng_http_set_uri(st.conn, "/subdir/file2.txt", NULL)); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(doc2)); @@ -710,7 +676,7 @@ test_serve_directory(void) NUTS_PASS(nng_http_handler_alloc_directory(&h, "/", sd.workdir)); server_setup(&st, h); - NUTS_PASS(nng_http_req_set_uri(st.req, "/subdir1/index.html")); + NUTS_PASS(nng_http_set_uri(st.conn, "/subdir1/index.html", NULL)); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(doc1)); @@ -740,7 +706,7 @@ test_serve_directory_index(void) server_setup(&st, h); NUTS_CASE("Directory 1: index.html"); - NUTS_PASS(nng_http_req_set_uri(st.req, "/subdir1/")); + NUTS_PASS(nng_http_set_uri(st.conn, "/subdir1/", NULL)); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(doc1)); @@ -752,7 +718,7 @@ test_serve_directory_index(void) server_reset(&st); NUTS_CASE("Directory 2: index.htm"); - NUTS_PASS(nng_http_req_set_uri(st.req, "/subdir2/")); + NUTS_PASS(nng_http_set_uri(st.conn, "/subdir2/", NULL)); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(doc3)); @@ -781,7 +747,7 @@ test_serve_plain_text(void) NUTS_PASS(nng_http_handler_alloc_directory(&h, "/", sd.workdir)); server_setup(&st, h); - NUTS_PASS(nng_http_req_set_uri(st.req, "/file.txt")); + NUTS_PASS(nng_http_set_uri(st.conn, "/file.txt", NULL)); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(doc2)); @@ -810,12 +776,24 @@ test_serve_file_parameters(void) NUTS_PASS(nng_http_handler_alloc_directory(&h, "/", sd.workdir)); server_setup(&st, h); - NUTS_PASS(nng_http_req_set_uri(st.req, "/file.txt?param=1234")); + NUTS_PASS(nng_http_set_uri(st.conn, "/file.txt?param=1234", NULL)); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(doc2)); NUTS_TRUE(memcmp(data, doc2, size) == 0); NUTS_MATCH(ctype, "text/plain"); + nng_free(data, size); + nng_strfree(ctype); + + // again but this time pass parameter as arg + nng_http_reset(st.conn); + NUTS_PASS(nng_http_set_uri(st.conn, "/file.txt", "param=1234")); + NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); + NUTS_TRUE(stat == NNG_HTTP_STATUS_OK); + NUTS_TRUE(size == strlen(doc2)); + NUTS_TRUE(memcmp(data, doc2, size) == 0); + NUTS_MATCH(ctype, "text/plain"); + nng_strfree(ctype); nng_free(data, size); @@ -839,7 +817,7 @@ test_serve_missing_index(void) NUTS_PASS(nng_http_handler_alloc_directory(&h, "/", sd.workdir)); server_setup(&st, h); - NUTS_PASS(nng_http_req_set_uri(st.req, "/index.html")); + NUTS_PASS(nng_http_set_uri(st.conn, "/index.html", NULL)); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_NOT_FOUND); nng_strfree(ctype); @@ -865,8 +843,8 @@ test_serve_index_not_post(void) NUTS_PASS(nng_http_handler_alloc_directory(&h, "/", sd.workdir)); server_setup(&st, h); - NUTS_PASS(nng_http_req_set_uri(st.req, "/subdir2/index.html")); - nng_http_req_set_method(st.req, "POST"); + NUTS_PASS(nng_http_set_uri(st.conn, "/subdir2/index.html", NULL)); + nng_http_set_method(st.conn, "POST"); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_METHOD_NOT_ALLOWED); nng_strfree(ctype); @@ -892,7 +870,7 @@ test_serve_subdir_index(void) NUTS_PASS(nng_http_handler_alloc_directory(&h, "/docs", sd.workdir)); server_setup(&st, h); - NUTS_PASS(nng_http_req_set_uri(st.req, "/docs/subdir1/")); + NUTS_PASS(nng_http_set_uri(st.conn, "/docs/subdir1/", NULL)); NUTS_PASS(httpget(&st, &data, &size, &stat, &ctype)); NUTS_TRUE(stat == NNG_HTTP_STATUS_OK); NUTS_TRUE(size == strlen(doc1)); diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c index 70323b0cb..86edf1235 100644 --- a/src/supplemental/websocket/websocket.c +++ b/src/supplemental/websocket/websocket.c @@ -14,6 +14,7 @@ #include #include "core/nng_impl.h" +#include "nng/http.h" #include "supplemental/http/http_api.h" #include "base64.h" @@ -21,7 +22,7 @@ #include "websocket.h" // This should be removed or handled differently in the future. -typedef int (*nni_ws_listen_hook)(void *, nng_http_req *, nng_http_res *); +typedef int (*nni_ws_listen_hook)(void *, nng_http *); // We have chosen to be a bit more stringent in the size of the frames that // we send, while we more generously allow larger incoming frames. These @@ -55,6 +56,7 @@ struct nni_ws { bool inmsg; bool send_text; bool recv_text; + bool recv_res; nni_mtx mtx; nni_list sendq; nni_list recvq; @@ -68,16 +70,21 @@ struct nni_ws { nni_aio httpaio; nni_aio connaio; // connect aio nni_aio *useraio; // user aio, during HTTP negotiation - nni_http_conn *http; - nni_http_req *req; - nni_http_res *res; - char *reqhdrs; - char *reshdrs; + nng_http *http; size_t maxframe; size_t fragsize; size_t recvmax; // largest message size nni_ws_listener *listener; nni_ws_dialer *dialer; + char keybuf[29]; // key on client, accept on server + struct { + nni_http_header connection; + nni_http_header upgrade; + nni_http_header wsaccept; + nni_http_header wskey; + nni_http_header wsproto; + nni_http_header wsversion; + } hdrs; }; struct nni_ws_listener { @@ -235,64 +242,6 @@ ws_set_header(nni_list *l, const char *n, const char *v) return (ws_set_header_ext(l, n, v, true)); } -static int -ws_set_headers(nni_list *l, const char *str) -{ - char *dupstr; - size_t duplen; - char *n; - char *v; - char *nl; - int rv; - - if ((dupstr = nni_strdup(str)) == NULL) { - return (NNG_ENOMEM); - } - duplen = strlen(dupstr) + 1; // so we can free it later - - n = dupstr; - for (;;) { - if ((v = strchr(n, ':')) == NULL) { - // Note that this also means that if - // a bare word is present, we ignore it. - break; - } - *v = '\0'; - v++; - while (*v == ' ') { - // Skip leading whitespace. Not strictly - // necessary, but still a good idea. - v++; - } - nl = v; - // Find the end of the line -- should be CRLF, but can - // also be unterminated or just LF if user - while ((*nl != '\0') && (*nl != '\r') && (*nl != '\n')) { - nl++; - } - while ((*nl == '\r') || (*nl == '\n')) { - *nl = '\0'; - nl++; - } - - // Note that this can lead to a partial failure. As this - // is most likely ENOMEM, don't worry too much about it. - // This method does *not* eliminate duplicates. - if ((rv = ws_set_header_ext(l, n, v, false)) != 0) { - goto done; - } - - // Advance to the next name. - n = nl; - } - - rv = 0; - -done: - nni_free(dupstr, duplen); - return (rv); -} - // This looks, case independently for a word in a list, which is either // space or comma separated. static bool @@ -1244,8 +1193,6 @@ ws_fini(void *arg) nni_http_conn_fini(ws->http); } - nni_strfree(ws->reqhdrs); - nni_strfree(ws->reshdrs); nni_aio_fini(&ws->rxaio); nni_aio_fini(&ws->txaio); nni_aio_fini(&ws->closeaio); @@ -1325,14 +1272,14 @@ 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) { - ws->res = nni_http_conn_res(ws->http); - nni_http_read_res(ws->http, ws->res, &ws->httpaio); + if (!ws->recv_res) { + ws->recv_res = true; + nng_http_read_response(ws->http, &ws->httpaio); nni_mtx_unlock(&d->mtx); return; } - status = nni_http_res_get_status(ws->res); + status = nni_http_get_status(ws->http); switch (status) { case NNG_HTTP_STATUS_SWITCHING: break; @@ -1342,6 +1289,7 @@ ws_http_cb_dialer(nni_ws *ws, nni_aio *aio) goto err; case NNG_HTTP_STATUS_NOT_FOUND: case NNG_HTTP_STATUS_METHOD_NOT_ALLOWED: + case NNG_HTTP_STATUS_NOT_IMPLEMENTED: rv = NNG_ECONNREFUSED; // Treat these as refusals. goto err; case NNG_HTTP_STATUS_BAD_REQUEST: @@ -1351,34 +1299,31 @@ ws_http_cb_dialer(nni_ws *ws, nni_aio *aio) goto err; } - // Check that the server gave us back the right key. - rv = ws_make_accept( - nni_http_req_get_header(ws->req, "Sec-WebSocket-Key"), wskey); + rv = ws_make_accept(ws->keybuf, wskey); if (rv != 0) { goto err; } -#define GETH(h) nni_http_res_get_header(ws->res, h) - - if (((ptr = GETH("Sec-WebSocket-Accept")) == NULL) || + if (((ptr = nng_http_get_header(ws->http, "Sec-WebSocket-Accept")) == + NULL) || (strcmp(ptr, wskey) != 0) || - ((ptr = GETH("Connection")) == NULL) || + ((ptr = nng_http_get_header(ws->http, "Connection")) == NULL) || (!ws_contains_word(ptr, "upgrade")) || - ((ptr = GETH("Upgrade")) == NULL) || + ((ptr = nng_http_get_header(ws->http, "Upgrade")) == NULL) || (strcmp(ptr, "websocket") != 0)) { ws_close_error(ws, WS_CLOSE_PROTOCOL_ERR); rv = NNG_EPROTO; goto err; } if (d->proto != NULL) { - if (((ptr = GETH("Sec-WebSocket-Protocol")) == NULL) || + if (((ptr = nng_http_get_header( + ws->http, "Sec-WebSocket-Protocol")) == NULL) || (!ws_contains_word(d->proto, ptr))) { ws_close_error(ws, WS_CLOSE_PROTOCOL_ERR); rv = NNG_EPROTO; goto err; } } -#undef GETH // At this point, we are in business! nni_list_remove(&d->wspend, ws); @@ -1506,19 +1451,16 @@ ws_listener_free(void *arg) } static void -ws_handler(nng_http_conn *conn, void *arg, nng_aio *aio) +ws_handler(nng_http *conn, void *arg, nng_aio *aio) { 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_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) { @@ -1527,39 +1469,39 @@ ws_handler(nng_http_conn *conn, void *arg, nng_aio *aio) } // Now check the headers, etc. - if (strcmp(nni_http_req_get_version(req), "HTTP/1.1") != 0) { + if (strcmp(nng_http_get_version(conn), "HTTP/1.1") != 0) { status = NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP; goto err; } - if (strcmp(nni_http_req_get_method(req), "GET") != 0) { + if (strcmp(nng_http_get_method(conn), "GET") != 0) { // HEAD request. We can't really deal with it. status = NNG_HTTP_STATUS_BAD_REQUEST; goto err; } -#define GETH(h) nni_http_req_get_header(req, h) -#define SETH(h, v) nni_http_res_set_header(res, h, v) - - if ((((ptr = GETH("Content-Length")) != NULL) && (atoi(ptr) > 0)) || - (((ptr = GETH("Transfer-Encoding")) != NULL) && + if ((((ptr = nng_http_get_header(conn, "Content-Length")) != NULL) && + (atoi(ptr) > 0)) || + (((ptr = nng_http_get_header(conn, "Transfer-Encoding")) != + NULL) && (nni_strcasestr(ptr, "chunked") != NULL))) { - status = NNG_HTTP_STATUS_PAYLOAD_TOO_LARGE; + status = NNG_HTTP_STATUS_CONTENT_TOO_LARGE; goto err; } // These headers have to be present. - if (((ptr = GETH("Upgrade")) == NULL) || + if (((ptr = nng_http_get_header(conn, "Upgrade")) == NULL) || (!ws_contains_word(ptr, "websocket")) || - ((ptr = GETH("Connection")) == NULL) || + ((ptr = nng_http_get_header(conn, "Connection")) == NULL) || (!ws_contains_word(ptr, "upgrade")) || - ((ptr = GETH("Sec-WebSocket-Version")) == NULL) || + ((ptr = nng_http_get_header(conn, "Sec-WebSocket-Version")) == + NULL) || (strcmp(ptr, "13") != 0)) { status = NNG_HTTP_STATUS_BAD_REQUEST; goto err; } - if (((ptr = GETH("Sec-WebSocket-Key")) == NULL) || + if (((ptr = nng_http_get_header(conn, "Sec-WebSocket-Key")) == NULL) || (ws_make_accept(ptr, key) != 0)) { status = NNG_HTTP_STATUS_BAD_REQUEST; goto err; @@ -1569,7 +1511,7 @@ ws_handler(nng_http_conn *conn, void *arg, nng_aio *aio) // we need to try to match it to what the handler says we // support. (If no suitable option is found in the handler, we // fail the request.) - proto = GETH("Sec-WebSocket-Protocol"); + proto = nng_http_get_header(conn, "Sec-WebSocket-Protocol"); if (proto == NULL) { if (l->proto != NULL) { status = NNG_HTTP_STATUS_BAD_REQUEST; @@ -1581,23 +1523,13 @@ ws_handler(nng_http_conn *conn, void *arg, nng_aio *aio) 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; - goto err; - } - if ((proto != NULL) && (SETH("Sec-WebSocket-Protocol", proto) != 0)) { - status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; - goto err; - } + nng_http_set_status(conn, NNG_HTTP_STATUS_SWITCHING, NULL); // Set any user supplied headers. This is better than using a hook - // for most things, because it is loads easier. + // for most things, because it is loads easier. Note that websocket + // headers we care about will be overridden below! NNI_LIST_FOREACH (&l->headers, hdr) { - if (SETH(hdr->name, hdr->value) != 0) { + if (nng_http_set_header(conn, hdr->name, hdr->value) != 0) { status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; goto err; } @@ -1608,33 +1540,25 @@ ws_handler(nng_http_conn *conn, void *arg, nng_aio *aio) // need to, because it's much more complex. But if you want to set // up an HTTP Authorization handler this might be the only choice. if (l->hookfn != NULL) { - rv = l->hookfn(l->hookarg, req, res); + rv = l->hookfn(l->hookarg, conn); if (rv != 0) { nni_aio_finish_error(aio, rv); nni_mtx_unlock(&l->mtx); return; } - if (nni_http_res_get_status(res) != - NNG_HTTP_STATUS_SWITCHING) { + if (nng_http_get_status(conn) != NNG_HTTP_STATUS_SWITCHING) { // The hook has decided to give back a // different reply and we are not upgrading // anymore. For example the Origin might not // be permitted, or another level of - // authentication may be required. (Note that - // the hook can also give back various other - // headers, but it would be bad for it to alter - // the websocket mandated headers.) - nni_aio_set_output(aio, 0, res); + // authentication may be required. nni_aio_finish(aio, 0, 0); nni_mtx_unlock(&l->mtx); return; } } -#undef GETH -#undef SETH - // We are good to go, provided we can get the websocket struct, // and send the reply. if ((rv = ws_init(&ws)) != 0) { @@ -1642,8 +1566,6 @@ ws_handler(nng_http_conn *conn, void *arg, nng_aio *aio) goto err; } ws->http = conn; - ws->req = req; - ws->res = res; ws->server = true; ws->maxframe = l->maxframe; ws->fragsize = l->fragsize; @@ -1652,9 +1574,23 @@ ws_handler(nng_http_conn *conn, void *arg, nng_aio *aio) ws->recv_text = l->recv_text; ws->send_text = l->send_text; ws->listener = l; + memcpy(ws->keybuf, key, sizeof(ws->keybuf)); + + nni_http_set_static_header( + conn, &ws->hdrs.connection, "Connection", "Upgrade"); + nni_http_set_static_header( + conn, &ws->hdrs.upgrade, "Upgrade", "websocket"); + nni_http_set_static_header( + conn, &ws->hdrs.wsaccept, "Sec-WebSocket-Accept", ws->keybuf); + if (proto != NULL) { + // NB: we still have the request protocol in the header, so + // that should be fine. + nni_http_set_static_header( + conn, &ws->hdrs.wsproto, "Sec-WebSocket-Protocol", proto); + } nni_list_append(&l->reply, ws); - nni_http_write_res(conn, &ws->httpaio); + nng_http_write_response(conn, &ws->httpaio); (void) nni_http_hijack(conn); nni_aio_set_output(aio, 0, NULL); nni_aio_finish(aio, 0, 0); @@ -1662,10 +1598,9 @@ ws_handler(nng_http_conn *conn, void *arg, nng_aio *aio) return; err: - if ((rv = nni_http_res_set_error(res, status)) != 0) { + if ((rv = nni_http_set_error(conn, status, NULL, NULL)) != 0) { nni_aio_finish_error(aio, rv); } else { - nni_aio_set_output(aio, 0, res); nni_aio_finish(aio, 0, 0); } nni_mtx_unlock(&l->mtx); @@ -1861,20 +1796,6 @@ ws_listener_get_recvmax(void *arg, void *buf, size_t *szp, nni_type t) return (ws_listener_get_size(l, &l->recvmax, buf, szp, t)); } -static int -ws_listener_set_res_headers(void *arg, const void *buf, size_t sz, nni_type t) -{ - nni_ws_listener *l = arg; - int rv; - - if ((rv = ws_check_string(buf, sz, t)) == 0) { - nni_mtx_lock(&l->mtx); - rv = ws_set_headers(&l->headers, buf); - nni_mtx_unlock(&l->mtx); - } - return (rv); -} - static int ws_listener_set_proto(void *arg, const void *buf, size_t sz, nni_type t) { @@ -1995,11 +1916,6 @@ static const nni_option ws_listener_options[] = { .o_set = ws_listener_set_recvmax, .o_get = ws_listener_get_recvmax, }, - { - .o_name = NNG_OPT_WS_RESPONSE_HEADERS, - .o_set = ws_listener_set_res_headers, - // XXX: Get not implemented yet; likely of marginal value. - }, { .o_name = NNG_OPT_WS_PROTOCOL, .o_set = ws_listener_set_proto, @@ -2025,7 +1941,7 @@ ws_listener_set_header(nni_ws_listener *l, const char *name, const void *buf, size_t sz, nni_type t) { int rv; - name += strlen(NNG_OPT_WS_RESPONSE_HEADER); + name += strlen(NNG_OPT_WS_HEADER); if ((rv = ws_check_string(buf, sz, t)) == 0) { nni_mtx_lock(&l->mtx); rv = ws_set_header(&l->headers, name, buf); @@ -2047,7 +1963,7 @@ ws_listener_set( } if (rv == NNG_ENOTSUP) { - if (startswith(name, NNG_OPT_WS_RESPONSE_HEADER)) { + if (startswith(name, NNG_OPT_WS_HEADER)) { rv = ws_listener_set_header(l, name, buf, sz, t); } } @@ -2147,10 +2063,8 @@ ws_conn_cb(void *arg) nni_ws_dialer *d; nni_ws *ws; nni_aio *uaio; - nni_http_req *req = NULL; int rv; uint8_t raw[16]; - char wskey[25]; ws_header *hdr; ws = arg; @@ -2192,35 +2106,36 @@ ws_conn_cb(void *arg) for (int i = 0; i < 16; i++) { raw[i] = (uint8_t) nni_random(); } - nni_base64_encode(raw, 16, wskey, 24); - wskey[24] = '\0'; - - req = nni_http_conn_req(ws->http); + nni_base64_encode(raw, 16, ws->keybuf, 24); + ws->keybuf[24] = '\0'; -#define SETH(h, v) nni_http_req_set_header(req, h, v) - 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) || - ((rv = SETH("Sec-WebSocket-Version", "13")) != 0)) { + if ((rv = nni_http_set_uri( + ws->http, d->url->u_path, d->url->u_query)) != 0) { goto err; } - if ((d->proto != NULL) && - ((rv = SETH("Sec-WebSocket-Protocol", d->proto)) != 0)) { - goto err; + nni_http_set_static_header( + ws->http, &ws->hdrs.connection, "Connection", "Upgrade"); + nni_http_set_static_header( + ws->http, &ws->hdrs.upgrade, "Upgrade", "websocket"); + nni_http_set_static_header( + ws->http, &ws->hdrs.wskey, "Sec-WebSocket-Key", ws->keybuf); + nni_http_set_static_header( + ws->http, &ws->hdrs.wsversion, "Sec-WebSocket-Version", "13"); + + if (d->proto != NULL) { + nni_http_set_static_header(ws->http, &ws->hdrs.wsproto, + "Sec-WebSocket-Protocol", d->proto); } NNI_LIST_FOREACH (&d->headers, hdr) { - if ((rv = SETH(hdr->name, hdr->value)) != 0) { + if ((rv = nni_http_set_header( + ws->http, hdr->name, hdr->value)) != 0) { goto err; } } -#undef SETH - - ws->req = req; - nni_http_write_req(ws->http, req, &ws->httpaio); + nni_http_write_req(ws->http, &ws->httpaio); nni_mtx_unlock(&ws->mtx); return; @@ -2454,20 +2369,6 @@ ws_dialer_get_recvmax(void *arg, void *buf, size_t *szp, nni_type t) return (ws_dialer_get_size(d, &d->recvmax, buf, szp, t)); } -static int -ws_dialer_set_req_headers(void *arg, const void *buf, size_t sz, nni_type t) -{ - nni_ws_dialer *d = arg; - int rv; - - if ((rv = ws_check_string(buf, sz, t)) == 0) { - nni_mtx_lock(&d->mtx); - rv = ws_set_headers(&d->headers, buf); - nni_mtx_unlock(&d->mtx); - } - return (rv); -} - static int ws_dialer_set_proto(void *arg, const void *buf, size_t sz, nni_type t) { @@ -2543,11 +2444,6 @@ static const nni_option ws_dialer_options[] = { .o_set = ws_dialer_set_recvmax, .o_get = ws_dialer_get_recvmax, }, - { - .o_name = NNG_OPT_WS_REQUEST_HEADERS, - .o_set = ws_dialer_set_req_headers, - // XXX: Get not implemented yet; likely of marginal value. - }, { .o_name = NNG_OPT_WS_PROTOCOL, .o_set = ws_dialer_set_proto, @@ -2574,7 +2470,7 @@ ws_dialer_set_header( nni_ws_dialer *d, const char *name, const void *buf, size_t sz, nni_type t) { int rv; - name += strlen(NNG_OPT_WS_REQUEST_HEADER); + name += strlen(NNG_OPT_WS_HEADER); if ((rv = ws_check_string(buf, sz, t)) == 0) { nni_mtx_lock(&d->mtx); rv = ws_set_header(&d->headers, name, buf); @@ -2596,7 +2492,7 @@ ws_dialer_set( } if (rv == NNG_ENOTSUP) { - if (startswith(name, NNG_OPT_WS_REQUEST_HEADER)) { + if (startswith(name, NNG_OPT_WS_HEADER)) { rv = ws_dialer_set_header(d, name, buf, sz, t); } } @@ -2772,35 +2668,11 @@ ws_str_recv(void *arg, nng_aio *aio) nni_mtx_unlock(&ws->mtx); } -static int -ws_get_request_headers(void *arg, void *buf, size_t *szp, nni_type t) -{ - nni_ws *ws = arg; - nni_mtx_lock(&ws->mtx); - if (ws->reqhdrs == NULL) { - ws->reqhdrs = nni_http_req_headers(ws->req); - } - nni_mtx_unlock(&ws->mtx); - return (nni_copyout_str(ws->reqhdrs, buf, szp, t)); -} - -static int -ws_get_response_headers(void *arg, void *buf, size_t *szp, nni_type t) -{ - nni_ws *ws = arg; - nni_mtx_lock(&ws->mtx); - if (ws->reshdrs == NULL) { - ws->reshdrs = nni_http_res_headers(ws->res); - } - nni_mtx_unlock(&ws->mtx); - return (nni_copyout_str(ws->reshdrs, buf, szp, t)); -} - static int ws_get_request_uri(void *arg, void *buf, size_t *szp, nni_type t) { nni_ws *ws = arg; - return (nni_copyout_str(nni_http_req_get_uri(ws->req), buf, szp, t)); + return (nni_copyout_str(nni_http_get_uri(ws->http), buf, szp, t)); } static int @@ -2828,14 +2700,6 @@ ws_get_send_text(void *arg, void *buf, size_t *szp, nni_type t) } static const nni_option ws_options[] = { - { - .o_name = NNG_OPT_WS_REQUEST_HEADERS, - .o_get = ws_get_request_headers, - }, - { - .o_name = NNG_OPT_WS_RESPONSE_HEADERS, - .o_get = ws_get_response_headers, - }, { .o_name = NNG_OPT_WS_REQUEST_URI, .o_get = ws_get_request_uri, @@ -2854,25 +2718,11 @@ static const nni_option ws_options[] = { }; static int -ws_get_req_header( - nni_ws *ws, const char *nm, void *buf, size_t *szp, nni_type t) -{ - const char *s; - nm += strlen(NNG_OPT_WS_REQUEST_HEADER); - s = nni_http_req_get_header(ws->req, nm); - if (s == NULL) { - return (NNG_ENOENT); - } - return (nni_copyout_str(s, buf, szp, t)); -} - -static int -ws_get_res_header( - nni_ws *ws, const char *nm, void *buf, size_t *szp, nni_type t) +ws_get_header(nni_ws *ws, const char *nm, void *buf, size_t *szp, nni_type t) { const char *s; - nm += strlen(NNG_OPT_WS_RESPONSE_HEADER); - s = nni_http_res_get_header(ws->res, nm); + nm += strlen(NNG_OPT_WS_HEADER); + s = nni_http_get_header(ws->http, nm); if (s == NULL) { return (NNG_ENOENT); } @@ -2897,10 +2747,8 @@ ws_str_get(void *arg, const char *nm, void *buf, size_t *szp, nni_type t) } // Check for generic headers... if (rv == NNG_ENOTSUP) { - if (startswith(nm, NNG_OPT_WS_REQUEST_HEADER)) { - rv = ws_get_req_header(ws, nm, buf, szp, t); - } else if (startswith(nm, NNG_OPT_WS_RESPONSE_HEADER)) { - rv = ws_get_res_header(ws, nm, buf, szp, t); + if (startswith(nm, NNG_OPT_WS_HEADER)) { + rv = ws_get_header(ws, nm, buf, szp, t); } } return (rv); diff --git a/src/supplemental/websocket/websocket_test.c b/src/supplemental/websocket/websocket_test.c index 30ebb3f54..98bcf6587 100644 --- a/src/supplemental/websocket/websocket_test.c +++ b/src/supplemental/websocket/websocket_test.c @@ -163,10 +163,10 @@ test_websocket_conn_props(void) NUTS_PASS(nng_stream_dialer_alloc(&d, uri)); NUTS_PASS(nng_stream_dialer_set_string( - d, NNG_OPT_WS_REQUEST_HEADER "NNG-Req", "True")); + d, NNG_OPT_WS_HEADER "NNG-Req", "True")); NUTS_PASS(nng_stream_listener_set_string( - l, NNG_OPT_WS_RESPONSE_HEADER "NNG-Rep", "True")); + l, NNG_OPT_WS_HEADER "NNG-Rep", "True")); nng_stream_dialer_dial(d, daio); nng_stream_listener_accept(l, laio); @@ -203,20 +203,20 @@ test_websocket_conn_props(void) nng_stream_get_size(c1, NNG_OPT_TCP_NODELAY, &sz), NNG_EBADTYPE); NUTS_FAIL(nng_stream_get_string( - c1, NNG_OPT_WS_REQUEST_HEADER "No-Such-Header", &str), + c1, NNG_OPT_WS_HEADER "No-Such-Header", &str), NNG_ENOENT); - NUTS_PASS(nng_stream_get_string( - c1, NNG_OPT_WS_REQUEST_HEADER "NNG-Req", &str)); + NUTS_PASS( + nng_stream_get_string(c1, NNG_OPT_WS_HEADER "NNG-Req", &str)); NUTS_MATCH(str, "True"); nng_strfree(str); - NUTS_PASS(nng_stream_get_string( - c2, NNG_OPT_WS_RESPONSE_HEADER "NNG-Rep", &str)); + NUTS_PASS( + nng_stream_get_string(c2, NNG_OPT_WS_HEADER "NNG-Rep", &str)); NUTS_MATCH(str, "True"); nng_strfree(str); NUTS_PASS(nng_stream_get_string( - c1, NNG_OPT_WS_REQUEST_HEADER "Sec-WebSocket-Version", &str)); + c1, NNG_OPT_WS_HEADER "Sec-WebSocket-Version", &str)); NUTS_TRUE(str != NULL); NUTS_TRUE(strcmp(str, "13") == 0); nng_strfree(str); diff --git a/tests/httpclient.c b/tests/httpclient.c index f3307fc18..b23449f16 100644 --- a/tests/httpclient.c +++ b/tests/httpclient.c @@ -14,8 +14,8 @@ #include #endif +#include #include -#include #include "core/nng_impl.h" @@ -26,7 +26,7 @@ TestMain("HTTP Client", { Convey("Given a TCP connection to example.com", { nng_aio *aio; nng_http_client *cli; - nng_http_conn *http; + nng_http *http; nng_url *url; So(nng_aio_alloc(&aio, NULL, NULL) == 0); @@ -41,31 +41,24 @@ TestMain("HTTP Client", { http = nng_aio_get_output(aio, 0); Reset({ nng_http_client_free(cli); - nng_http_conn_close(http); + nng_http_close(http); nng_aio_free(aio); nng_url_free(url); }); Convey("We can initiate a message", { - nng_http_req *req; - nng_http_res *res; - So(http != NULL); - So(nng_http_req_alloc(&req, url) == 0); - So(nng_http_res_alloc(&res) == 0); - Reset({ - nng_http_req_free(req); - nng_http_res_free(res); - }); - nng_http_conn_write_req(http, req, aio); + So(nng_http_set_uri(http, nng_url_path(url), NULL) == + 0); + nng_http_write_request(http, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - nng_http_conn_read_res(http, res, aio); + nng_http_read_response(http, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - So(nng_http_res_get_status(res) == 200); + So(nng_http_get_status(http) == 200); Convey("The message contents are correct", { void *data; @@ -73,8 +66,8 @@ TestMain("HTTP Client", { size_t sz; nng_iov iov; - cstr = nng_http_res_get_header( - res, "Content-Length"); + cstr = nng_http_get_header( + http, "Content-Length"); So(cstr != NULL); sz = atoi(cstr); So(sz > 0); @@ -90,7 +83,7 @@ TestMain("HTTP Client", { nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - nng_http_conn_read_all(http, aio); + nng_http_read_all(http, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); }); @@ -116,35 +109,34 @@ TestMain("HTTP Client", { }); Convey("One off exchange works", { - nng_http_req *req; - nng_http_res *res; - void *data; - size_t len; + nng_http *conn; + void *data; + size_t len; - So(nng_http_req_alloc(&req, url) == 0); - So(nng_http_res_alloc(&res) == 0); - Reset({ - nng_http_req_free(req); - nng_http_res_free(res); - }); + nng_http_client_connect(cli, aio); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); + conn = nng_aio_get_output(aio, 0); + Reset({ nng_http_close(conn); }); - nng_http_client_transact(cli, req, res, aio); + So(nng_http_set_uri(conn, nng_url_path(url), NULL) == + 0); + + nng_http_transact(conn, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - So(nng_http_res_get_status(res) == 200); - nng_http_res_get_data(res, &data, &len); + So(nng_http_get_status(conn) == 200); + nng_http_get_body(conn, &data, &len); }); Convey("Connection reuse works", { - nng_http_res *res; - nng_http_req *req; - void *data; - size_t len; - nng_http_conn *conn = NULL; + void *data; + size_t len; + nng_http *conn = NULL; Reset({ if (conn != NULL) { - nng_http_conn_close(conn); + nng_http_close(conn); } }); @@ -153,20 +145,22 @@ TestMain("HTTP Client", { So(nng_aio_result(aio) == 0); conn = nng_aio_get_output(aio, 0); - req = nng_http_conn_req(conn); - res = nng_http_conn_res(conn); - So(nng_http_req_set_url(req, url) == 0); - nng_http_conn_transact(conn, aio); + So(nng_http_set_uri(conn, nng_url_path(url), NULL) == + 0); + nng_http_transact(conn, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - So(nng_http_res_get_status(res) == 200); - nng_http_res_get_data(res, &data, &len); + So(nng_http_get_status(conn) == 200); + nng_http_get_body(conn, &data, &len); - nng_http_conn_transact(conn, aio); + nng_http_reset(conn); + So(nng_http_set_uri(conn, nng_url_path(url), NULL) == + 0); + nng_http_transact(conn, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - So(nng_http_res_get_status(res) == 200); - nng_http_res_get_data(res, &data, &len); + So(nng_http_get_status(conn) == 200); + nng_http_get_body(conn, &data, &len); }); }); @@ -178,29 +172,27 @@ TestMain("HTTP Client", { nng_aio *aio; nng_http_client *cli; nng_url *url; - nng_http_req *req; - nng_http_res *res; + nng_http *conn; So(nng_aio_alloc(&aio, NULL, NULL) == 0); So(nng_url_parse(&url, "http://httpbin.org/delay/30") == 0); So(nng_http_client_alloc(&cli, url) == 0); - So(nng_http_req_alloc(&req, url) == 0); - So(nng_http_res_alloc(&res) == 0); - + nng_http_client_connect(cli, aio); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); + conn = nng_aio_get_output(aio, 0); Reset({ nng_http_client_free(cli); nng_url_free(url); nng_aio_free(aio); - nng_http_req_free(req); - nng_http_res_free(res); }); nng_aio_set_timeout(aio, 10); // 10 msec timeout - So(nng_http_req_set_header(req, "Cache-Control", "no-cache") == + So(nng_http_set_header(conn, "Cache-Control", "no-cache") == 0); - nng_http_client_transact(cli, req, res, aio); + nng_http_transact(conn, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == NNG_ETIMEDOUT); }); @@ -227,23 +219,22 @@ TestMain("HTTP Client", { }); Convey("One off exchange works", { - nng_http_req *req; - nng_http_res *res; - void *data; - size_t len; - - So(nng_http_req_alloc(&req, url) == 0); - So(nng_http_res_alloc(&res) == 0); - Reset({ - nng_http_req_free(req); - nng_http_res_free(res); - }); + void *data; + size_t len; + nng_http *conn; - nng_http_client_transact(cli, req, res, aio); + nng_http_client_connect(cli, aio); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); + conn = nng_aio_get_output(aio, 0); + Reset({ nng_http_close(conn); }); + So(nng_http_set_uri(conn, nng_url_path(url), NULL) == + 0); + nng_http_transact(conn, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - So(nng_http_res_get_status(res) == 200); - nng_http_res_get_data(res, &data, &len); + So(nng_http_get_status(conn) == 200); + nng_http_get_body(conn, (void **) &data, &len); }); }); }) diff --git a/tests/wss.c b/tests/wss.c index 4fef74e0b..8b028fbe1 100644 --- a/tests/wss.c +++ b/tests/wss.c @@ -132,7 +132,6 @@ check_props(nng_msg *msg) nng_pipe p; nng_sockaddr la; nng_sockaddr ra; - char *buf; p = nng_msg_get_pipe(msg); So(nng_pipe_id(p) > 0); @@ -143,18 +142,6 @@ check_props(nng_msg *msg) So(nng_pipe_get_addr(p, NNG_OPT_REMADDR, &ra) == 0); So(validloopback(&ra)); - // Request header - buf = NULL; - So(nng_pipe_get_string(p, NNG_OPT_WS_REQUEST_HEADERS, &buf) == 0); - So(strstr(buf, "Sec-WebSocket-Key") != NULL); - nng_strfree(buf); - - // Response header - buf = NULL; - So(nng_pipe_get_string(p, NNG_OPT_WS_RESPONSE_HEADERS, &buf) == 0); - So(strstr(buf, "Sec-WebSocket-Accept") != NULL); - nng_strfree(buf); - return (0); }