aboutsummaryrefslogtreecommitdiff
path: root/src/supplemental
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-01-24 17:38:16 -0800
committerGarrett D'Amore <garrett@damore.org>2018-02-01 16:11:38 -0800
commit3dae30ed5e543dc73fc993334ef56b9b157b9b3c (patch)
treed7e294b5d544aa18e8fc8749abfe605a05fa4bd7 /src/supplemental
parent5914e40c2ff7fcf346c90705785f3fb7650a9fdc (diff)
downloadnng-3dae30ed5e543dc73fc993334ef56b9b157b9b3c.tar.gz
nng-3dae30ed5e543dc73fc993334ef56b9b157b9b3c.tar.bz2
nng-3dae30ed5e543dc73fc993334ef56b9b157b9b3c.zip
fixes #173 Define public HTTP server API
This introduces enough of the HTTP API to support fully server applications, including creation of websocket style protocols, pluggable handlers, and so forth. We have also introduced scatter/gather I/O (rudimentary) for aios, and made other enhancements to the AIO framework. The internals of the AIOs themselves are now fully private, and we have eliminated the aio->a_addr member, with plans to remove the pipe and possibly message members as well. A few other minor issues were found and fixed as well. The HTTP API includes request, response, and connection objects, which can be used with both servers and clients. It also defines the HTTP server and handler objects, which support server applications. Support for client applications will require a client object to be exposed, and that should be happening shortly. None of this is "documented" yet, bug again, we will follow up shortly.
Diffstat (limited to 'src/supplemental')
-rw-r--r--src/supplemental/http/CMakeLists.txt19
-rw-r--r--src/supplemental/http/http.c740
-rw-r--r--src/supplemental/http/http.h226
-rw-r--r--src/supplemental/http/http_client.c (renamed from src/supplemental/http/client.c)20
-rw-r--r--src/supplemental/http/http_conn.c765
-rw-r--r--src/supplemental/http/http_msg.c318
-rw-r--r--src/supplemental/http/http_public.c668
-rw-r--r--src/supplemental/http/http_server.c (renamed from src/supplemental/http/server.c)406
-rw-r--r--src/supplemental/tls/CMakeLists.txt2
-rw-r--r--src/supplemental/tls/mbedtls/tls.c57
-rw-r--r--src/supplemental/tls/tls.h4
-rw-r--r--src/supplemental/websocket/websocket.c177
-rw-r--r--src/supplemental/websocket/websocket.h20
13 files changed, 2045 insertions, 1377 deletions
diff --git a/src/supplemental/http/CMakeLists.txt b/src/supplemental/http/CMakeLists.txt
index 2c8d6a68..9cfbd14a 100644
--- a/src/supplemental/http/CMakeLists.txt
+++ b/src/supplemental/http/CMakeLists.txt
@@ -9,11 +9,18 @@
#
if (NNG_SUPP_HTTP)
-set(HTTP_SOURCES
- supplemental/http/http.c
- supplemental/http/http_msg.c
- supplemental/http/server.c
- supplemental/http/client.c
- supplemental/http/http.h)
+ set(HTTP_DEFINES -DNNG_SUPP_HTTP)
+ set(HTTP_SOURCES
+ supplemental/http/http.h
+ supplemental/http/http_client.c
+ supplemental/http/http_conn.c
+ supplemental/http/http_msg.c
+ supplemental/http/http_public.c
+ supplemental/http/http_server.c)
+else()
+ set(HTTP_SOURCES
+ supplemental/http/http.h
+ supplemental/http/http_public.c)
endif()
+set(NNG_DEFINES ${NNG_DEFINES} ${HTTP_DEFINES} PARENT_SCOPE)
set(NNG_SOURCES ${NNG_SOURCES} ${HTTP_SOURCES} PARENT_SCOPE)
diff --git a/src/supplemental/http/http.c b/src/supplemental/http/http.c
deleted file mode 100644
index 2ba5b274..00000000
--- a/src/supplemental/http/http.c
+++ /dev/null
@@ -1,740 +0,0 @@
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This software is supplied under the terms of the MIT License, a
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-#include <stdbool.h>
-#include <string.h>
-
-#include "core/nng_impl.h"
-#include "supplemental/tls/tls.h"
-
-#include "http.h"
-
-// We insist that individual headers fit in 8K.
-// If you need more than that, you need something we can't do.
-#define HTTP_BUFSIZE 8192
-
-// types of reads
-enum read_flavor {
- HTTP_RD_RAW,
- HTTP_RD_FULL,
- HTTP_RD_REQ,
- HTTP_RD_RES,
-};
-
-enum write_flavor {
- HTTP_WR_RAW,
- HTTP_WR_FULL,
- HTTP_WR_REQ,
- HTTP_WR_RES,
-};
-
-typedef struct nni_http_tran {
- void (*h_read)(void *, nni_aio *);
- void (*h_write)(void *, nni_aio *);
- int (*h_sock_addr)(void *, nni_sockaddr *);
- int (*h_peer_addr)(void *, nni_sockaddr *);
- bool (*h_verified)(void *);
- void (*h_close)(void *);
- void (*h_fini)(void *);
-} nni_http_tran;
-
-#define SET_RD_FLAVOR(aio, f) (aio)->a_prov_extra[0] = ((void *) (intptr_t)(f))
-#define GET_RD_FLAVOR(aio) (int) ((intptr_t) aio->a_prov_extra[0])
-#define SET_WR_FLAVOR(aio, f) (aio)->a_prov_extra[0] = ((void *) (intptr_t)(f))
-#define GET_WR_FLAVOR(aio) (int) ((intptr_t) aio->a_prov_extra[0])
-
-struct nni_http {
- void *sock;
- void (*rd)(void *, nni_aio *);
- void (*wr)(void *, nni_aio *);
- int (*sock_addr)(void *, nni_sockaddr *);
- int (*peer_addr)(void *, nni_sockaddr *);
- bool (*verified)(void *);
- void (*close)(void *);
- void (*fini)(void *);
-
- bool closed;
-
- nni_list rdq; // high level http read requests
- nni_list wrq; // high level http write requests
-
- nni_aio *rd_uaio; // user aio for read
- nni_aio *wr_uaio; // user aio for write
- nni_aio *rd_aio; // bottom half read operations
- nni_aio *wr_aio; // bottom half write operations
-
- nni_mtx mtx;
-
- uint8_t *rd_buf;
- size_t rd_get;
- size_t rd_put;
- size_t rd_bufsz;
-};
-
-static void
-http_close(nni_http *http)
-{
- // Call with lock held.
- nni_aio *aio;
-
- if (http->closed) {
- return;
- }
-
- http->closed = true;
- if (nni_list_first(&http->wrq)) {
- nni_aio_cancel(http->wr_aio, NNG_ECLOSED);
- // Abort all operations except the one in flight.
- while ((aio = nni_list_last(&http->wrq)) !=
- nni_list_first(&http->wrq)) {
- nni_aio_list_remove(aio);
- nni_aio_finish_error(aio, NNG_ECLOSED);
- }
- }
- if (nni_list_first(&http->rdq)) {
- nni_aio_cancel(http->rd_aio, NNG_ECLOSED);
- while ((aio = nni_list_last(&http->rdq)) !=
- nni_list_first(&http->rdq)) {
- nni_aio_list_remove(aio);
- nni_aio_finish_error(aio, NNG_ECLOSED);
- }
- }
-
- if (http->sock != NULL) {
- http->close(http->sock);
- }
-}
-
-void
-nni_http_close(nni_http *http)
-{
- nni_mtx_lock(&http->mtx);
- http_close(http);
- nni_mtx_unlock(&http->mtx);
-}
-
-// http_rd_buf attempts to satisfy the read from data in the buffer.
-static int
-http_rd_buf(nni_http *http, nni_aio *aio)
-{
- size_t cnt = http->rd_put - http->rd_get;
- size_t n;
- uint8_t *rbuf = http->rd_buf;
- int i;
- int rv;
- bool raw = false;
-
- rbuf += http->rd_get;
-
- switch (GET_RD_FLAVOR(aio)) {
- case HTTP_RD_RAW:
- raw = true; // FALLTHROUGH
- case HTTP_RD_FULL:
- for (i = 0; (aio->a_niov != 0) && (cnt != 0); i++) {
- // Pull up data from the buffer if possible.
- n = aio->a_iov[0].iov_len;
- if (n > cnt) {
- n = cnt;
- }
- memcpy(aio->a_iov[0].iov_buf, rbuf, n);
- aio->a_iov[0].iov_len -= n;
- NNI_INCPTR(aio->a_iov[0].iov_buf, n);
- http->rd_get += n;
- rbuf += n;
- aio->a_count += n;
- cnt -= n;
-
- if (aio->a_iov[0].iov_len == 0) {
- aio->a_niov--;
- for (i = 0; i < aio->a_niov; i++) {
- aio->a_iov[i] = aio->a_iov[i + 1];
- }
- }
- }
-
- if ((aio->a_niov == 0) || (raw && (aio->a_count != 0))) {
- // Finished the read. (We are finished if we either
- // got *all* the data, or we got *some* data for
- // a raw read.)
- return (0);
- }
-
- // No more data left in the buffer, so use a physio.
- // (Note that we get here if we either have not completed
- // a full transaction on a FULL read, or were not even able
- // to get *any* data for a partial RAW read.)
- for (i = 0; i < aio->a_niov; i++) {
- http->rd_aio->a_iov[i] = aio->a_iov[i];
- }
- nni_aio_set_data(http->rd_aio, 1, NULL);
- http->rd_aio->a_niov = aio->a_niov;
- http->rd(http->sock, http->rd_aio);
- return (NNG_EAGAIN);
-
- case HTTP_RD_REQ:
- rv = nni_http_req_parse(aio->a_prov_extra[1], rbuf, cnt, &n);
- http->rd_get += n;
- if (http->rd_get == http->rd_put) {
- http->rd_get = http->rd_put = 0;
- }
- if (rv == NNG_EAGAIN) {
- http->rd_aio->a_niov = 1;
- http->rd_aio->a_iov[0].iov_buf =
- http->rd_buf + http->rd_put;
- http->rd_aio->a_iov[0].iov_len =
- http->rd_bufsz - http->rd_put;
- nni_aio_set_data(http->rd_aio, 1, aio);
- http->rd(http->sock, http->rd_aio);
- }
- return (rv);
-
- case HTTP_RD_RES:
- rv = nni_http_res_parse(aio->a_prov_extra[1], rbuf, cnt, &n);
- http->rd_get += n;
- if (http->rd_get == http->rd_put) {
- http->rd_get = http->rd_put = 0;
- }
- if (rv == NNG_EAGAIN) {
- http->rd_aio->a_niov = 1;
- http->rd_aio->a_iov[0].iov_buf =
- http->rd_buf + http->rd_put;
- http->rd_aio->a_iov[0].iov_len =
- http->rd_bufsz - http->rd_put;
- nni_aio_set_data(http->rd_aio, 1, aio);
- http->rd(http->sock, http->rd_aio);
- }
- return (rv);
- }
- return (NNG_EINVAL);
-}
-
-static void
-http_rd_start(nni_http *http)
-{
- for (;;) {
- nni_aio *aio;
- int rv;
-
- if ((aio = http->rd_uaio) == NULL) {
- if ((aio = nni_list_first(&http->rdq)) == NULL) {
- // No more stuff waiting for read.
- return;
- }
- nni_list_remove(&http->rdq, aio);
- http->rd_uaio = aio;
- }
-
- if (http->closed) {
- rv = NNG_ECLOSED;
- } else {
- rv = http_rd_buf(http, aio);
- }
- switch (rv) {
- case NNG_EAGAIN:
- return;
- case 0:
- http->rd_uaio = NULL;
- nni_aio_finish(aio, 0, aio->a_count);
- break;
- default:
- http->rd_uaio = NULL;
- nni_aio_finish_error(aio, rv);
- http_close(http);
- break;
- }
- }
-}
-
-static void
-http_rd_cb(void *arg)
-{
- nni_http *http = arg;
- nni_aio * aio = http->rd_aio;
- nni_aio * uaio;
- size_t cnt;
- int rv;
-
- nni_mtx_lock(&http->mtx);
-
- if ((rv = nni_aio_result(aio)) != 0) {
- if ((uaio = http->rd_uaio) != NULL) {
- http->rd_uaio = NULL;
- nni_aio_finish_error(uaio, rv);
- }
- http_close(http);
- nni_mtx_unlock(&http->mtx);
- return;
- }
-
- cnt = nni_aio_count(aio);
-
- // If we were reading into the buffer, then advance location(s).
- if ((uaio = nni_aio_get_data(aio, 1)) != NULL) {
- http->rd_put += cnt;
- NNI_ASSERT(http->rd_put <= http->rd_bufsz);
- http_rd_start(http);
- nni_mtx_unlock(&http->mtx);
- return;
- }
-
- // Otherwise we are completing a USER request, and there should
- // be no data left in the user buffer.
- NNI_ASSERT(http->rd_get == http->rd_put);
-
- if ((uaio = http->rd_uaio) == NULL) {
- // This indicates that a read request was canceled. This
- // can occur only when shutting down, really.
- nni_mtx_unlock(&http->mtx);
- return;
- }
-
- for (int i = 0; (uaio->a_niov != 0) && (cnt != 0); i++) {
- // Pull up data from the buffer if possible.
- size_t n = uaio->a_iov[0].iov_len;
- if (n > cnt) {
- n = cnt;
- }
- uaio->a_iov[0].iov_len -= n;
- NNI_INCPTR(uaio->a_iov[0].iov_buf, n);
- uaio->a_count += n;
- cnt -= n;
-
- if (uaio->a_iov[0].iov_len == 0) {
- uaio->a_niov--;
- for (i = 0; i < uaio->a_niov; i++) {
- uaio->a_iov[i] = uaio->a_iov[i + 1];
- }
- }
- }
-
- // Resubmit the start. This will attempt to consume data
- // from the read buffer (there won't be any), and then either
- // complete the I/O (for HTTP_RD_RAW, or if there is nothing left),
- // or submit another physio.
- http_rd_start(http);
- nni_mtx_unlock(&http->mtx);
-}
-
-static void
-http_rd_cancel(nni_aio *aio, int rv)
-{
- nni_http *http = aio->a_prov_data;
-
- nni_mtx_lock(&http->mtx);
- if (aio == http->rd_uaio) {
- http->rd_uaio = NULL;
- nni_aio_cancel(http->rd_aio, rv);
- nni_aio_finish_error(aio, rv);
- } else if (nni_aio_list_active(aio)) {
- nni_aio_list_remove(aio);
- nni_aio_finish_error(aio, rv);
- }
- nni_mtx_unlock(&http->mtx);
-}
-
-static void
-http_rd_submit(nni_http *http, nni_aio *aio)
-{
- if (nni_aio_start(aio, http_rd_cancel, http) != 0) {
- return;
- }
- if (http->closed) {
- nni_aio_finish_error(aio, NNG_ECLOSED);
- return;
- }
- nni_list_append(&http->rdq, aio);
- if (http->rd_uaio == NULL) {
- http_rd_start(http);
- }
-}
-
-static void
-http_wr_start(nni_http *http)
-{
- nni_aio *aio;
-
- if ((aio = http->wr_uaio) == NULL) {
- if ((aio = nni_list_first(&http->wrq)) == NULL) {
- // No more stuff waiting for read.
- return;
- }
- nni_list_remove(&http->wrq, aio);
- http->wr_uaio = aio;
- }
-
- for (int i = 0; i < aio->a_niov; i++) {
- http->wr_aio->a_iov[i] = aio->a_iov[i];
- }
- http->wr_aio->a_niov = aio->a_niov;
- http->wr(http->sock, http->wr_aio);
-}
-
-static void
-http_wr_cb(void *arg)
-{
- nni_http *http = arg;
- nni_aio * aio = http->wr_aio;
- nni_aio * uaio;
- int rv;
- size_t n;
-
- nni_mtx_lock(&http->mtx);
-
- uaio = http->wr_uaio;
-
- if ((rv = nni_aio_result(aio)) != 0) {
- // We failed to complete the aio.
- if (uaio != NULL) {
- http->wr_uaio = NULL;
- nni_aio_finish_error(uaio, rv);
- }
- http_close(http);
- nni_mtx_unlock(&http->mtx);
- return;
- }
-
- if (uaio == NULL) {
- // Write canceled? This happens pretty much only during
- // shutdown/close, so we don't want to resume writing.
- // The stream is probably corrupted at this point anyway.
- nni_mtx_unlock(&http->mtx);
- return;
- }
-
- n = nni_aio_count(aio);
- uaio->a_count += n;
- if (GET_WR_FLAVOR(uaio) == HTTP_WR_RAW) {
- // For raw data, we just send partial completion
- // notices to the consumer.
- goto done;
- }
- while (n) {
- NNI_ASSERT(aio->a_niov != 0);
-
- if (aio->a_iov[0].iov_len > n) {
- aio->a_iov[0].iov_len -= n;
- NNI_INCPTR(aio->a_iov[0].iov_buf, n);
- break;
- }
- n -= aio->a_iov[0].iov_len;
- for (int i = 0; i < aio->a_niov; i++) {
- aio->a_iov[i] = aio->a_iov[i + 1];
- }
- aio->a_niov--;
- }
- if ((aio->a_niov != 0) && (aio->a_iov[0].iov_len != 0)) {
- // We have more to transmit - start another and leave
- // (we will get called again when it is done).
- http->wr(http->sock, aio);
- nni_mtx_unlock(&http->mtx);
- return;
- }
-
-done:
- http->wr_uaio = NULL;
- nni_aio_finish(uaio, 0, uaio->a_count);
-
- // Start next write if another is ready.
- http_wr_start(http);
-
- nni_mtx_unlock(&http->mtx);
-}
-
-static void
-http_wr_cancel(nni_aio *aio, int rv)
-{
- nni_http *http = aio->a_prov_data;
-
- nni_mtx_lock(&http->mtx);
- if (aio == http->wr_uaio) {
- http->wr_uaio = NULL;
- nni_aio_cancel(http->wr_aio, rv);
- nni_aio_finish_error(aio, rv);
- } else if (nni_aio_list_active(aio)) {
- nni_aio_list_remove(aio);
- nni_aio_finish_error(aio, rv);
- }
- nni_mtx_unlock(&http->mtx);
-}
-
-static void
-http_wr_submit(nni_http *http, nni_aio *aio)
-{
- if (nni_aio_start(aio, http_wr_cancel, http) != 0) {
- return;
- }
- if (http->closed) {
- nni_aio_finish_error(aio, NNG_ECLOSED);
- return;
- }
- nni_list_append(&http->wrq, aio);
- if (http->wr_uaio == NULL) {
- http_wr_start(http);
- }
-}
-
-void
-nni_http_read_req(nni_http *http, nni_http_req *req, nni_aio *aio)
-{
- SET_RD_FLAVOR(aio, HTTP_RD_REQ);
- aio->a_prov_extra[1] = req;
-
- nni_mtx_lock(&http->mtx);
- http_rd_submit(http, aio);
- nni_mtx_unlock(&http->mtx);
-}
-
-void
-nni_http_read_res(nni_http *http, nni_http_res *res, nni_aio *aio)
-{
- SET_RD_FLAVOR(aio, HTTP_RD_RES);
- aio->a_prov_extra[1] = res;
-
- nni_mtx_lock(&http->mtx);
- http_rd_submit(http, aio);
- nni_mtx_unlock(&http->mtx);
-}
-
-void
-nni_http_read_full(nni_http *http, nni_aio *aio)
-{
- aio->a_count = 0;
- SET_RD_FLAVOR(aio, HTTP_RD_FULL);
- aio->a_prov_extra[1] = NULL;
-
- nni_mtx_lock(&http->mtx);
- http_rd_submit(http, aio);
- nni_mtx_unlock(&http->mtx);
-}
-
-void
-nni_http_read(nni_http *http, nni_aio *aio)
-{
- SET_RD_FLAVOR(aio, HTTP_RD_RAW);
- aio->a_prov_extra[1] = NULL;
-
- nni_mtx_lock(&http->mtx);
- http_rd_submit(http, aio);
- nni_mtx_unlock(&http->mtx);
-}
-
-void
-nni_http_write_req(nni_http *http, nni_http_req *req, nni_aio *aio)
-{
- int rv;
- void * buf;
- size_t bufsz;
-
- if ((rv = nni_http_req_get_buf(req, &buf, &bufsz)) != 0) {
- nni_aio_finish_error(aio, rv);
- return;
- }
- aio->a_niov = 1;
- aio->a_iov[0].iov_len = bufsz;
- aio->a_iov[0].iov_buf = buf;
- SET_WR_FLAVOR(aio, HTTP_WR_REQ);
-
- nni_mtx_lock(&http->mtx);
- http_wr_submit(http, aio);
- nni_mtx_unlock(&http->mtx);
-}
-
-void
-nni_http_write_res(nni_http *http, nni_http_res *res, nni_aio *aio)
-{
- int rv;
- void * buf;
- size_t bufsz;
-
- if ((rv = nni_http_res_get_buf(res, &buf, &bufsz)) != 0) {
- nni_aio_finish_error(aio, rv);
- return;
- }
- aio->a_niov = 1;
- aio->a_iov[0].iov_len = bufsz;
- aio->a_iov[0].iov_buf = buf;
- SET_WR_FLAVOR(aio, HTTP_WR_RES);
-
- nni_mtx_lock(&http->mtx);
- http_wr_submit(http, aio);
- nni_mtx_unlock(&http->mtx);
-}
-
-// Writer. As with nni_http_conn_write, this is used to write data on
-// a connection that has been "upgraded" (e.g. transformed to
-// websocket). It is an error to perform other HTTP exchanges on an
-// connection after this method is called. (This mostly exists to
-// support websocket.)
-void
-nni_http_write(nni_http *http, nni_aio *aio)
-{
- SET_WR_FLAVOR(aio, HTTP_WR_RAW);
-
- nni_mtx_lock(&http->mtx);
- http_wr_submit(http, aio);
- nni_mtx_unlock(&http->mtx);
-}
-
-void
-nni_http_write_full(nni_http *http, nni_aio *aio)
-{
- SET_WR_FLAVOR(aio, HTTP_WR_FULL);
-
- nni_mtx_lock(&http->mtx);
- http_wr_submit(http, aio);
- nni_mtx_unlock(&http->mtx);
-}
-
-int
-nni_http_sock_addr(nni_http *http, nni_sockaddr *sa)
-{
- int rv;
- nni_mtx_lock(&http->mtx);
- rv = http->closed ? NNG_ECLOSED : http->sock_addr(http->sock, sa);
- nni_mtx_unlock(&http->mtx);
- return (rv);
-}
-
-int
-nni_http_peer_addr(nni_http *http, nni_sockaddr *sa)
-{
- int rv;
- nni_mtx_lock(&http->mtx);
- rv = http->closed ? NNG_ECLOSED : http->peer_addr(http->sock, sa);
- nni_mtx_unlock(&http->mtx);
- return (rv);
-}
-
-bool
-nni_http_tls_verified(nni_http *http)
-{
- bool rv;
-
- nni_mtx_lock(&http->mtx);
- rv = http->closed ? false : http->verified(http->sock);
- nni_mtx_unlock(&http->mtx);
- return (rv);
-}
-
-void
-nni_http_fini(nni_http *http)
-{
- nni_mtx_lock(&http->mtx);
- http_close(http);
- if ((http->sock != NULL) && (http->fini != NULL)) {
- http->fini(http->sock);
- http->sock = NULL;
- }
- nni_mtx_unlock(&http->mtx);
- nni_aio_stop(http->wr_aio);
- nni_aio_stop(http->rd_aio);
- nni_aio_fini(http->wr_aio);
- nni_aio_fini(http->rd_aio);
- nni_free(http->rd_buf, http->rd_bufsz);
- nni_mtx_fini(&http->mtx);
- NNI_FREE_STRUCT(http);
-}
-
-static int
-http_init(nni_http **httpp, nni_http_tran *tran, void *data)
-{
- nni_http *http;
- int rv;
-
- if ((http = NNI_ALLOC_STRUCT(http)) == NULL) {
- return (NNG_ENOMEM);
- }
- http->rd_bufsz = HTTP_BUFSIZE;
- if ((http->rd_buf = nni_alloc(http->rd_bufsz)) == NULL) {
- NNI_FREE_STRUCT(http);
- return (NNG_ENOMEM);
- }
- nni_mtx_init(&http->mtx);
- nni_aio_list_init(&http->rdq);
- nni_aio_list_init(&http->wrq);
-
- http->sock = data;
- http->rd_bufsz = HTTP_BUFSIZE;
- http->rd = tran->h_read;
- http->wr = tran->h_write;
- http->close = tran->h_close;
- http->fini = tran->h_fini;
- http->sock_addr = tran->h_sock_addr;
- http->peer_addr = tran->h_peer_addr;
- http->verified = tran->h_verified;
-
- if (((rv = nni_aio_init(&http->wr_aio, http_wr_cb, http)) != 0) ||
- ((rv = nni_aio_init(&http->rd_aio, http_rd_cb, http)) != 0)) {
- nni_http_fini(http);
- return (rv);
- }
-
- *httpp = http;
-
- return (0);
-}
-
-static bool
-nni_http_verified_tcp(void *arg)
-{
- NNI_ARG_UNUSED(arg);
- return (false);
-}
-
-static nni_http_tran http_tcp_ops = {
- .h_read = (void *) nni_plat_tcp_pipe_recv,
- .h_write = (void *) nni_plat_tcp_pipe_send,
- .h_close = (void *) nni_plat_tcp_pipe_close,
- .h_fini = (void *) nni_plat_tcp_pipe_fini,
- .h_sock_addr = (void *) nni_plat_tcp_pipe_sockname,
- .h_peer_addr = (void *) nni_plat_tcp_pipe_peername,
- .h_verified = nni_http_verified_tcp,
-};
-
-int
-nni_http_init_tcp(nni_http **hpp, void *tcp)
-{
- return (http_init(hpp, &http_tcp_ops, tcp));
-}
-
-#ifdef NNG_SUPP_TLS
-static nni_http_tran http_tls_ops = {
- .h_read = (void *) nni_tls_recv,
- .h_write = (void *) nni_tls_send,
- .h_close = (void *) nni_tls_close,
- .h_fini = (void *) nni_tls_fini,
- .h_sock_addr = (void *) nni_tls_sockname,
- .h_peer_addr = (void *) nni_tls_peername,
- .h_verified = (void *) nni_tls_verified,
-};
-
-int
-nni_http_init_tls(nni_http **hpp, nng_tls_config *cfg, void *tcp)
-{
- nni_tls *tls;
- int rv;
-
- if ((rv = nni_tls_init(&tls, cfg, tcp)) != 0) {
- nni_plat_tcp_pipe_fini(tcp);
- return (rv);
- }
-
- return (http_init(hpp, &http_tls_ops, tls));
-}
-#else
-int
-nni_http_init_tls(nni_http **hpp, nng_tls_config *cfg, void *tcp)
-{
- NNI_ARG_UNUSED(hpp);
- NNI_ARG_UNUSED(cfg);
- nni_plat_tcp_pipe_fini(tcp);
- return (NNG_ENOTSUP);
-}
-#endif // NNG_SUPP_TLS \ No newline at end of file
diff --git a/src/supplemental/http/http.h b/src/supplemental/http/http.h
index 93a94049..e44ddc76 100644
--- a/src/supplemental/http/http.h
+++ b/src/supplemental/http/http.h
@@ -11,113 +11,34 @@
#ifndef NNG_SUPPLEMENTAL_HTTP_HTTP_H
#define NNG_SUPPLEMENTAL_HTTP_HTTP_H
-#include <stdbool.h>
-
-typedef struct nni_http_res nni_http_res;
-typedef struct nni_http_entity nni_http_entity;
+#include "core/nng_impl.h"
-typedef struct nni_http_req nni_http_req;
+#include <stdbool.h>
-extern int nni_http_req_init(nni_http_req **);
-extern void nni_http_req_fini(nni_http_req *);
-extern void nni_http_req_reset(nni_http_req *);
-extern int nni_http_req_set_header(nni_http_req *, const char *, const char *);
-extern int nni_http_req_add_header(nni_http_req *, const char *, const char *);
-extern int nni_http_req_del_header(nni_http_req *, const char *);
-extern int nni_http_req_get_buf(nni_http_req *, void **, size_t *);
-extern int 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 const char *nni_http_req_get_header(nni_http_req *, const char *);
-extern const char *nni_http_req_get_header(nni_http_req *, const char *);
-extern const char *nni_http_req_get_version(nni_http_req *);
-extern const char *nni_http_req_get_uri(nni_http_req *);
-extern const char *nni_http_req_get_method(nni_http_req *);
+typedef struct nng_http_req nni_http_req;
+typedef struct nng_http_res nni_http_res;
+typedef struct nng_http_conn nni_http_conn;
+typedef struct nng_http_handler nni_http_handler;
+typedef struct nng_http_server nni_http_server;
+
+// These functions are private to the internal framework, and really should
+// not be used elsewhere.
+extern int 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 int nni_http_res_init(nni_http_res **);
-extern void nni_http_res_fini(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_set_header(nni_http_res *, const char *, const char *);
-extern int nni_http_res_add_header(nni_http_res *, const char *, const char *);
-extern int nni_http_res_del_header(nni_http_res *, const char *);
-extern int nni_http_res_set_version(nni_http_res *, const char *);
-extern int nni_http_res_set_status(nni_http_res *, int, const char *);
-extern const char *nni_http_res_get_header(nni_http_res *, const char *);
-extern const char *nni_http_res_get_version(nni_http_res *);
-extern const char *nni_http_res_get_reason(nni_http_res *);
-extern int nni_http_res_get_status(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 int nni_http_res_set_data(nni_http_res *, const void *, size_t);
-extern int nni_http_res_copy_data(nni_http_res *, const void *, size_t);
-extern int nni_http_res_alloc_data(nni_http_res *, size_t);
extern void nni_http_res_get_data(nni_http_res *, void **, size_t *);
-extern int nni_http_res_init_error(nni_http_res **, uint16_t);
extern char *nni_http_res_headers(nni_http_res *);
-// HTTP status codes. This list is not exhaustive.
-enum { NNI_HTTP_STATUS_CONTINUE = 100,
- NNI_HTTP_STATUS_SWITCHING = 101,
- NNI_HTTP_STATUS_PROCESSING = 102,
- NNI_HTTP_STATUS_OK = 200,
- NNI_HTTP_STATUS_CREATED = 201,
- NNI_HTTP_STATUS_ACCEPTED = 202,
- NNI_HTTP_STATUS_NOT_AUTHORITATIVE = 203,
- NNI_HTTP_STATUS_NO_CONTENT = 204,
- NNI_HTTP_STATUS_RESET_CONTENT = 205,
- NNI_HTTP_STATUS_PARTIAL_CONTENT = 206,
- NNI_HTTP_STATUS_MULTI_STATUS = 207,
- NNI_HTTP_STATUS_ALREADY_REPORTED = 208,
- NNI_HTTP_STATUS_IM_USED = 226,
- NNI_HTTP_STATUS_MULTIPLE_CHOICES = 300,
- NNI_HTTP_STATUS_STATUS_MOVED_PERMANENTLY = 301,
- NNI_HTTP_STATUS_FOUND = 302,
- NNI_HTTP_STATUS_SEE_OTHER = 303,
- NNI_HTTP_STATUS_NOT_MODIFIED = 304,
- NNI_HTTP_STATUS_USE_PROXY = 305,
- NNI_HTTP_STATUS_TEMPORARY_REDIRECT = 307,
- NNI_HTTP_STATUS_PERMANENT_REDIRECT = 308,
- NNI_HTTP_STATUS_BAD_REQUEST = 400,
- NNI_HTTP_STATUS_UNAUTHORIZED = 401,
- NNI_HTTP_STATUS_PAYMENT_REQUIRED = 402,
- NNI_HTTP_STATUS_FORBIDDEN = 403,
- NNI_HTTP_STATUS_NOT_FOUND = 404,
- NNI_HTTP_STATUS_METHOD_NOT_ALLOWED = 405,
- NNI_HTTP_STATUS_NOT_ACCEPTABLE = 406,
- NNI_HTTP_STATUS_PROXY_AUTH_REQUIRED = 407,
- NNI_HTTP_STATUS_REQUEST_TIMEOUT = 408,
- NNI_HTTP_STATUS_CONFLICT = 409,
- NNI_HTTP_STATUS_GONE = 410,
- NNI_HTTP_STATUS_LENGTH_REQUIRED = 411,
- NNI_HTTP_STATUS_PRECONDITION_FAILED = 412,
- NNI_HTTP_STATUS_PAYLOAD_TOO_LARGE = 413,
- NNI_HTTP_STATUS_URI_TOO_LONG = 414,
- NNI_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
- NNI_HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416,
- NNI_HTTP_STATUS_EXPECTATION_FAILED = 417,
- NNI_HTTP_STATUS_TEAPOT = 418,
- NNI_HTTP_STATUS_UNPROCESSABLE_ENTITY = 422,
- NNI_HTTP_STATUS_LOCKED = 423,
- NNI_HTTP_STATUS_FAILED_DEPENDENCY = 424,
- NNI_HTTP_STATUS_UPGRADE_REQUIRED = 426,
- NNI_HTTP_STATUS_PRECONDITION_REQUIRED = 428,
- NNI_HTTP_STATUS_TOO_MANY_REQUESTS = 429,
- NNI_HTTP_STATUS_HEADERS_TOO_LARGE = 431,
- NNI_HTTP_STATUS_UNAVAIL_LEGAL_REASONS = 451,
- NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500,
- NNI_HTTP_STATUS_NOT_IMPLEMENTED = 501,
- NNI_HTTP_STATUS_BAD_GATEWAY = 502,
- NNI_HTTP_STATUS_SERVICE_UNAVAILABLE = 503,
- NNI_HTTP_STATUS_GATEWAY_TIMEOUT = 504,
- NNI_HTTP_STATUS_HTTP_VERSION_NOT_SUPP = 505,
- NNI_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506,
- NNI_HTTP_STATUS_INSUFFICIENT_STORAGE = 507,
- NNI_HTTP_STATUS_LOOP_DETECTED = 508,
- NNI_HTTP_STATUS_NOT_EXTENDED = 510,
- NNI_HTTP_STATUS_NETWORK_AUTH_REQUIRED = 511,
-};
+// Private to the server. (Used to support session hijacking.)
+extern void nni_http_conn_set_ctx(nni_http_conn *, void *);
+extern void *nni_http_conn_get_ctx(nni_http_conn *);
// An HTTP connection is a connection over which messages are exchanged.
// Generally, clients send request messages, and then read responses.
@@ -132,39 +53,65 @@ enum { NNI_HTTP_STATUS_CONTINUE = 100,
//
// Any error on the connection, including cancellation of a request, is fatal
// the connection.
-typedef struct nni_http nni_http;
// 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_init_tcp(nni_http **, void *);
-extern int nni_http_init_tls(nni_http **, nng_tls_config *, void *);
+extern int nni_http_conn_init_tcp(nni_http_conn **, void *);
+extern int nni_http_conn_init_tls(nni_http_conn **, nng_tls_config *, void *);
-extern void nni_http_close(nni_http *);
-extern void nni_http_fini(nni_http *);
+extern void nni_http_conn_close(nni_http_conn *);
+extern void nni_http_conn_fini(nni_http_conn *);
// Reading messages -- the caller must supply a preinitialized (but otherwise
// idle) message. We recommend the caller store this in the aio's user data.
// Note that the iovs of the aio's are clobbered by these methods -- callers
// must not use them for any other purpose.
-extern void nni_http_write_req(nni_http *, nni_http_req *, nni_aio *);
-extern void nni_http_write_res(nni_http *, nni_http_res *, nni_aio *);
-extern void nni_http_read_req(nni_http *, nni_http_req *, nni_aio *);
-extern void nni_http_read_res(nni_http *, nni_http_res *, nni_aio *);
+extern int nni_http_req_alloc(nni_http_req **, const nni_url *);
+extern int nni_http_res_alloc(nni_http_res **);
+extern int nni_http_res_alloc_error(nni_http_res **, uint16_t);
+extern void nni_http_req_free(nni_http_req *);
+extern void nni_http_res_free(nni_http_res *);
+extern void nni_http_write_req(nni_http_conn *, nni_http_req *, nni_aio *);
+extern void nni_http_write_res(nni_http_conn *, nni_http_res *, nni_aio *);
+extern void nni_http_read_req(nni_http_conn *, nni_http_req *, nni_aio *);
+extern void nni_http_read_res(nni_http_conn *, nni_http_res *, nni_aio *);
+
+extern const char *nni_http_req_get_header(nni_http_req *, const char *);
+extern const char *nni_http_res_get_header(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 const char *nni_http_req_get_method(nni_http_req *);
+extern const char *nni_http_req_get_version(nni_http_req *);
+extern const char *nni_http_req_get_uri(nni_http_req *);
+extern int 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 uint16_t nni_http_res_get_status(nni_http_res *);
+extern int nni_http_res_set_status(nni_http_res *, uint16_t);
+extern const char *nni_http_res_get_version(nni_http_res *);
+extern int nni_http_res_set_version(nni_http_res *, const char *);
+extern const char *nni_http_res_get_reason(nni_http_res *);
+extern int nni_http_res_set_reason(nni_http_res *, const char *);
-extern void nni_http_read(nni_http *, nni_aio *);
-extern void nni_http_read_full(nni_http *, nni_aio *);
-extern void nni_http_write(nni_http *, nni_aio *);
-extern void nni_http_write_full(nni_http *, nni_aio *);
-extern int nni_http_sock_addr(nni_http *, nni_sockaddr *);
-extern int nni_http_peer_addr(nni_http *, nni_sockaddr *);
+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_sock_addr(nni_http_conn *, nni_sockaddr *);
+extern int nni_http_peer_addr(nni_http_conn *, nni_sockaddr *);
// nni_tls_http_verified returns true if the peer has been verified using TLS.
-extern bool nni_http_tls_verified(nni_http *);
-
-typedef struct nni_http_server nni_http_server;
-typedef struct nni_http_handler nni_http_handler;
+extern bool nni_http_tls_verified(nni_http_conn *);
// 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
@@ -174,7 +121,7 @@ typedef struct nni_http_handler nni_http_handler;
// a restricted binding is required, we recommend using a URL consisting
// of an empty host name, such as http:// or https:// -- this would
// convert to binding to the default port on all interfaces on the host.
-extern int nni_http_server_init(nni_http_server **, nni_url *);
+extern int nni_http_server_init(nni_http_server **, const nni_url *);
// nni_http_server_fini drops the reference count on the server, and
// if this was the last reference, closes down the server and frees
@@ -188,8 +135,10 @@ extern void nni_http_server_fini(nni_http_server *);
extern int nni_http_server_add_handler(nni_http_server *, nni_http_handler *);
// nni_http_del_handler removes the given handler. The caller is
-// responsible for finalizing it afterwards.
-extern void nni_http_server_del_handler(nni_http_server *, nni_http_handler *);
+// responsible for finalizing it afterwards. If the handler was not found
+// (not registered), NNG_ENOENT is returned. In this case it is unsafe
+// to make assumptions about the validity of the handler.
+extern int nni_http_server_del_handler(nni_http_server *, nni_http_handler *);
// nni_http_server_set_tls adds a TLS configuration to the server,
// and enables the use of it. This returns NNG_EBUSY if the server is
@@ -212,10 +161,6 @@ extern int nni_http_server_start(nni_http_server *);
// associated with a callback will complete their callback, and then close.
extern void nni_http_server_stop(nni_http_server *);
-// nni_http_ctx is the context associated with a particular request
-// arriving at the server, and is tied to an underlying nni_http channel.
-typedef struct nni_http_ctx nni_http_ctx;
-
// 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
// (such as in the case of websocket). The caller is responsible for obtaining
@@ -226,12 +171,7 @@ typedef struct nni_http_ctx nni_http_ctx;
// when a session is hijacked, the caller is also responsible for disposing
// of the request structure. (Some hijackers may keep the request for
// further processing.)
-extern int nni_http_hijack(nni_http_ctx *);
-
-// nni_http_ctx_stream obtains the underlying nni_http channel for the
-// context. This is used by hijackers, as well as anything that needs
-// to handle sending its own replies on the channel.
-extern int nni_http_ctx_stream(nni_http_ctx *, nni_http **);
+extern int nni_http_hijack(nni_http_conn *);
// nni_http_handler_init creates a server handler object, for the supplied
// URI (path only) with the callback.
@@ -241,7 +181,7 @@ extern int nni_http_ctx_stream(nni_http_ctx *, nni_http **);
// once per server.
//
// The callback function will receive the following arguments (via
-// nni_aio_get_input(): nni_http_request *, nni_http_handler *, and
+// nng_aio_get_input(): nni_http_request *, nni_http_handler *, and
// nni_http_context_t *. The first is a request object, for convenience.
// The second is the handler, from which the callback can obtain any other
// data it has set. The final is the http context, from which its possible
@@ -255,12 +195,12 @@ extern int nni_http_handler_init_file(
nni_http_handler **, const char *, const char *);
// nni_http_handler_init_file_ctype is like nni_http_handler_init_file, but
-// provides for settign the Content-Type explicitly (last argument).
+// provides for setting the Content-Type explicitly (last argument).
extern int nni_http_handler_init_file_ctype(
nni_http_handler **, const char *, const char *, const char *);
// nni_http_handler_init_directory arranges to serve up an entire
-// directory tree. The content types are determined from the builtin
+// directory tree. The content types are determined from the built-in
// content type list. Actual directories are required to contain a
// file called index.html or index.htm. We do not generate directory
// listings for security reasons.
@@ -277,17 +217,10 @@ extern int nni_http_handler_init_static(
// calls this for any handlers still registered with it if it is destroyed.
extern void nni_http_handler_fini(nni_http_handler *);
-// nni_http_handler_set_dtor sets a callback that is executed when
-// the handler is torn down. The argument to the destructor is the
-// handler itself. This function is called by the nni_http_handler_fini
-// function.
-extern int nni_http_handler_set_dtor(
- nni_http_handler *, void (*)(nni_http_handler *));
-
// nni_http_handler_set_tree marks the handler as servicing the entire
// tree (e.g. a directory), rather than just a leaf node. The handler
// will probably need to inspect the URL of the request.
-extern int nni_http_handler_set_tree(nni_http_handler *, bool);
+extern int nni_http_handler_set_tree(nni_http_handler *);
// nni_http_handler_set_host limits the handler to only being called for
// the given Host: field. This can be used to set up multiple virtual
@@ -312,14 +245,17 @@ extern int nni_http_handler_set_method(nni_http_handler *, const char *);
// nni_http_handler_set_data sets an opaque data element on the handler,
// which will be available to the callback via nni_http_handler_get_data.
-// Note that indices used should be small, to minimize array allocations.
-// This can fail with NNG_ENOMEM if storage cannot be allocated.
-extern int nni_http_handler_set_data(nni_http_handler *, void *, unsigned);
+// The callback is an optional destructor, and will be called with the
+// data as its argument, when the handler is being destroyed.
+extern int nni_http_handler_set_data(nni_http_handler *, void *, nni_cb);
// nni_http_handler_get_data returns the data that was previously stored
// at that index. It returns NULL if no data was set, or an invalid index
// is supplied.
-extern void *nni_http_handler_get_data(nni_http_handler *, unsigned);
+extern void *nni_http_handler_get_data(nni_http_handler *);
+
+// nni_http_handler_get_uri returns the URI set on the handler.
+extern const char *nni_http_handler_get_uri(nni_http_handler *);
// Client stuff.
diff --git a/src/supplemental/http/client.c b/src/supplemental/http/http_client.c
index 4c54a708..345e5947 100644
--- a/src/supplemental/http/client.c
+++ b/src/supplemental/http/http_client.c
@@ -40,7 +40,7 @@ http_conn_done(void *arg)
nni_aio * aio;
int rv;
nni_plat_tcp_pipe *p;
- nni_http * http;
+ nni_http_conn * conn;
nni_mtx_lock(&c->mtx);
rv = nni_aio_result(c->connaio);
@@ -61,9 +61,9 @@ http_conn_done(void *arg)
}
if (c->tls != NULL) {
- rv = nni_http_init_tls(&http, c->tls, p);
+ rv = nni_http_conn_init_tls(&conn, c->tls, p);
} else {
- rv = nni_http_init_tcp(&http, p);
+ rv = nni_http_conn_init_tcp(&conn, p);
}
if (rv != 0) {
nni_aio_finish_error(aio, rv);
@@ -71,7 +71,7 @@ http_conn_done(void *arg)
return;
}
- nni_aio_set_output(aio, 0, http);
+ nni_aio_set_output(aio, 0, conn);
nni_aio_finish(aio, 0, 0);
if (!nni_list_empty(&c->aios)) {
@@ -124,9 +124,9 @@ nni_http_client_init(nni_http_client **cp, nni_url *url)
if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
return (rv);
}
- aio->a_addr = &sa;
- host = (strlen(url->u_hostname) != 0) ? url->u_hostname : NULL;
- port = (strlen(url->u_port) != 0) ? url->u_port : NULL;
+ nni_aio_set_input(aio, 0, &sa);
+ host = (strlen(url->u_hostname) != 0) ? url->u_hostname : NULL;
+ port = (strlen(url->u_port) != 0) ? url->u_port : NULL;
nni_plat_tcp_resolv(host, port, NNG_AF_UNSPEC, false, aio);
nni_aio_wait(aio);
rv = nni_aio_result(aio);
@@ -221,14 +221,14 @@ nni_http_client_get_tls(nni_http_client *c, nng_tls_config **tlsp)
static void
http_connect_cancel(nni_aio *aio, int rv)
{
- nni_http_client *c = aio->a_prov_data;
+ nni_http_client *c = nni_aio_get_prov_data(aio);
nni_mtx_lock(&c->mtx);
if (nni_aio_list_active(aio)) {
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, rv);
}
if (nni_list_empty(&c->aios)) {
- nni_aio_cancel(c->connaio, rv);
+ nni_aio_abort(c->connaio, rv);
}
nni_mtx_unlock(&c->mtx);
}
@@ -245,4 +245,4 @@ nni_http_client_connect(nni_http_client *c, nni_aio *aio)
http_conn_start(c);
}
nni_mtx_unlock(&c->mtx);
-} \ No newline at end of file
+}
diff --git a/src/supplemental/http/http_conn.c b/src/supplemental/http/http_conn.c
new file mode 100644
index 00000000..484d2242
--- /dev/null
+++ b/src/supplemental/http/http_conn.c
@@ -0,0 +1,765 @@
+//
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "core/nng_impl.h"
+#include "supplemental/tls/tls.h"
+
+#include "http.h"
+
+// We insist that individual headers fit in 8K.
+// If you need more than that, you need something we can't do.
+#define HTTP_BUFSIZE 8192
+
+// types of reads
+enum read_flavor {
+ HTTP_RD_RAW,
+ HTTP_RD_FULL,
+ HTTP_RD_REQ,
+ HTTP_RD_RES,
+};
+
+enum write_flavor {
+ HTTP_WR_RAW,
+ HTTP_WR_FULL,
+ HTTP_WR_REQ,
+ HTTP_WR_RES,
+};
+
+typedef struct nni_http_tran {
+ void (*h_read)(void *, nni_aio *);
+ void (*h_write)(void *, nni_aio *);
+ int (*h_sock_addr)(void *, nni_sockaddr *);
+ int (*h_peer_addr)(void *, nni_sockaddr *);
+ bool (*h_verified)(void *);
+ void (*h_close)(void *);
+ void (*h_fini)(void *);
+} nni_http_tran;
+
+#define SET_RD_FLAVOR(aio, f) \
+ nni_aio_set_prov_extra(aio, 0, ((void *) (intptr_t)(f)))
+#define GET_RD_FLAVOR(aio) (int) ((intptr_t) nni_aio_get_prov_extra(aio, 0))
+#define SET_WR_FLAVOR(aio, f) \
+ nni_aio_set_prov_extra(aio, 0, ((void *) (intptr_t)(f)))
+#define GET_WR_FLAVOR(aio) (int) ((intptr_t) nni_aio_get_prov_extra(aio, 0))
+
+struct nng_http_conn {
+ void *sock;
+ void (*rd)(void *, nni_aio *);
+ void (*wr)(void *, nni_aio *);
+ int (*sock_addr)(void *, nni_sockaddr *);
+ int (*peer_addr)(void *, nni_sockaddr *);
+ bool (*verified)(void *);
+ void (*close)(void *);
+ void (*fini)(void *);
+
+ void *ctx;
+ bool closed;
+
+ nni_list rdq; // high level http read requests
+ nni_list wrq; // high level http write requests
+
+ nni_aio *rd_uaio; // user aio for read
+ nni_aio *wr_uaio; // user aio for write
+ nni_aio *rd_aio; // bottom half read operations
+ nni_aio *wr_aio; // bottom half write operations
+
+ nni_mtx mtx;
+
+ uint8_t *rd_buf;
+ size_t rd_get;
+ size_t rd_put;
+ size_t rd_bufsz;
+};
+
+void
+nni_http_conn_set_ctx(nni_http_conn *conn, void *ctx)
+{
+ conn->ctx = ctx;
+}
+
+void *
+nni_http_conn_get_ctx(nni_http_conn *conn)
+{
+ return (conn->ctx);
+}
+
+static void
+http_close(nni_http_conn *conn)
+{
+ // Call with lock held.
+ nni_aio *aio;
+
+ if (conn->closed) {
+ return;
+ }
+
+ conn->closed = true;
+ if (nni_list_first(&conn->wrq)) {
+ nni_aio_abort(conn->wr_aio, NNG_ECLOSED);
+ // Abort all operations except the one in flight.
+ while ((aio = nni_list_last(&conn->wrq)) !=
+ nni_list_first(&conn->wrq)) {
+ nni_aio_list_remove(aio);
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ }
+ }
+ if (nni_list_first(&conn->rdq)) {
+ nni_aio_abort(conn->rd_aio, NNG_ECLOSED);
+ while ((aio = nni_list_last(&conn->rdq)) !=
+ nni_list_first(&conn->rdq)) {
+ nni_aio_list_remove(aio);
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ }
+ }
+
+ if (conn->sock != NULL) {
+ conn->close(conn->sock);
+ }
+}
+
+void
+nni_http_conn_close(nni_http_conn *conn)
+{
+ nni_mtx_lock(&conn->mtx);
+ http_close(conn);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+// 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)
+{
+ size_t cnt = conn->rd_put - conn->rd_get;
+ size_t n;
+ uint8_t *rbuf = conn->rd_buf;
+ int rv;
+ bool raw = false;
+ nni_iov *iov;
+ int niov;
+
+ rbuf += conn->rd_get;
+
+ switch (GET_RD_FLAVOR(aio)) {
+ case HTTP_RD_RAW:
+ raw = true; // FALLTHROUGH
+ case HTTP_RD_FULL:
+ nni_aio_get_iov(aio, &niov, &iov);
+ while ((niov != 0) && (cnt != 0)) {
+ // Pull up data from the buffer if possible.
+ n = iov[0].iov_len;
+ if (n > cnt) {
+ n = cnt;
+ }
+ memcpy(iov[0].iov_buf, rbuf, n);
+ iov[0].iov_len -= n;
+ NNI_INCPTR(iov[0].iov_buf, n);
+ conn->rd_get += n;
+ rbuf += n;
+ nni_aio_bump_count(aio, n);
+ cnt -= n;
+
+ if (iov[0].iov_len == 0) {
+ niov--;
+ iov = &iov[1];
+ }
+ }
+
+ nni_aio_set_iov(aio, niov, iov);
+
+ if ((niov == 0) || (raw && (nni_aio_count(aio) != 0))) {
+ // Finished the read. (We are finished if we either
+ // got *all* the data, or we got *some* data for
+ // a raw read.)
+ return (0);
+ }
+
+ // No more data left in the buffer, so use a physio.
+ // (Note that we get here if we either have not completed
+ // a full transaction on a FULL read, or were not even able
+ // to get *any* data for a partial RAW read.)
+ nni_aio_set_data(conn->rd_aio, 1, NULL);
+ nni_aio_set_iov(conn->rd_aio, niov, iov);
+ conn->rd(conn->sock, conn->rd_aio);
+ return (NNG_EAGAIN);
+
+ case HTTP_RD_REQ:
+ rv = nni_http_req_parse(
+ nni_aio_get_prov_extra(aio, 1), rbuf, cnt, &n);
+ conn->rd_get += n;
+ if (conn->rd_get == conn->rd_put) {
+ conn->rd_get = conn->rd_put = 0;
+ }
+ if (rv == NNG_EAGAIN) {
+ nni_iov iov;
+ iov.iov_buf = conn->rd_buf + conn->rd_put;
+ iov.iov_len = conn->rd_bufsz - conn->rd_put;
+ nni_aio_set_iov(conn->rd_aio, 1, &iov);
+ nni_aio_set_data(conn->rd_aio, 1, aio);
+ conn->rd(conn->sock, conn->rd_aio);
+ }
+ return (rv);
+
+ case HTTP_RD_RES:
+ rv = nni_http_res_parse(
+ nni_aio_get_prov_extra(aio, 1), rbuf, cnt, &n);
+ conn->rd_get += n;
+ if (conn->rd_get == conn->rd_put) {
+ conn->rd_get = conn->rd_put = 0;
+ }
+ if (rv == NNG_EAGAIN) {
+ nni_iov iov;
+ iov.iov_buf = conn->rd_buf + conn->rd_put;
+ iov.iov_len = conn->rd_bufsz - conn->rd_put;
+ nni_aio_set_iov(conn->rd_aio, 1, &iov);
+ nni_aio_set_data(conn->rd_aio, 1, aio);
+ conn->rd(conn->sock, conn->rd_aio);
+ }
+ return (rv);
+ }
+ return (NNG_EINVAL);
+}
+
+static void
+http_rd_start(nni_http_conn *conn)
+{
+ for (;;) {
+ nni_aio *aio;
+ int rv;
+
+ if ((aio = conn->rd_uaio) == NULL) {
+ if ((aio = nni_list_first(&conn->rdq)) == NULL) {
+ // No more stuff waiting for read.
+ return;
+ }
+ nni_list_remove(&conn->rdq, aio);
+ conn->rd_uaio = aio;
+ }
+
+ if (conn->closed) {
+ rv = NNG_ECLOSED;
+ } else {
+ rv = http_rd_buf(conn, aio);
+ }
+ switch (rv) {
+ case NNG_EAGAIN:
+ return;
+ case 0:
+ conn->rd_uaio = NULL;
+ nni_aio_finish(aio, 0, nni_aio_count(aio));
+ break;
+ default:
+ conn->rd_uaio = NULL;
+ nni_aio_finish_error(aio, rv);
+ http_close(conn);
+ break;
+ }
+ }
+}
+
+static void
+http_rd_cb(void *arg)
+{
+ nni_http_conn *conn = arg;
+ nni_aio * aio = conn->rd_aio;
+ nni_aio * uaio;
+ size_t cnt;
+ int rv;
+ int niov;
+ nni_iov * iov;
+
+ nni_mtx_lock(&conn->mtx);
+
+ if ((rv = nni_aio_result(aio)) != 0) {
+ if ((uaio = conn->rd_uaio) != NULL) {
+ conn->rd_uaio = NULL;
+ nni_aio_finish_error(uaio, rv);
+ }
+ http_close(conn);
+ nni_mtx_unlock(&conn->mtx);
+ return;
+ }
+
+ cnt = nni_aio_count(aio);
+
+ // If we were reading into the buffer, then advance location(s).
+ if ((uaio = nni_aio_get_data(aio, 1)) != NULL) {
+ conn->rd_put += cnt;
+ NNI_ASSERT(conn->rd_put <= conn->rd_bufsz);
+ http_rd_start(conn);
+ nni_mtx_unlock(&conn->mtx);
+ return;
+ }
+
+ // Otherwise we are completing a USER request, and there should
+ // be no data left in the user buffer.
+ NNI_ASSERT(conn->rd_get == conn->rd_put);
+
+ if ((uaio = conn->rd_uaio) == NULL) {
+ // This indicates that a read request was canceled. This
+ // can occur only when shutting down, really.
+ nni_mtx_unlock(&conn->mtx);
+ return;
+ }
+
+ nni_aio_get_iov(uaio, &niov, &iov);
+
+ while ((niov != 0) && (cnt != 0)) {
+ // Pull up data from the buffer if possible.
+ size_t n = iov[0].iov_len;
+ if (n > cnt) {
+ n = cnt;
+ }
+ iov[0].iov_len -= n;
+ NNI_INCPTR(iov[0].iov_buf, n);
+ nni_aio_bump_count(uaio, n);
+ cnt -= n;
+
+ if (iov[0].iov_len == 0) {
+ niov--;
+ iov = &iov[1];
+ }
+ }
+ nni_aio_set_iov(uaio, niov, iov);
+
+ // Resubmit the start. This will attempt to consume data
+ // from the read buffer (there won't be any), and then either
+ // complete the I/O (for HTTP_RD_RAW, or if there is nothing left),
+ // or submit another physio.
+ http_rd_start(conn);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+static void
+http_rd_cancel(nni_aio *aio, int rv)
+{
+ nni_http_conn *conn = nni_aio_get_prov_data(aio);
+
+ nni_mtx_lock(&conn->mtx);
+ if (aio == conn->rd_uaio) {
+ conn->rd_uaio = NULL;
+ nni_aio_abort(conn->rd_aio, rv);
+ nni_aio_finish_error(aio, rv);
+ } else if (nni_aio_list_active(aio)) {
+ nni_aio_list_remove(aio);
+ nni_aio_finish_error(aio, rv);
+ }
+ nni_mtx_unlock(&conn->mtx);
+}
+
+static void
+http_rd_submit(nni_http_conn *conn, nni_aio *aio)
+{
+ if (nni_aio_start(aio, http_rd_cancel, conn) != 0) {
+ return;
+ }
+ if (conn->closed) {
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ return;
+ }
+ nni_list_append(&conn->rdq, aio);
+ if (conn->rd_uaio == NULL) {
+ http_rd_start(conn);
+ }
+}
+
+static void
+http_wr_start(nni_http_conn *conn)
+{
+ nni_aio *aio;
+ nni_iov *iov;
+ int niov;
+
+ if ((aio = conn->wr_uaio) == NULL) {
+ if ((aio = nni_list_first(&conn->wrq)) == NULL) {
+ // No more stuff waiting for read.
+ return;
+ }
+ nni_list_remove(&conn->wrq, aio);
+ conn->wr_uaio = aio;
+ }
+
+ nni_aio_get_iov(aio, &niov, &iov);
+ nni_aio_set_iov(conn->wr_aio, niov, iov);
+ conn->wr(conn->sock, conn->wr_aio);
+}
+
+static void
+http_wr_cb(void *arg)
+{
+ nni_http_conn *conn = arg;
+ nni_aio * aio = conn->wr_aio;
+ nni_aio * uaio;
+ int rv;
+ size_t n;
+ int niov;
+ nni_iov * iov;
+
+ nni_mtx_lock(&conn->mtx);
+
+ uaio = conn->wr_uaio;
+
+ if ((rv = nni_aio_result(aio)) != 0) {
+ // We failed to complete the aio.
+ if (uaio != NULL) {
+ conn->wr_uaio = NULL;
+ nni_aio_finish_error(uaio, rv);
+ }
+ http_close(conn);
+ nni_mtx_unlock(&conn->mtx);
+ return;
+ }
+
+ if (uaio == NULL) {
+ // Write canceled? This happens pretty much only during
+ // shutdown/close, so we don't want to resume writing.
+ // The stream is probably corrupted at this point anyway.
+ nni_mtx_unlock(&conn->mtx);
+ return;
+ }
+
+ n = nni_aio_count(aio);
+ nni_aio_bump_count(uaio, n);
+
+ if (GET_WR_FLAVOR(uaio) == HTTP_WR_RAW) {
+ // For raw data, we just send partial completion
+ // notices to the consumer.
+ goto done;
+ }
+ nni_aio_iov_advance(aio, n);
+ if (nni_aio_iov_count(aio) > 0) {
+ // We have more to transmit - start another and leave
+ // (we will get called again when it is done).
+ conn->wr(conn->sock, aio);
+ nni_mtx_unlock(&conn->mtx);
+ return;
+ }
+
+done:
+ conn->wr_uaio = NULL;
+ nni_aio_finish(uaio, 0, nni_aio_count(uaio));
+
+ // Start next write if another is ready.
+ http_wr_start(conn);
+
+ nni_mtx_unlock(&conn->mtx);
+}
+
+static void
+http_wr_cancel(nni_aio *aio, int rv)
+{
+ nni_http_conn *conn = nni_aio_get_prov_data(aio);
+
+ nni_mtx_lock(&conn->mtx);
+ if (aio == conn->wr_uaio) {
+ conn->wr_uaio = NULL;
+ nni_aio_abort(conn->wr_aio, rv);
+ nni_aio_finish_error(aio, rv);
+ } else if (nni_aio_list_active(aio)) {
+ nni_aio_list_remove(aio);
+ nni_aio_finish_error(aio, rv);
+ }
+ nni_mtx_unlock(&conn->mtx);
+}
+
+static void
+http_wr_submit(nni_http_conn *conn, nni_aio *aio)
+{
+ if (nni_aio_start(aio, http_wr_cancel, conn) != 0) {
+ return;
+ }
+ if (conn->closed) {
+ nni_aio_finish_error(aio, NNG_ECLOSED);
+ return;
+ }
+ nni_list_append(&conn->wrq, aio);
+ if (conn->wr_uaio == NULL) {
+ http_wr_start(conn);
+ }
+}
+
+void
+nni_http_read_req(nni_http_conn *conn, nni_http_req *req, nni_aio *aio)
+{
+ SET_RD_FLAVOR(aio, HTTP_RD_REQ);
+ nni_aio_set_prov_extra(aio, 1, req);
+
+ nni_mtx_lock(&conn->mtx);
+ http_rd_submit(conn, aio);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+void
+nni_http_read_res(nni_http_conn *conn, nni_http_res *res, nni_aio *aio)
+{
+ SET_RD_FLAVOR(aio, HTTP_RD_RES);
+ nni_aio_set_prov_extra(aio, 1, res);
+
+ nni_mtx_lock(&conn->mtx);
+ http_rd_submit(conn, aio);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+void
+nni_http_read_full(nni_http_conn *conn, nni_aio *aio)
+{
+ SET_RD_FLAVOR(aio, HTTP_RD_FULL);
+ nni_aio_set_prov_extra(aio, 1, NULL);
+
+ nni_mtx_lock(&conn->mtx);
+ http_rd_submit(conn, aio);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+void
+nni_http_read(nni_http_conn *conn, nni_aio *aio)
+{
+ SET_RD_FLAVOR(aio, HTTP_RD_RAW);
+ nni_aio_set_prov_extra(aio, 1, NULL);
+
+ nni_mtx_lock(&conn->mtx);
+ http_rd_submit(conn, aio);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+void
+nni_http_write_req(nni_http_conn *conn, nni_http_req *req, 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) {
+ 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)) {
+ niov++;
+ iov[1].iov_len = size;
+ iov[1].iov_buf = data;
+ }
+ nni_aio_set_iov(aio, niov, iov);
+
+ SET_WR_FLAVOR(aio, HTTP_WR_REQ);
+
+ nni_mtx_lock(&conn->mtx);
+ http_wr_submit(conn, aio);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+void
+nni_http_write_res(nni_http_conn *conn, nni_http_res *res, 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_res_get_buf(res, &buf, &bufsz)) != 0) {
+ nni_aio_finish_error(aio, rv);
+ return;
+ }
+ nni_http_res_get_data(res, &data, &size);
+ niov = 1;
+ iov[0].iov_len = bufsz;
+ iov[0].iov_buf = buf;
+ if ((size > 0) && (data != NULL)) {
+ niov++;
+ iov[1].iov_len = size;
+ iov[1].iov_buf = data;
+ }
+ nni_aio_set_iov(aio, niov, iov);
+
+ SET_WR_FLAVOR(aio, HTTP_WR_RES);
+
+ nni_mtx_lock(&conn->mtx);
+ http_wr_submit(conn, aio);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+void
+nni_http_write(nni_http_conn *conn, nni_aio *aio)
+{
+ SET_WR_FLAVOR(aio, HTTP_WR_RAW);
+
+ nni_mtx_lock(&conn->mtx);
+ http_wr_submit(conn, aio);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+void
+nni_http_write_full(nni_http_conn *conn, nni_aio *aio)
+{
+ SET_WR_FLAVOR(aio, HTTP_WR_FULL);
+
+ nni_mtx_lock(&conn->mtx);
+ http_wr_submit(conn, aio);
+ nni_mtx_unlock(&conn->mtx);
+}
+
+int
+nni_http_sock_addr(nni_http_conn *conn, nni_sockaddr *sa)
+{
+ int rv;
+ nni_mtx_lock(&conn->mtx);
+ rv = conn->closed ? NNG_ECLOSED : conn->sock_addr(conn->sock, sa);
+ nni_mtx_unlock(&conn->mtx);
+ return (rv);
+}
+
+int
+nni_http_peer_addr(nni_http_conn *conn, nni_sockaddr *sa)
+{
+ int rv;
+ nni_mtx_lock(&conn->mtx);
+ rv = conn->closed ? NNG_ECLOSED : conn->peer_addr(conn->sock, sa);
+ nni_mtx_unlock(&conn->mtx);
+ return (rv);
+}
+
+bool
+nni_http_tls_verified(nni_http_conn *conn)
+{
+ bool rv;
+
+ nni_mtx_lock(&conn->mtx);
+ rv = conn->closed ? false : conn->verified(conn->sock);
+ nni_mtx_unlock(&conn->mtx);
+ return (rv);
+}
+
+void
+nni_http_conn_fini(nni_http_conn *conn)
+{
+ nni_mtx_lock(&conn->mtx);
+ http_close(conn);
+ if ((conn->sock != NULL) && (conn->fini != NULL)) {
+ conn->fini(conn->sock);
+ conn->sock = NULL;
+ }
+ nni_mtx_unlock(&conn->mtx);
+ nni_aio_stop(conn->wr_aio);
+ nni_aio_stop(conn->rd_aio);
+ nni_aio_fini(conn->wr_aio);
+ nni_aio_fini(conn->rd_aio);
+ 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, nni_http_tran *tran, void *data)
+{
+ nni_http_conn *conn;
+ int rv;
+
+ if ((conn = NNI_ALLOC_STRUCT(conn)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ conn->rd_bufsz = HTTP_BUFSIZE;
+ if ((conn->rd_buf = nni_alloc(conn->rd_bufsz)) == NULL) {
+ NNI_FREE_STRUCT(conn);
+ return (NNG_ENOMEM);
+ }
+ nni_mtx_init(&conn->mtx);
+ nni_aio_list_init(&conn->rdq);
+ nni_aio_list_init(&conn->wrq);
+
+ conn->sock = data;
+ conn->rd_bufsz = HTTP_BUFSIZE;
+ conn->rd = tran->h_read;
+ conn->wr = tran->h_write;
+ conn->close = tran->h_close;
+ conn->fini = tran->h_fini;
+ conn->sock_addr = tran->h_sock_addr;
+ conn->peer_addr = tran->h_peer_addr;
+ conn->verified = tran->h_verified;
+
+ if (((rv = nni_aio_init(&conn->wr_aio, http_wr_cb, conn)) != 0) ||
+ ((rv = nni_aio_init(&conn->rd_aio, http_rd_cb, conn)) != 0)) {
+ nni_http_conn_fini(conn);
+ return (rv);
+ }
+
+ *connp = conn;
+
+ return (0);
+}
+
+static bool
+nni_http_verified_tcp(void *arg)
+{
+ NNI_ARG_UNUSED(arg);
+ return (false);
+}
+
+static nni_http_tran http_tcp_ops = {
+ .h_read = (void *) nni_plat_tcp_pipe_recv,
+ .h_write = (void *) nni_plat_tcp_pipe_send,
+ .h_close = (void *) nni_plat_tcp_pipe_close,
+ .h_fini = (void *) nni_plat_tcp_pipe_fini,
+ .h_sock_addr = (void *) nni_plat_tcp_pipe_sockname,
+ .h_peer_addr = (void *) nni_plat_tcp_pipe_peername,
+ .h_verified = nni_http_verified_tcp,
+};
+
+int
+nni_http_conn_init_tcp(nni_http_conn **connp, void *tcp)
+{
+ return (http_init(connp, &http_tcp_ops, tcp));
+}
+
+#ifdef NNG_SUPP_TLS
+static nni_http_tran http_tls_ops = {
+ .h_read = (void *) nni_tls_recv,
+ .h_write = (void *) nni_tls_send,
+ .h_close = (void *) nni_tls_close,
+ .h_fini = (void *) nni_tls_fini,
+ .h_sock_addr = (void *) nni_tls_sockname,
+ .h_peer_addr = (void *) nni_tls_peername,
+ .h_verified = (void *) nni_tls_verified,
+};
+
+int
+nni_http_conn_init_tls(nni_http_conn **connp, nng_tls_config *cfg, void *tcp)
+{
+ nni_tls *tls;
+ int rv;
+
+ if ((rv = nni_tls_init(&tls, cfg, tcp)) != 0) {
+ nni_plat_tcp_pipe_fini(tcp);
+ return (rv);
+ }
+
+ return (http_init(connp, &http_tls_ops, tls));
+}
+#else
+int
+nni_http_conn_init_tls(nni_http_conn **connp, nng_tls_config *cfg, void *tcp)
+{
+ NNI_ARG_UNUSED(connp);
+ NNI_ARG_UNUSED(cfg);
+ nni_plat_tcp_pipe_fini(tcp);
+ return (NNG_ENOTSUP);
+}
+#endif // NNG_SUPP_TLS \ No newline at end of file
diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c
index da8c70f3..81c1b453 100644
--- a/src/supplemental/http/http_msg.c
+++ b/src/supplemental/http/http_msg.c
@@ -27,14 +27,14 @@ typedef struct http_header {
nni_list_node node;
} http_header;
-struct nni_http_entity {
+typedef struct nni_http_entity {
char * data;
size_t size; // allocated/expected size
size_t len; // current length
bool own; // if true, data is "ours", and should be freed
-};
+} nni_http_entity;
-struct nni_http_req {
+struct nng_http_req {
nni_list hdrs;
nni_http_entity data;
char * meth;
@@ -42,23 +42,27 @@ struct nni_http_req {
char * vers;
char * buf;
size_t bufsz;
+ bool parsed;
};
-struct nni_http_res {
+struct nng_http_res {
nni_list hdrs;
nni_http_entity data;
- int code;
+ uint16_t code;
char * rsn;
char * vers;
char * buf;
size_t bufsz;
+ bool parsed;
};
static int
http_set_string(char **strp, const char *val)
{
char *news;
- if ((news = nni_strdup(val)) == NULL) {
+ if (val == NULL) {
+ news = NULL;
+ } else if ((news = nni_strdup(val)) == NULL) {
return (NNG_ENOMEM);
}
nni_strfree(*strp);
@@ -114,6 +118,8 @@ nni_http_res_reset(nni_http_res *res)
http_entity_reset(&res->data);
nni_strfree(res->rsn);
nni_strfree(res->vers);
+ res->vers = NULL;
+ res->rsn = NULL;
res->code = 0;
if (res->bufsz) {
res->buf[0] = '\0';
@@ -121,7 +127,7 @@ nni_http_res_reset(nni_http_res *res)
}
void
-nni_http_req_fini(nni_http_req *req)
+nni_http_req_free(nni_http_req *req)
{
nni_http_req_reset(req);
if (req->bufsz) {
@@ -131,7 +137,7 @@ nni_http_req_fini(nni_http_req *req)
}
void
-nni_http_res_fini(nni_http_res *res)
+nni_http_res_free(nni_http_res *res)
{
nni_http_res_reset(res);
if (res->bufsz) {
@@ -157,13 +163,13 @@ http_del_header(nni_list *hdrs, const char *key)
}
int
-nni_req_del_header(nni_http_req *req, const char *key)
+nni_http_req_del_header(nni_http_req *req, const char *key)
{
return (http_del_header(&req->hdrs, key));
}
int
-nni_res_del_header(nni_http_res *res, const char *key)
+nni_http_res_del_header(nni_http_res *res, const char *key)
{
return (http_del_header(&res->hdrs, key));
}
@@ -398,12 +404,6 @@ nni_http_res_copy_data(nni_http_res *res, const void *data, size_t size)
return (0);
}
-int
-nni_http_res_alloc_data(nni_http_res *res, size_t size)
-{
- return (http_entity_alloc_data(&res->data, size));
-}
-
static int
http_parse_header(nni_list *hdrs, void *line)
{
@@ -501,11 +501,12 @@ static int
http_req_prepare(nni_http_req *req)
{
int rv;
- if ((req->uri == NULL) || (req->meth == NULL)) {
+ 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 != NULL ? req->vers : "HTTP/1.1");
+ req->meth != NULL ? req->meth : "GET", req->uri,
+ req->vers != NULL ? req->vers : "HTTP/1.1");
return (rv);
}
@@ -514,8 +515,8 @@ http_res_prepare(nni_http_res *res)
{
int rv;
rv = http_asprintf(&res->buf, &res->bufsz, &res->hdrs, "%s %d %s\r\n",
- res->vers != NULL ? res->vers : "HTTP/1.1", res->code,
- res->rsn != NULL ? res->rsn : "Unknown Error");
+ nni_http_res_get_version(res), nni_http_res_get_status(res),
+ nni_http_res_get_reason(res));
return (rv);
}
@@ -572,7 +573,7 @@ nni_http_res_get_buf(nni_http_res *res, void **data, size_t *szp)
}
int
-nni_http_req_init(nni_http_req **reqp)
+nni_http_req_alloc(nni_http_req **reqp, const nni_url *url)
{
nni_http_req *req;
if ((req = NNI_ALLOC_STRUCT(req)) == NULL) {
@@ -587,12 +588,33 @@ nni_http_req_init(nni_http_req **reqp)
req->vers = NULL;
req->meth = NULL;
req->uri = NULL;
- *reqp = req;
+ if (url != NULL) {
+ const char *host;
+ int rv;
+ if ((req->uri = nni_strdup(url->u_rawpath)) == NULL) {
+ NNI_FREE_STRUCT(req);
+ 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 (strcmp(nni_url_default_port(url->u_scheme), url->u_port) ==
+ 0) {
+ host = url->u_hostname;
+ } else {
+ host = url->u_host;
+ }
+ if ((rv = nni_http_req_add_header(req, "Host", host)) != 0) {
+ nni_http_req_free(req);
+ return (rv);
+ }
+ }
+ *reqp = req;
return (0);
}
int
-nni_http_res_init(nni_http_res **resp)
+nni_http_res_alloc(nni_http_res **resp)
{
nni_http_res *res;
if ((res = NNI_ALLOC_STRUCT(res)) == NULL) {
@@ -614,7 +636,7 @@ nni_http_res_init(nni_http_res **resp)
const char *
nni_http_req_get_method(nni_http_req *req)
{
- return (req->meth != NULL ? req->meth : "");
+ return (req->meth != NULL ? req->meth : "GET");
}
const char *
@@ -626,24 +648,30 @@ nni_http_req_get_uri(nni_http_req *req)
const char *
nni_http_req_get_version(nni_http_req *req)
{
- return (req->vers != NULL ? req->vers : "");
+ return (req->vers != NULL ? req->vers : "HTTP/1.1");
}
const char *
nni_http_res_get_version(nni_http_res *res)
{
- return (res->vers != NULL ? res->vers : "");
+ return (res->vers != NULL ? res->vers : "HTTP/1.1");
}
int
nni_http_req_set_version(nni_http_req *req, const char *vers)
{
+ if (strcmp(vers, "HTTP/1.1") == 0) {
+ vers = NULL;
+ }
return (http_set_string(&req->vers, vers));
}
int
nni_http_res_set_version(nni_http_res *res, const char *vers)
{
+ if (strcmp(vers, "HTTP/1.1") == 0) {
+ vers = NULL;
+ }
return (http_set_string(&res->vers, vers));
}
@@ -656,31 +684,25 @@ nni_http_req_set_uri(nni_http_req *req, const char *uri)
int
nni_http_req_set_method(nni_http_req *req, const char *meth)
{
+ if (strcmp(meth, "GET") == 0) {
+ meth = NULL;
+ }
return (http_set_string(&req->meth, meth));
}
int
-nni_http_res_set_status(nni_http_res *res, int status, const char *reason)
+nni_http_res_set_status(nni_http_res *res, uint16_t status)
{
- int rv;
- if ((rv = http_set_string(&res->rsn, reason)) == 0) {
- res->code = status;
- }
- return (rv);
+ res->code = status;
+ return (0);
}
-int
+uint16_t
nni_http_res_get_status(nni_http_res *res)
{
return (res->code);
}
-const char *
-nni_http_res_get_reason(nni_http_res *res)
-{
- return (res->rsn != NULL ? res->rsn : "");
-}
-
static int
http_scan_line(void *vbuf, size_t n, size_t *lenp)
{
@@ -740,6 +762,7 @@ http_req_parse_line(nni_http_req *req, void *line)
((rv = nni_http_req_set_version(req, version)) != 0)) {
return (rv);
}
+ req->parsed = true;
return (0);
}
@@ -770,10 +793,12 @@ http_res_parse_line(nni_http_res *res, uint8_t *line)
return (NNG_EPROTO);
}
- if (((rv = nni_http_res_set_status(res, status, reason)) != 0) ||
- ((rv = nni_http_res_set_version(res, version)) != 0)) {
+ if (((rv = nni_http_res_set_status(res, (uint16_t) status)) != 0) ||
+ ((rv = nni_http_res_set_version(res, version)) != 0) ||
+ ((rv = nni_http_res_set_reason(res, reason)) != 0)) {
return (rv);
}
+ res->parsed = true;
return (0);
}
@@ -806,7 +831,7 @@ nni_http_req_parse(nni_http_req *req, void *buf, size_t n, size_t *lenp)
break;
}
- if (req->vers != NULL) {
+ if (req->parsed) {
rv = http_parse_header(&req->hdrs, line);
} else {
rv = http_req_parse_line(req, line);
@@ -843,7 +868,7 @@ nni_http_res_parse(nni_http_res *res, void *buf, size_t n, size_t *lenp)
break;
}
- if (res->vers != NULL) {
+ if (res->parsed) {
rv = http_parse_header(&res->hdrs, line);
} else {
rv = http_res_parse_line(res, line);
@@ -858,105 +883,121 @@ nni_http_res_parse(nni_http_res *res, void *buf, size_t n, size_t *lenp)
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, "Swithching 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 *
+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(nni_http_res *res)
+{
+ return (res->rsn ? res->rsn : http_reason(res->code));
+}
+
int
-nni_http_res_init_error(nni_http_res **resp, uint16_t err)
+nni_http_res_set_reason(nni_http_res *res, const char *reason)
{
- char * rsn;
- char rsnbuf[80];
- char html[1024];
+ if (strcmp(reason, http_reason(res->code)) == 0) {
+ reason = NULL;
+ }
+ return (http_set_string(&res->rsn, reason));
+}
+
+int
+nni_http_res_alloc_error(nni_http_res **resp, uint16_t err)
+{
+ char html[512];
int rv;
nni_http_res *res;
- if ((rv = nni_http_res_init(&res)) != 0) {
+ if ((rv = nni_http_res_alloc(&res)) != 0) {
return (rv);
}
- // Note that it is expected that redirect URIs will update the
- // payload to reflect the target location.
- switch (err) {
- case NNI_HTTP_STATUS_STATUS_MOVED_PERMANENTLY:
- rsn = "Moved Permanently";
- break;
- case NNI_HTTP_STATUS_MULTIPLE_CHOICES:
- rsn = "Multiple Choices";
- break;
- case NNI_HTTP_STATUS_FOUND:
- rsn = "Found";
- break;
- case NNI_HTTP_STATUS_SEE_OTHER:
- rsn = "See Other";
- break;
- case NNI_HTTP_STATUS_TEMPORARY_REDIRECT:
- rsn = "Temporary Redirect";
- break;
- case NNI_HTTP_STATUS_BAD_REQUEST:
- rsn = "Bad Request";
- break;
- case NNI_HTTP_STATUS_UNAUTHORIZED:
- rsn = "Unauthorized";
- break;
- case NNI_HTTP_STATUS_PAYMENT_REQUIRED:
- rsn = "Payment Required";
- break;
- case NNI_HTTP_STATUS_NOT_FOUND:
- rsn = "Not Found";
- break;
- case NNI_HTTP_STATUS_METHOD_NOT_ALLOWED:
- // Caller must also supply an Allow: header
- rsn = "Method Not Allowed";
- break;
- case NNI_HTTP_STATUS_NOT_ACCEPTABLE:
- rsn = "Not Acceptable";
- break;
- case NNI_HTTP_STATUS_REQUEST_TIMEOUT:
- rsn = "Request Timeout";
- break;
- case NNI_HTTP_STATUS_CONFLICT:
- rsn = "Conflict";
- break;
- case NNI_HTTP_STATUS_GONE:
- rsn = "Gone";
- break;
- case NNI_HTTP_STATUS_LENGTH_REQUIRED:
- rsn = "Length Required";
- break;
- case NNI_HTTP_STATUS_PAYLOAD_TOO_LARGE:
- rsn = "Payload Too Large";
- break;
- case NNI_HTTP_STATUS_FORBIDDEN:
- rsn = "Forbidden";
- break;
- case NNI_HTTP_STATUS_URI_TOO_LONG:
- rsn = "URI Too Long";
- break;
- case NNI_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE:
- rsn = "Unsupported Media Type";
- break;
- case NNI_HTTP_STATUS_EXPECTATION_FAILED:
- rsn = "Expectation Failed";
- break;
- case NNI_HTTP_STATUS_UPGRADE_REQUIRED:
- // Caller must add "Upgrade:" header.
- rsn = "Upgrade Required";
- break;
- case NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR:
- rsn = "Internal Server Error";
- break;
- case NNI_HTTP_STATUS_HTTP_VERSION_NOT_SUPP:
- rsn = "HTTP version not supported";
- break;
- case NNI_HTTP_STATUS_NOT_IMPLEMENTED:
- rsn = "Not Implemented";
- break;
- case NNI_HTTP_STATUS_SERVICE_UNAVAILABLE:
- rsn = "Service Unavailable";
- break;
- default:
- snprintf(rsnbuf, sizeof(rsnbuf), "HTTP error code %d", err);
- rsn = rsnbuf;
- break;
- }
-
// very simple builtin error page
(void) snprintf(html, sizeof(html),
"<head><title>%d %s</title></head>"
@@ -967,14 +1008,13 @@ nni_http_res_init_error(nni_http_res **resp, uint16_t err)
"<p align=\"center\">"
"<span style=\"font-size: 24px; font-family: Arial, sans serif;\">"
"%s</span></p></body>",
- err, rsn, err, rsn);
+ err, http_reason(err), err, http_reason(err));
- if (((rv = nni_http_res_set_status(res, err, rsn)) != 0) ||
- ((rv = nni_http_res_set_version(res, "HTTP/1.1")) != 0) ||
- ((rv = nni_http_res_set_header(
+ res->code = err;
+ if (((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_http_res_fini(res);
+ nni_http_res_free(res);
} else {
*resp = res;
}
diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c
new file mode 100644
index 00000000..f19b83b1
--- /dev/null
+++ b/src/supplemental/http/http_public.c
@@ -0,0 +1,668 @@
+//
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include "core/nng_impl.h"
+#include "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(nng_http_req *req, const char *key)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_req_get_header(req, key));
+#else
+ NNI_ARG_UNUSED(req);
+ NNI_ARG_UNUSED(key);
+ return (NULL);
+#endif
+}
+
+const char *
+nng_http_res_get_header(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(key);
+ return (NULL);
+#endif
+}
+
+int
+nng_http_req_add_header(nng_http_req *req, const char *key, const char *val)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_req_add_header(req, 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(key);
+ NNI_ARG_UNUSED(val);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+int
+nng_http_res_set_header(nng_http_res *res, const char *key, const char *val)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_res_set_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_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)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_res_del_header(res, key));
+#else
+ NNI_ARG_UNUSED(res);
+ 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)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_req_set_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_set_data(nng_http_res *res, const void *data, size_t sz)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_res_set_data(res, data, sz));
+#else
+ NNI_ARG_UNUSED(res);
+ NNI_ARG_UNUSED(data);
+ NNI_ARG_UNUSED(sz);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+const char *
+nng_http_req_get_method(nng_http_req *req)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_req_get_method(req));
+#else
+ NNI_ARG_UNUSED(req);
+ return (NULL);
+#endif
+}
+
+const char *
+nng_http_req_get_version(nng_http_req *req)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_req_get_version(req));
+#else
+ NNI_ARG_UNUSED(req);
+ return (NULL);
+#endif
+}
+
+const char *
+nng_http_req_get_uri(nng_http_req *req)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_req_get_uri(req));
+#else
+ NNI_ARG_UNUSED(req);
+ return (NULL);
+#endif
+}
+
+int
+nng_http_req_set_method(nng_http_req *req, const char *meth)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_req_set_method(req, meth));
+#else
+ NNI_ARG_UNUSED(req);
+ NNI_ARG_UNUSED(meth);
+ return (NNG_ENOTSUP);
+#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_uri(nng_http_req *req, const char *uri)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_req_set_uri(req, uri));
+#else
+ NNI_ARG_UNUSED(req);
+ NNI_ARG_UNUSED(uri);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+uint16_t
+nng_http_res_get_status(nng_http_res *res)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_res_get_status(res));
+#else
+ NNI_ARG_UNUSED(res);
+ return (0);
+#endif
+}
+
+const char *
+nng_http_res_get_version(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(nng_http_res *res)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_res_get_reason(res));
+#else
+ NNI_ARG_UNUSED(res);
+ return (NULL);
+#endif
+}
+
+int
+nng_http_res_set_status(nng_http_res *res, uint16_t status)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_res_set_status(res, status));
+#else
+ NNI_ARG_UNUSED(res);
+ NNI_ARG_UNUSED(status);
+ return (NNG_ENOTSUP);
+#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)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_res_set_reason(res, rsn));
+#else
+ NNI_ARG_UNUSED(res);
+ NNI_ARG_UNUSED(rsn);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+void
+nng_http_conn_close(nng_http_conn *conn)
+{
+#ifdef NNG_SUPP_HTTP
+ // API version of this closes *and* frees the structure.
+ nni_http_conn_fini(conn);
+#else
+ NNI_ARG_UNUSED(conn);
+#endif
+}
+
+void
+nng_http_conn_read(nng_http_conn *conn, nng_aio *aio)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_read(conn, aio);
+#else
+ NNI_ARG_UNUSED(conn);
+ NNI_ARG_UNUSED(aio);
+#endif
+}
+
+void
+nng_http_conn_read_all(nng_http_conn *conn, nng_aio *aio)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_read_full(conn, aio);
+#else
+ NNI_ARG_UNUSED(conn);
+ NNI_ARG_UNUSED(aio);
+#endif
+}
+
+void
+nng_http_conn_write(nng_http_conn *conn, nng_aio *aio)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_write(conn, aio);
+#else
+ NNI_ARG_UNUSED(conn);
+ NNI_ARG_UNUSED(aio);
+#endif
+}
+
+void
+nng_http_conn_write_all(nng_http_conn *conn, nng_aio *aio)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_write_full(conn, aio);
+#else
+ NNI_ARG_UNUSED(conn);
+ NNI_ARG_UNUSED(aio);
+#endif
+}
+
+void
+nng_http_conn_write_req(nng_http_conn *conn, nng_http_req *req, nng_aio *aio)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_write_req(conn, req, aio);
+#else
+ NNI_ARG_UNUSED(conn);
+ NNI_ARG_UNUSED(req);
+ NNI_ARG_UNUSED(aio);
+#endif
+}
+
+void
+nng_http_conn_write_res(nng_http_conn *conn, nng_http_res *res, nng_aio *aio)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_write_res(conn, res, aio);
+#else
+ NNI_ARG_UNUSED(conn);
+ NNI_ARG_UNUSED(res);
+ NNI_ARG_UNUSED(aio);
+#endif
+}
+
+void
+nng_http_conn_read_req(nng_http_conn *conn, nng_http_req *req, nng_aio *aio)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_read_req(conn, req, aio);
+#else
+ NNI_ARG_UNUSED(conn);
+ NNI_ARG_UNUSED(req);
+ NNI_ARG_UNUSED(aio);
+#endif
+}
+
+void
+nng_http_conn_read_res(nng_http_conn *conn, nng_http_res *res, nng_aio *aio)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_read_res(conn, res, aio);
+#else
+ NNI_ARG_UNUSED(conn);
+ NNI_ARG_UNUSED(res);
+ NNI_ARG_UNUSED(aio);
+#endif
+}
+
+int
+nng_http_handler_alloc(
+ nng_http_handler **hp, const char *uri, void (*cb)(nng_aio *))
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_handler_init(hp, uri, cb));
+#else
+ NNI_ARG_UNUSED(hp);
+ NNI_ARG_UNUSED(uri);
+ NNI_ARG_UNUSED(cb);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+void
+nng_http_handler_free(nng_http_handler *h)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_handler_fini(h);
+#else
+ NNI_ARG_UNUSED(h);
+#endif
+}
+
+int
+nng_http_handler_alloc_file(
+ nng_http_handler **hp, const char *uri, const char *path)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_handler_init_file(hp, uri, path));
+#else
+ NNI_ARG_UNUSED(hp);
+ NNI_ARG_UNUSED(uri);
+ NNI_ARG_UNUSED(path);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+int
+nng_http_handler_alloc_directory(
+ nng_http_handler **hp, const char *uri, const char *path)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_handler_init_directory(hp, uri, path));
+#else
+ NNI_ARG_UNUSED(hp);
+ NNI_ARG_UNUSED(uri);
+ NNI_ARG_UNUSED(path);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+int
+nng_http_handler_alloc_static(nng_http_handler **hp, const char *uri,
+ const void *data, size_t size, const char *ctype)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_handler_init_static(hp, uri, data, size, ctype));
+#else
+ NNI_ARG_UNUSED(hp);
+ NNI_ARG_UNUSED(uri);
+ NNI_ARG_UNUSED(data);
+ NNI_ARG_UNUSED(size);
+ NNI_ARG_UNUSED(ctype);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+int
+nng_http_handler_set_method(nng_http_handler *h, const char *meth)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_handler_set_method(h, meth));
+#else
+ NNI_ARG_UNUSED(h);
+ NNI_ARG_UNUSED(meth);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+int
+nng_http_handler_set_host(nng_http_handler *h, const char *host)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_handler_set_host(h, host));
+#else
+ NNI_ARG_UNUSED(h);
+ NNI_ARG_UNUSED(host);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+int
+nng_http_handler_set_data(nng_http_handler *h, void *dat, void (*dtor)(void *))
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_handler_set_data(h, dat, dtor));
+#else
+ NNI_ARG_UNUSED(h);
+ NNI_ARG_UNUSED(dat);
+ NNI_ARG_UNUSED(dtor);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+void *
+nng_handler_get_data(nng_http_handler *h)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_handler_get_data(h));
+#else
+ NNI_ARG_UNUSED(h);
+ return (NULL);
+#endif
+}
+
+int
+nng_http_server_hold(nng_http_server **srvp, const nng_url *url)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_server_init(srvp, url));
+#else
+ NNI_ARG_UNUSED(srvp);
+ NNI_ARG_UNUSED(url);
+#endif
+}
+
+void
+nng_http_server_release(nng_http_server *srv)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_server_fini(srv);
+#else
+ NNI_ARG_UNUSED(srv);
+#endif
+}
+
+int
+nng_http_server_start(nng_http_server *srv)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_server_start(srv));
+#else
+ NNI_ARG_UNUSED(srv);
+#endif
+}
+
+void
+nng_http_server_stop(nng_http_server *srv)
+{
+#ifdef NNG_SUPP_HTTP
+ nni_http_server_stop(srv);
+#else
+ NNI_ARG_UNUSED(srv);
+#endif
+}
+
+int
+nng_http_server_add_handler(nng_http_server *srv, nng_http_handler *h)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_server_add_handler(srv, h));
+#else
+ NNI_ARG_UNUSED(srv);
+ NNI_ARG_UNUSED(h);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+int
+nng_http_server_del_handler(nng_http_server *srv, nng_http_handler *h)
+{
+#ifdef NNG_SUPP_HTTP
+ return (nni_http_server_del_handler(srv, h));
+#else
+ NNI_ARG_UNUSED(srv);
+ NNI_ARG_UNUSED(h);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+int
+nng_http_server_set_tls(nng_http_server *srv, nng_tls_config *cfg)
+{
+#if defined(NNG_SUPP_HTTP) && defined(NNG_SUPP_TLS)
+ return (nni_http_server_set_tls(srv, cfg));
+#else
+ NNI_ARG_UNUSED(srv);
+ NNI_ARG_UNUSED(cfg);
+ return (NNG_ENOTSUP);
+#endif
+}
+
+int
+nng_http_server_get_tls(nng_http_server *srv, nng_tls_config **cfgp)
+{
+#if defined(NNG_SUPP_HTTP) && defined(NNG_SUPP_TLS)
+ return (nni_http_server_get_tls(srv, cfgp));
+#else
+ NNI_ARG_UNUSED(srv);
+ NNI_ARG_UNUSED(cfgp);
+ return (NNG_ENOTSUP);
+#endif
+}
diff --git a/src/supplemental/http/server.c b/src/supplemental/http/http_server.c
index ecb544ea..21a88f9e 100644
--- a/src/supplemental/http/server.c
+++ b/src/supplemental/http/http_server.c
@@ -27,22 +27,21 @@ static nni_initializer http_server_initializer = {
.i_once = 0,
};
-struct nni_http_handler {
+struct nng_http_handler {
nni_list_node node;
- void ** args;
- unsigned nargs;
char * path;
- const char * method;
+ char * method;
char * host;
bool tree;
int refcnt;
+ void * data;
+ nni_cb dtor;
void (*cb)(nni_aio *);
- void (*dtor)(nni_http_handler *);
};
typedef struct nni_http_ctx {
nni_list_node node;
- nni_http * http;
+ nni_http_conn * conn;
nni_http_server *server;
nni_http_req * req;
nni_http_res * res;
@@ -56,7 +55,7 @@ typedef struct nni_http_ctx {
nni_reap_item reap;
} http_sconn;
-struct nni_http_server {
+struct nng_http_server {
nng_sockaddr addr;
nni_list_node node;
int refcnt;
@@ -82,16 +81,15 @@ nni_http_handler_init(
if ((h = NNI_ALLOC_STRUCT(h)) == NULL) {
return (NNG_ENOMEM);
}
- if ((h->path = nni_strdup(path)) == NULL) {
- NNI_FREE_STRUCT(h);
+ if (((h->path = nni_strdup(path)) == NULL) ||
+ ((h->method = nni_strdup("GET")) == NULL)) {
+ nni_http_handler_fini(h);
return (NNG_ENOMEM);
}
NNI_LIST_NODE_INIT(&h->node);
h->cb = cb;
- h->args = NULL;
- h->nargs = 0;
+ h->data = NULL;
h->dtor = NULL;
- h->method = "GET";
h->host = NULL;
h->tree = false;
h->refcnt = 0;
@@ -106,54 +104,44 @@ nni_http_handler_fini(nni_http_handler *h)
return;
}
if (h->dtor != NULL) {
- h->dtor(h);
- }
- if (h->nargs > 0) {
- nni_free(h->args, h->nargs * sizeof(void *));
+ h->dtor(h->data);
}
nni_strfree(h->host);
nni_strfree(h->path);
+ nni_strfree(h->method);
NNI_FREE_STRUCT(h);
}
int
-nni_http_handler_set_data(nni_http_handler *h, void *data, unsigned index)
+nni_http_handler_set_data(nni_http_handler *h, void *data, nni_cb dtor)
{
if (h->refcnt != 0) {
return (NNG_EBUSY);
}
- if (index >= h->nargs) {
- void ** newargs;
- unsigned newnargs = index + 4; // +4 to reduce allocations
- if ((newargs = nni_alloc(newnargs * sizeof(void *))) == NULL) {
- return (NNG_ENOMEM);
- }
-
- memcpy(newargs, h->args, h->nargs * sizeof(void *));
- for (unsigned i = h->nargs; i < newnargs; i++) {
- newargs[i] = NULL;
- }
- nni_free(h->args, h->nargs * sizeof(void *));
- h->args = newargs;
- h->nargs = newnargs;
- }
- h->args[index] = data;
+ h->data = data;
+ h->dtor = dtor;
return (0);
}
void *
-nni_http_handler_get_data(nni_http_handler *h, unsigned index)
+nni_http_handler_get_data(nni_http_handler *h)
+{
+ return (h->data);
+}
+
+const char *
+nni_http_handler_get_uri(nni_http_handler *h)
{
- return ((index < h->nargs) ? h->args[index] : NULL);
+ return (h->path);
}
int
-nni_http_handler_set_tree(nni_http_handler *h, bool is_tree)
+nni_http_handler_set_tree(nni_http_handler *h)
{
if (h->refcnt != 0) {
return (NNG_EBUSY);
}
- h->tree = is_tree;
+ h->tree = true;
return (0);
}
@@ -180,21 +168,20 @@ nni_http_handler_set_host(nni_http_handler *h, const char *host)
int
nni_http_handler_set_method(nni_http_handler *h, const char *method)
{
+ char *dupmeth;
if (h->refcnt != 0) {
return (NNG_EBUSY);
}
- h->method = method;
- return (0);
-}
-
-int
-nni_http_handler_set_dtor(
- nni_http_handler *h, void (*dtor)(nni_http_handler *))
-{
- if (h->refcnt != 0) {
- return (NNG_EBUSY);
+ if (method == NULL) {
+ nni_strfree(h->method);
+ h->method = NULL;
+ return (0);
}
- h->dtor = dtor;
+ if ((dupmeth = nni_strdup(method)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ nni_strfree(h->method);
+ h->method = dupmeth;
return (0);
}
@@ -213,14 +200,14 @@ http_sconn_reap(void *arg)
nni_aio_stop(sc->txdataio);
nni_aio_stop(sc->cbaio);
- if (sc->http != NULL) {
- nni_http_fini(sc->http);
+ if (sc->conn != NULL) {
+ nni_http_conn_fini(sc->conn);
}
if (sc->req != NULL) {
- nni_http_req_fini(sc->req);
+ nni_http_req_free(sc->req);
}
if (sc->res != NULL) {
- nni_http_res_fini(sc->res);
+ nni_http_res_free(sc->res);
}
nni_aio_fini(sc->rxaio);
nni_aio_fini(sc->txaio);
@@ -249,9 +236,7 @@ http_sconn_fini(http_sconn *sc)
static void
http_sconn_close_locked(http_sconn *sc)
{
- nni_http_server *s;
- s = sc->server;
- nni_http *h;
+ nni_http_conn *conn;
if (sc->closed) {
return;
@@ -259,13 +244,13 @@ http_sconn_close_locked(http_sconn *sc)
NNI_ASSERT(!sc->finished);
sc->closed = true;
- nni_aio_cancel(sc->rxaio, NNG_ECLOSED);
- nni_aio_cancel(sc->txaio, NNG_ECLOSED);
- nni_aio_cancel(sc->txdataio, NNG_ECLOSED);
- nni_aio_cancel(sc->cbaio, NNG_ECLOSED);
+ nni_aio_abort(sc->rxaio, NNG_ECLOSED);
+ nni_aio_abort(sc->txaio, NNG_ECLOSED);
+ nni_aio_abort(sc->txdataio, NNG_ECLOSED);
+ nni_aio_abort(sc->cbaio, NNG_ECLOSED);
- if ((h = sc->http) != NULL) {
- nni_http_close(h);
+ if ((conn = sc->conn) != NULL) {
+ nni_http_conn_close(conn);
}
http_sconn_fini(sc);
}
@@ -293,7 +278,7 @@ http_sconn_txdatdone(void *arg)
}
if (sc->res != NULL) {
- nni_http_res_fini(sc->res);
+ nni_http_res_free(sc->res);
sc->res = NULL;
}
@@ -303,7 +288,7 @@ http_sconn_txdatdone(void *arg)
}
nni_http_req_reset(sc->req);
- nni_http_read_req(sc->http, sc->req, sc->rxaio);
+ nni_http_read_req(sc->conn, sc->req, sc->rxaio);
}
static void
@@ -311,42 +296,23 @@ http_sconn_txdone(void *arg)
{
http_sconn *sc = arg;
nni_aio * aio = sc->txaio;
- int rv;
- void * data;
- size_t size;
- if ((rv = nni_aio_result(aio)) != 0) {
+ if (nni_aio_result(aio) != 0) {
http_sconn_close(sc);
return;
}
- // For HEAD requests, we just treat like "GET" but don't send
- // the data. (Required per HTTP.)
- if (strcmp(nni_http_req_get_method(sc->req), "HEAD") == 0) {
- size = 0;
- } else {
- nni_http_res_get_data(sc->res, &data, &size);
- }
- if (size) {
- // Submit data.
- sc->txdataio->a_niov = 1;
- sc->txdataio->a_iov[0].iov_buf = data;
- sc->txdataio->a_iov[0].iov_len = size;
- nni_http_write_full(sc->http, sc->txdataio);
- return;
- }
-
if (sc->close) {
http_sconn_close(sc);
return;
}
if (sc->res != NULL) {
- nni_http_res_fini(sc->res);
+ nni_http_res_free(sc->res);
sc->res = NULL;
}
nni_http_req_reset(sc->req);
- nni_http_read_req(sc->http, sc->req, sc->rxaio);
+ nni_http_read_req(sc->conn, sc->req, sc->rxaio);
}
static char
@@ -364,6 +330,7 @@ http_hexval(char c)
return (0);
}
+// XXX: REPLACE THIS WITH CODE USING THE URL FRAMEWORK.
static char *
http_uri_canonify(char *path)
{
@@ -430,7 +397,7 @@ http_sconn_error(http_sconn *sc, uint16_t err)
{
nni_http_res *res;
- if (nni_http_res_init_error(&res, err) != 0) {
+ if (nni_http_res_alloc_error(&res, err) != 0) {
http_sconn_close(sc);
return;
}
@@ -441,32 +408,24 @@ http_sconn_error(http_sconn *sc, uint16_t err)
}
}
sc->res = res;
- nni_http_write_res(sc->http, res, sc->txaio);
+ nni_http_write_res(sc->conn, res, sc->txaio);
}
int
-nni_http_hijack(nni_http_ctx *ctx)
+nni_http_hijack(nni_http_conn *conn)
{
- nni_http_server *s = ctx->server;
+ http_sconn *sc;
- nni_mtx_lock(&s->mtx);
- ctx->http = NULL;
- ctx->req = NULL;
- nni_mtx_unlock(&s->mtx);
- return (0);
-}
+ sc = nni_http_conn_get_ctx(conn);
+ if (sc != NULL) {
+ nni_http_server *s = sc->server;
+ nni_http_conn_set_ctx(conn, NULL);
-int
-nni_http_ctx_stream(nni_http_ctx *ctx, nni_http **hpp)
-{
- nni_http_server *s = ctx->server;
-
- nni_mtx_lock(&s->mtx);
- if ((*hpp = ctx->http) == NULL) {
+ nni_mtx_lock(&s->mtx);
+ sc->conn = NULL;
+ sc->req = NULL;
nni_mtx_unlock(&s->mtx);
- return (NNG_ECLOSED);
}
- nni_mtx_unlock(&s->mtx);
return (0);
}
@@ -498,12 +457,12 @@ http_sconn_rxdone(void *arg)
// cope with HTTP/2.
if ((val = nni_http_req_get_version(req)) == NULL) {
sc->close = true;
- http_sconn_error(sc, NNI_HTTP_STATUS_BAD_REQUEST);
+ http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST);
return;
}
if (strncmp(val, "HTTP/1.", 7) != 0) {
sc->close = true;
- http_sconn_error(sc, NNI_HTTP_STATUS_HTTP_VERSION_NOT_SUPP);
+ http_sconn_error(sc, NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP);
return;
}
if (strcmp(val, "HTTP/1.1") != 0) {
@@ -540,7 +499,8 @@ http_sconn_rxdone(void *arg)
host = nni_http_req_get_header(req, "Host");
if ((host == NULL) && (needhost)) {
// Per RFC 2616 14.23 we have to send 400 status here.
- http_sconn_error(sc, NNI_HTTP_STATUS_BAD_REQUEST);
+ http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST);
+ nni_free(uri, urisz);
return;
}
@@ -616,16 +576,16 @@ http_sconn_rxdone(void *arg)
nni_mtx_unlock(&s->mtx);
if (badmeth) {
http_sconn_error(
- sc, NNI_HTTP_STATUS_METHOD_NOT_ALLOWED);
+ sc, NNG_HTTP_STATUS_METHOD_NOT_ALLOWED);
} else {
- http_sconn_error(sc, NNI_HTTP_STATUS_NOT_FOUND);
+ http_sconn_error(sc, NNG_HTTP_STATUS_NOT_FOUND);
}
return;
}
nni_aio_set_input(sc->cbaio, 0, sc->req);
nni_aio_set_input(sc->cbaio, 1, h);
- nni_aio_set_input(sc->cbaio, 2, sc);
+ nni_aio_set_input(sc->cbaio, 2, sc->conn);
// Technically, probably callback should initialize this with
// start, but we do it instead.
@@ -668,7 +628,7 @@ http_sconn_cbdone(void *arg)
// If its an upgrader, and they didn't give us back a response,
// it means that they took over, and we should just discard
// this session, without closing the underlying channel.
- if (sc->http == NULL) {
+ if (sc->conn == NULL) {
// If this happens, then the session was hijacked.
// We close the context, but the http channel stays up.
http_sconn_close(sc);
@@ -684,14 +644,24 @@ http_sconn_cbdone(void *arg)
nni_http_res_set_header(res, "Connection", "close");
}
sc->res = res;
- nni_http_write_res(sc->http, res, sc->txaio);
+ if (strcmp(nni_http_req_get_method(sc->req), "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);
+ }
+ nni_http_write_res(sc->conn, res, sc->txaio);
} else if (sc->close) {
http_sconn_close(sc);
} else {
// Presumably client already sent a response.
// Wait for another request.
nni_http_req_reset(sc->req);
- nni_http_read_req(sc->http, sc->req, sc->rxaio);
+ nni_http_read_req(sc->conn, sc->req, sc->rxaio);
}
}
@@ -706,7 +676,7 @@ http_sconn_init(http_sconn **scp, nni_http_server *s, nni_plat_tcp_pipe *tcp)
return (NNG_ENOMEM);
}
- if (((rv = nni_http_req_init(&sc->req)) != 0) ||
+ if (((rv = nni_http_req_alloc(&sc->req, NULL)) != 0) ||
((rv = nni_aio_init(&sc->rxaio, http_sconn_rxdone, sc)) != 0) ||
((rv = nni_aio_init(&sc->txaio, http_sconn_txdone, sc)) != 0) ||
((rv = nni_aio_init(&sc->txdataio, http_sconn_txdatdone, sc)) !=
@@ -718,14 +688,15 @@ http_sconn_init(http_sconn **scp, nni_http_server *s, nni_plat_tcp_pipe *tcp)
}
if (s->tls != NULL) {
- rv = nni_http_init_tls(&sc->http, s->tls, tcp);
+ rv = nni_http_conn_init_tls(&sc->conn, s->tls, tcp);
} else {
- rv = nni_http_init_tcp(&sc->http, tcp);
+ rv = nni_http_conn_init_tcp(&sc->conn, tcp);
}
if (rv != 0) {
http_sconn_close(sc);
return (rv);
}
+ nni_http_conn_set_ctx(sc->conn, sc);
*scp = sc;
return (0);
}
@@ -765,7 +736,7 @@ http_server_acccb(void *arg)
sc->server = s;
nni_list_append(&s->conns, sc);
- nni_http_read_req(sc->http, sc->req, sc->rxaio);
+ nni_http_read_req(sc->conn, sc->req, sc->rxaio);
nni_plat_tcp_ep_accept(s->tep, s->accaio);
nni_mtx_unlock(&s->mtx);
}
@@ -816,14 +787,12 @@ nni_http_server_fini(nni_http_server *s)
}
static int
-http_server_init(nni_http_server **serverp, nni_url *url)
+http_server_init(nni_http_server **serverp, const nni_url *url)
{
nni_http_server *s;
int rv;
- const char * port;
nni_aio * aio;
- port = url->u_port;
if ((strcmp(url->u_scheme, "http") != 0) &&
#ifdef NNG_SUPP_TLS
(strcmp(url->u_scheme, "https") != 0) &&
@@ -874,7 +843,7 @@ http_server_init(nni_http_server **serverp, nni_url *url)
http_server_fini(s);
return (rv);
}
- aio->a_addr = &s->addr;
+ nni_aio_set_input(aio, 0, &s->addr);
nni_plat_tcp_resolv(s->hostname, s->port, NNG_AF_UNSPEC, true, aio);
nni_aio_wait(aio);
rv = nni_aio_result(aio);
@@ -889,7 +858,7 @@ http_server_init(nni_http_server **serverp, nni_url *url)
}
int
-nni_http_server_init(nni_http_server **serverp, nni_url *url)
+nni_http_server_init(nni_http_server **serverp, const nni_url *url)
{
int rv;
nni_http_server *s;
@@ -1058,15 +1027,22 @@ nni_http_server_add_handler(nni_http_server *s, nni_http_handler *h)
return (0);
}
-void
+int
nni_http_server_del_handler(nni_http_server *s, nni_http_handler *h)
{
+ int rv = NNG_ENOENT;
+ nni_http_handler *srch;
nni_mtx_lock(&s->mtx);
- if (nni_list_node_active(&h->node)) {
- nni_list_remove(&s->handlers, h);
- h->refcnt--;
+ NNI_LIST_FOREACH (&s->handlers, srch) {
+ if (srch == h) {
+ nni_list_remove(&s->handlers, h);
+ h->refcnt--;
+ rv = 0;
+ break;
+ }
}
nni_mtx_unlock(&s->mtx);
+ return (rv);
}
// Very limited MIME type map. Used only if the handler does not
@@ -1127,6 +1103,11 @@ http_lookup_type(const char *path)
return (NULL);
}
+typedef struct http_file {
+ char *path;
+ char *ctype;
+} http_file;
+
static void
http_handle_file(nni_aio *aio)
{
@@ -1135,31 +1116,36 @@ http_handle_file(nni_aio *aio)
void * data;
size_t size;
int rv;
- char * path = nni_http_handler_get_data(h, 0);
- char * ctype = nni_http_handler_get_data(h, 1);
+ http_file * hf = nni_http_handler_get_data(h);
+ char * path = nni_http_handler_get_data(h);
+ const char * ctype;
+
+ if ((ctype = hf->ctype) == NULL) {
+ ctype = "application/octet-stream";
+ }
// This is a very simplistic file server, suitable only for small
// files. In the future we can use an AIO based file read, where
// we read files a bit at a time, or even mmap them, and serve
// them up chunkwise. Applications could even come up with their own
// caching version of the http handler.
- if ((rv = nni_file_get(path, &data, &size)) != 0) {
+ if ((rv = nni_file_get(hf->path, &data, &size)) != 0) {
uint16_t status;
switch (rv) {
case NNG_ENOMEM:
- status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
break;
case NNG_ENOENT:
- status = NNI_HTTP_STATUS_NOT_FOUND;
+ status = NNG_HTTP_STATUS_NOT_FOUND;
break;
case NNG_EPERM:
- status = NNI_HTTP_STATUS_FORBIDDEN;
+ status = NNG_HTTP_STATUS_FORBIDDEN;
break;
default:
- status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
break;
}
- if ((rv = nni_http_res_init_error(&res, status)) != 0) {
+ if ((rv = nni_http_res_alloc_error(&res, status)) != 0) {
nni_aio_finish_error(aio, rv);
return;
}
@@ -1167,14 +1153,13 @@ http_handle_file(nni_aio *aio)
nni_aio_finish(aio, 0, 0);
return;
}
- if (((rv = nni_http_res_init(&res)) != 0) ||
- ((rv = nni_http_res_set_status(res, NNI_HTTP_STATUS_OK, "OK")) !=
- 0) ||
+ if (((rv = nni_http_res_alloc(&res)) != 0) ||
+ ((rv = nni_http_res_set_status(res, NNG_HTTP_STATUS_OK)) != 0) ||
((rv = nni_http_res_set_header(res, "Content-Type", ctype)) !=
0) ||
((rv = nni_http_res_copy_data(res, data, size)) != 0)) {
if (res != NULL) {
- nni_http_res_fini(res);
+ nni_http_res_free(res);
}
nni_free(data, size);
nni_aio_finish_error(aio, rv);
@@ -1187,10 +1172,14 @@ http_handle_file(nni_aio *aio)
}
static void
-http_file_dtor(nni_http_handler *h)
+http_file_free(void *arg)
{
- char *p = nni_http_handler_get_data(h, 0);
- nni_strfree(p);
+ http_file *hf;
+ if ((hf = arg) != NULL) {
+ nni_strfree(hf->path);
+ nni_strfree(hf->ctype);
+ NNI_FREE_STRUCT(hf);
+ }
}
int
@@ -1198,8 +1187,12 @@ nni_http_handler_init_file_ctype(nni_http_handler **hpp, const char *uri,
const char *path, const char *ctype)
{
nni_http_handler *h;
+ http_file * hf;
int rv;
- char * p;
+
+ if ((hf = NNI_ALLOC_STRUCT(hf)) == NULL) {
+ return (NNG_ENOMEM);
+ }
// Later we might want to do this in the server side, if we support
// custom media type lists on a per-server basis. For now doing this
@@ -1209,19 +1202,19 @@ nni_http_handler_init_file_ctype(nni_http_handler **hpp, const char *uri,
ctype = "application/octet-stream";
}
}
- if ((p = nni_strdup(path)) == NULL) {
+ if (((hf->path = nni_strdup(path)) == NULL) ||
+ ((hf->ctype = nni_strdup(ctype)) == NULL)) {
+ http_file_free(hf);
return (NNG_ENOMEM);
}
if ((rv = nni_http_handler_init(&h, uri, http_handle_file)) != 0) {
- nni_strfree(p);
+ http_file_free(hf);
return (rv);
}
- if (((rv = nni_http_handler_set_data(h, p, 0)) != 0) ||
- ((rv = nni_http_handler_set_data(h, (void *) ctype, 1)) != 0) ||
- ((rv = nni_http_handler_set_dtor(h, http_file_dtor)))) {
- nni_strfree(p);
+ if ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0) {
+ http_file_free(hf);
nni_http_handler_fini(h);
return (rv);
}
@@ -1238,16 +1231,7 @@ nni_http_handler_init_file(
}
static void
-http_directory_dtor(nni_http_handler *h)
-{
- char *path = nni_http_handler_get_data(h, 0);
- char *base = nni_http_handler_get_data(h, 1);
- nni_strfree(path);
- nni_strfree(base);
-}
-
-static void
-http_handle_directory(nni_aio *aio)
+http_handle_dir(nni_aio *aio)
{
nni_http_req * req = nni_aio_get_input(aio, 0);
nni_http_handler *h = nni_aio_get_input(aio, 1);
@@ -1255,8 +1239,9 @@ http_handle_directory(nni_aio *aio)
void * data;
size_t size;
int rv;
- char * path = nni_http_handler_get_data(h, 0);
- const char * base = nni_http_handler_get_data(h, 1); // base uri
+ http_file * hf = nni_http_handler_get_data(h);
+ const char * path = hf->path;
+ const char * base = nni_http_handler_get_uri(h); // base uri
const char * uri = nni_http_req_get_uri(req);
const char * ctype;
char * dst;
@@ -1335,19 +1320,19 @@ http_handle_directory(nni_aio *aio)
switch (rv) {
case NNG_ENOMEM:
- status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
break;
case NNG_ENOENT:
- status = NNI_HTTP_STATUS_NOT_FOUND;
+ status = NNG_HTTP_STATUS_NOT_FOUND;
break;
case NNG_EPERM:
- status = NNI_HTTP_STATUS_FORBIDDEN;
+ status = NNG_HTTP_STATUS_FORBIDDEN;
break;
default:
- status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
break;
}
- if ((rv = nni_http_res_init_error(&res, status)) != 0) {
+ if ((rv = nni_http_res_alloc_error(&res, status)) != 0) {
nni_aio_finish_error(aio, rv);
return;
}
@@ -1356,14 +1341,13 @@ http_handle_directory(nni_aio *aio)
return;
}
- if (((rv = nni_http_res_init(&res)) != 0) ||
- ((rv = nni_http_res_set_status(res, NNI_HTTP_STATUS_OK, "OK")) !=
- 0) ||
+ if (((rv = nni_http_res_alloc(&res)) != 0) ||
+ ((rv = nni_http_res_set_status(res, NNG_HTTP_STATUS_OK)) != 0) ||
((rv = nni_http_res_set_header(res, "Content-Type", ctype)) !=
0) ||
((rv = nni_http_res_copy_data(res, data, size)) != 0)) {
if (res != NULL) {
- nni_http_res_fini(res);
+ nni_http_res_free(res);
}
nni_free(data, size);
nni_aio_finish_error(aio, rv);
@@ -1379,31 +1363,27 @@ int
nni_http_handler_init_directory(
nni_http_handler **hpp, const char *uri, const char *path)
{
+ http_file * hf;
nni_http_handler *h;
int rv;
char * p;
- char * b;
- if ((p = nni_strdup(path)) == NULL) {
+ if ((hf = NNI_ALLOC_STRUCT(hf)) == NULL) {
return (NNG_ENOMEM);
}
- if ((b = nni_strdup(uri)) == NULL) {
- nni_strfree(p);
+ if ((hf->path = nni_strdup(path)) == NULL) {
+ NNI_FREE_STRUCT(hf);
return (NNG_ENOMEM);
}
- if ((rv = nni_http_handler_init(&h, uri, http_handle_directory)) !=
- 0) {
- nni_strfree(p);
+ if ((rv = nni_http_handler_init(&h, uri, http_handle_dir)) != 0) {
+ http_file_free(hf);
return (rv);
}
- if (((rv = nni_http_handler_set_data(h, p, 0)) != 0) ||
- ((rv = nni_http_handler_set_data(h, b, 1)) != 0) ||
- ((rv = nni_http_handler_set_tree(h, true)) != 0) ||
- ((rv = nni_http_handler_set_dtor(h, http_directory_dtor)))) {
- nni_strfree(p);
- nni_strfree(b);
+ if (((rv = nni_http_handler_set_tree(h)) != 0) ||
+ ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0)) {
+ http_file_free(hf);
nni_http_handler_fini(h);
return (rv);
}
@@ -1412,32 +1392,34 @@ nni_http_handler_init_directory(
return (0);
}
+typedef struct http_static {
+ void * data;
+ size_t size;
+ char * ctype;
+} http_static;
+
static void
http_handle_static(nni_aio *aio)
{
- void * data;
- size_t size;
- char * ctype;
+ http_static * hs;
+ const char * ctype;
nni_http_handler *h;
nni_http_res * r = NULL;
int rv;
- h = nni_aio_get_input(aio, 1);
- data = nni_http_handler_get_data(h, 0);
- size = (size_t)(uintptr_t) nni_http_handler_get_data(h, 1);
- ctype = nni_http_handler_get_data(h, 2);
+ h = nni_aio_get_input(aio, 1);
+ hs = nni_http_handler_get_data(h);
- if (ctype == NULL) {
+ if ((ctype = hs->ctype) == NULL) {
ctype = "application/octet-stream";
}
- if (((rv = nni_http_res_init(&r)) != 0) ||
+ if (((rv = nni_http_res_alloc(&r)) != 0) ||
((rv = nni_http_res_set_header(r, "Content-Type", ctype)) != 0) ||
- ((rv = nni_http_res_set_status(r, NNI_HTTP_STATUS_OK, "OK")) !=
- 0) ||
- ((rv = nni_http_res_set_data(r, data, size)) != 0)) {
+ ((rv = nni_http_res_set_status(r, NNG_HTTP_STATUS_OK)) != 0) ||
+ ((rv = nni_http_res_set_data(r, hs->data, hs->size)) != 0)) {
if (r != NULL) {
- nni_http_res_fini(r);
+ nni_http_res_free(r);
}
nni_aio_finish_error(aio, rv);
return;
@@ -1448,12 +1430,15 @@ http_handle_static(nni_aio *aio)
}
static void
-http_static_dtor(nni_http_handler *h)
+http_static_free(void *arg)
{
- void * data = nni_http_handler_get_data(h, 0);
- size_t size = (size_t)(uintptr_t) nni_http_handler_get_data(h, 1);
+ http_static *hs;
- nni_free(data, size);
+ if ((hs = arg) != NULL) {
+ nni_free(hs->data, hs->size);
+ nni_strfree(hs->ctype);
+ NNI_FREE_STRUCT(hs);
+ }
}
int
@@ -1462,23 +1447,26 @@ nni_http_handler_init_static(nni_http_handler **hpp, const char *uri,
{
nni_http_handler *h;
int rv;
- void * dat;
+ http_static * hs;
- if ((dat = nni_alloc(size)) == NULL) {
+ if ((hs = NNI_ALLOC_STRUCT(hs)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ if (((hs->ctype = nni_strdup(ctype)) == NULL) ||
+ ((size > 0) && ((hs->data = nni_alloc(size)) == NULL))) {
+ http_static_free(hs);
return (NNG_ENOMEM);
}
- memcpy(dat, data, size);
+ hs->size = size;
+ memcpy(hs->data, data, size);
if ((rv = nni_http_handler_init(&h, uri, http_handle_static)) != 0) {
- nni_free(dat, size);
+ http_static_free(hs);
return (rv);
}
- if (((rv = nni_http_handler_set_data(h, dat, 0)) != 0) ||
- ((rv = nni_http_handler_set_data(h, (void *) size, 1)) != 0) ||
- ((rv = nni_http_handler_set_data(h, (void *) ctype, 2)) != 0) ||
- ((rv = nni_http_handler_set_dtor(h, http_static_dtor)) != 0)) {
- nni_free(dat, size);
+ if ((rv = nni_http_handler_set_data(h, hs, http_static_free)) != 0) {
+ http_static_free(hs);
nni_http_handler_fini(h);
return (rv);
}
@@ -1541,4 +1529,4 @@ static void
http_server_sys_fini(void)
{
nni_mtx_fini(&http_servers_lk);
-} \ No newline at end of file
+}
diff --git a/src/supplemental/tls/CMakeLists.txt b/src/supplemental/tls/CMakeLists.txt
index e78f1c13..1d0dd08d 100644
--- a/src/supplemental/tls/CMakeLists.txt
+++ b/src/supplemental/tls/CMakeLists.txt
@@ -11,6 +11,7 @@
if (NNG_SUPP_TLS)
set(NNG_SUPP_TLS_MBEDTLS ON)
set(TLS_SOURCES supplemental/tls/tls.h)
+ set(TLS_DEFINES -DNNG_SUPP_TLS)
endif()
# For now we only support the ARM mbedTLS library.
@@ -35,4 +36,5 @@ if (NNG_SUPP_TLS_MBEDTLS)
set(TLS_SOURCES ${TLS_SOURCES} supplemental/tls/mbedtls/tls.c)
endif()
+set(NNG_DEFINES ${NNG_DEFINES} ${TLS_DEFINES} PARENT_SCOPE)
set(NNG_SOURCES ${NNG_SOURCES} ${TLS_SOURCES} PARENT_SCOPE)
diff --git a/src/supplemental/tls/mbedtls/tls.c b/src/supplemental/tls/mbedtls/tls.c
index 4ae842a2..cb0a4bbf 100644
--- a/src/supplemental/tls/mbedtls/tls.c
+++ b/src/supplemental/tls/mbedtls/tls.c
@@ -365,7 +365,7 @@ nni_tls_init(nni_tls **tpp, nng_tls_config *cfg, nni_plat_tcp_pipe *tcp)
static void
nni_tls_cancel(nni_aio *aio, int rv)
{
- nni_tls *tp = aio->a_prov_data;
+ nni_tls *tp = nni_aio_get_prov_data(aio);
nni_mtx_lock(&tp->lk);
if (nni_aio_list_active(aio)) {
nni_aio_list_remove(aio);
@@ -407,11 +407,11 @@ nni_tls_send_cb(void *ctx)
NNI_ASSERT(tp->sendlen <= n);
tp->sendlen -= n;
if (tp->sendlen) {
+ nni_iov iov;
tp->sendoff += n;
-
- aio->a_niov = 1;
- aio->a_iov[0].iov_buf = tp->sendbuf + tp->sendoff;
- aio->a_iov[0].iov_len = tp->sendlen;
+ iov.iov_buf = tp->sendbuf + tp->sendoff;
+ iov.iov_len = tp->sendlen;
+ nni_aio_set_iov(aio, 1, &iov);
nni_aio_set_timeout(aio, NNG_DURATION_INFINITE);
nni_plat_tcp_pipe_send(tp->tcp, aio);
nni_mtx_unlock(&tp->lk);
@@ -434,6 +434,7 @@ static void
nni_tls_recv_start(nni_tls *tp)
{
nni_aio *aio;
+ nni_iov iov;
if (tp->recving || tp->tcp_closed) {
return;
@@ -444,12 +445,12 @@ nni_tls_recv_start(nni_tls *tp)
return;
}
- tp->recving = 1;
- tp->recvoff = 0;
- aio = tp->tcp_recv;
- aio->a_niov = 1;
- aio->a_iov[0].iov_buf = tp->recvbuf;
- aio->a_iov[0].iov_len = NNG_TLS_MAX_RECV_SIZE;
+ tp->recving = 1;
+ tp->recvoff = 0;
+ aio = tp->tcp_recv;
+ iov.iov_buf = tp->recvbuf;
+ iov.iov_len = NNG_TLS_MAX_RECV_SIZE;
+ nni_aio_set_iov(aio, 1, &iov);
nni_aio_set_timeout(tp->tcp_recv, NNG_DURATION_INFINITE);
nni_plat_tcp_pipe_recv(tp->tcp, aio);
}
@@ -498,6 +499,7 @@ int
nni_tls_net_send(void *ctx, const unsigned char *buf, size_t len)
{
nni_tls *tp = ctx;
+ nni_iov iov;
if (len > NNG_TLS_MAX_SEND_SIZE) {
len = NNG_TLS_MAX_SEND_SIZE;
@@ -517,10 +519,9 @@ nni_tls_net_send(void *ctx, const unsigned char *buf, size_t len)
tp->sendlen = len;
tp->sendoff = 0;
memcpy(tp->sendbuf, buf, len);
-
- tp->tcp_send->a_niov = 1;
- tp->tcp_send->a_iov[0].iov_buf = tp->sendbuf;
- tp->tcp_send->a_iov[0].iov_len = len;
+ iov.iov_buf = tp->sendbuf;
+ iov.iov_len = len;
+ nni_aio_set_iov(tp->tcp_send, 1, &iov);
nni_aio_set_timeout(tp->tcp_send, NNG_DURATION_INFINITE);
nni_plat_tcp_pipe_send(tp->tcp, tp->tcp_send);
return (len);
@@ -640,11 +641,15 @@ nni_tls_do_send(nni_tls *tp)
int n;
uint8_t *buf = NULL;
size_t len = 0;
+ nni_iov *iov;
+ int niov;
- for (int i = 0; i < aio->a_niov; i++) {
- if (aio->a_iov[i].iov_len != 0) {
- buf = aio->a_iov[i].iov_buf;
- len = aio->a_iov[i].iov_len;
+ nni_aio_get_iov(aio, &niov, &iov);
+
+ for (int i = 0; i < niov; i++) {
+ if (iov[i].iov_len != 0) {
+ buf = iov[i].iov_buf;
+ len = iov[i].iov_len;
break;
}
}
@@ -682,11 +687,15 @@ nni_tls_do_recv(nni_tls *tp)
int n;
uint8_t *buf = NULL;
size_t len = 0;
+ nni_iov *iov;
+ int niov;
+
+ nni_aio_get_iov(aio, &niov, &iov);
- for (int i = 0; i < aio->a_niov; i++) {
- if (aio->a_iov[i].iov_len != 0) {
- buf = aio->a_iov[i].iov_buf;
- len = aio->a_iov[i].iov_len;
+ for (int i = 0; i < niov; i++) {
+ if (iov[i].iov_len != 0) {
+ buf = iov[i].iov_buf;
+ len = iov[i].iov_len;
break;
}
}
@@ -865,7 +874,7 @@ nng_tls_config_own_cert(
pem = (const uint8_t *) key;
len = strlen(key) + 1;
rv = mbedtls_pk_parse_key(&ck->key, pem, len, (const uint8_t *) pass,
- pass != NULL ? strlen(pass) : 0);
+ pass != NULL ? strlen(pass) : 0);
if (rv != 0) {
rv = nni_tls_mkerr(rv);
goto err;
diff --git a/src/supplemental/tls/tls.h b/src/supplemental/tls/tls.h
index 57b552d7..4dd94290 100644
--- a/src/supplemental/tls/tls.h
+++ b/src/supplemental/tls/tls.h
@@ -34,8 +34,8 @@ extern void nni_tls_config_hold(nng_tls_config *);
extern int nni_tls_init(nni_tls **, nng_tls_config *, nni_plat_tcp_pipe *);
extern void nni_tls_close(nni_tls *);
extern void nni_tls_fini(nni_tls *);
-extern void nni_tls_send(nni_tls *, nni_aio *);
-extern void nni_tls_recv(nni_tls *, nni_aio *);
+extern void nni_tls_send(nni_tls *, nng_aio *);
+extern void nni_tls_recv(nni_tls *, nng_aio *);
extern int nni_tls_sockname(nni_tls *, nni_sockaddr *);
extern int nni_tls_peername(nni_tls *, nni_sockaddr *);
diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c
index 8e75490b..ad4ce196 100644
--- a/src/supplemental/websocket/websocket.c
+++ b/src/supplemental/websocket/websocket.c
@@ -47,7 +47,7 @@ struct nni_ws {
nni_aio * httpaio;
nni_aio * connaio; // connect aio
nni_aio * useraio; // user aio, during HTTP negotiation
- nni_http * http;
+ nni_http_conn * http;
nni_http_req * req;
nni_http_res * res;
char * reqhdrs;
@@ -411,10 +411,10 @@ ws_close_cb(void *arg)
// we are done, and its time to abort everything else.
nni_mtx_lock(&ws->mtx);
- nni_http_close(ws->http);
- nni_aio_cancel(ws->txaio, NNG_ECLOSED);
- nni_aio_cancel(ws->rxaio, NNG_ECLOSED);
- nni_aio_cancel(ws->httpaio, NNG_ECLOSED);
+ nni_http_conn_close(ws->http);
+ nni_aio_abort(ws->txaio, NNG_ECLOSED);
+ nni_aio_abort(ws->rxaio, NNG_ECLOSED);
+ nni_aio_abort(ws->httpaio, NNG_ECLOSED);
// This list (receive) should be empty.
while ((wm = nni_list_first(&ws->rxmsgs)) != NULL) {
@@ -463,8 +463,8 @@ ws_close(nni_ws *ws, uint16_t code)
// pending connect request.
if (!ws->closed) {
// ABORT connection negotiation.
- nni_aio_cancel(ws->connaio, NNG_ECLOSED);
- nni_aio_cancel(ws->httpaio, NNG_ECLOSED);
+ nni_aio_abort(ws->connaio, NNG_ECLOSED);
+ nni_aio_abort(ws->httpaio, NNG_ECLOSED);
ws_send_close(ws, code);
}
@@ -484,6 +484,8 @@ ws_start_write(nni_ws *ws)
{
ws_frame *frame;
ws_msg * wm;
+ nni_iov iov[2];
+ int niov;
if ((ws->txframe != NULL) || (!ws->ready)) {
return; // busy
@@ -498,21 +500,23 @@ ws_start_write(nni_ws *ws)
NNI_ASSERT(frame != NULL);
// Push it out.
- ws->txframe = frame;
- ws->txaio->a_niov = frame->len > 0 ? 2 : 1;
- ws->txaio->a_iov[0].iov_len = frame->hlen;
- ws->txaio->a_iov[0].iov_buf = frame->head;
+ ws->txframe = frame;
+ niov = 1;
+ iov[0].iov_len = frame->hlen;
+ iov[0].iov_buf = frame->head;
if (frame->len > 0) {
- ws->txaio->a_iov[1].iov_len = frame->len;
- ws->txaio->a_iov[1].iov_buf = frame->buf;
+ niov++;
+ iov[1].iov_len = frame->len;
+ iov[1].iov_buf = frame->buf;
}
+ nni_aio_set_iov(ws->txaio, niov, iov);
nni_http_write_full(ws->http, ws->txaio);
}
static void
ws_cancel_close(nni_aio *aio, int rv)
{
- nni_ws *ws = aio->a_prov_data;
+ nni_ws *ws = nni_aio_get_prov_data(aio);
nni_mtx_lock(&ws->mtx);
if (ws->wclose) {
ws->wclose = false;
@@ -567,7 +571,7 @@ ws_write_cb(void *arg)
}
ws->closed = true;
- nni_http_close(ws->http);
+ nni_http_conn_close(ws->http);
nni_mtx_unlock(&ws->mtx);
return;
}
@@ -598,11 +602,11 @@ ws_write_cancel(nni_aio *aio, int rv)
// Is this aio active? We can tell by looking at the
// active tx frame.
- wm = aio->a_prov_data;
+ wm = nni_aio_get_prov_data(aio);
ws = wm->ws;
nni_mtx_lock(&ws->mtx);
if (((frame = ws->txframe) != NULL) && (frame->wmsg == wm)) {
- nni_aio_cancel(ws->txaio, rv);
+ nni_aio_abort(ws->txaio, rv);
// We will wait for callback on the txaio to finish aio.
} else if (nni_list_active(&ws->txmsgs, wm)) {
// If scheduled, just need to remove node and complete it.
@@ -731,6 +735,7 @@ ws_start_read(nni_ws *ws)
ws_frame *frame;
ws_msg * wm;
nni_aio * aio;
+ nni_iov iov;
if ((ws->rxframe != NULL) || ws->closed) {
return; // already reading or closed
@@ -755,10 +760,10 @@ ws_start_read(nni_ws *ws)
frame->len = 0;
ws->rxframe = frame;
- aio = ws->rxaio;
- aio->a_niov = 1;
- aio->a_iov[0].iov_len = 2; // We want the first two bytes.
- aio->a_iov[0].iov_buf = frame->head;
+ aio = ws->rxaio;
+ iov.iov_len = 2; // We want the first two bytes.
+ iov.iov_buf = frame->head;
+ nni_aio_set_iov(aio, 1, &iov);
nni_http_read_full(ws->http, aio);
}
@@ -891,9 +896,10 @@ ws_read_cb(void *arg)
// If we didn't read the full header yet, then read
// the rest of it.
if (frame->hlen != 2) {
- aio->a_niov = 1;
- aio->a_iov[0].iov_buf = frame->head + 2;
- aio->a_iov[0].iov_len = frame->hlen - 2;
+ nni_iov iov;
+ iov.iov_buf = frame->head + 2;
+ iov.iov_len = frame->hlen - 2;
+ nni_aio_set_iov(aio, 1, &iov);
nni_http_read_full(ws->http, aio);
nni_mtx_unlock(&ws->mtx);
return;
@@ -954,6 +960,8 @@ ws_read_cb(void *arg)
// If we expected data, then ask for it.
if (frame->len != 0) {
+ nni_iov iov;
+
// Short frames can avoid an alloc
if (frame->len < 126) {
frame->buf = frame->sdata;
@@ -968,9 +976,9 @@ ws_read_cb(void *arg)
frame->bufsz = frame->len;
}
- aio->a_niov = 1;
- aio->a_iov[0].iov_buf = frame->buf;
- aio->a_iov[0].iov_len = frame->len;
+ iov.iov_buf = frame->buf;
+ iov.iov_len = frame->len;
+ nni_aio_set_iov(aio, 1, &iov);
nni_http_read_full(ws->http, aio);
nni_mtx_unlock(&ws->mtx);
return;
@@ -988,13 +996,13 @@ ws_read_cb(void *arg)
static void
ws_read_cancel(nni_aio *aio, int rv)
{
- ws_msg *wm = aio->a_prov_data;
+ ws_msg *wm = nni_aio_get_prov_data(aio);
nni_ws *ws = wm->ws;
nni_mtx_lock(&ws->mtx);
if (wm == nni_list_first(&ws->rxmsgs)) {
// Cancellation will percolate back up.
- nni_aio_cancel(ws->rxaio, rv);
+ nni_aio_abort(ws->rxaio, rv);
} else if (nni_list_active(&ws->rxmsgs, wm)) {
nni_list_remove(&ws->rxmsgs, wm);
ws_msg_fini(wm);
@@ -1124,13 +1132,13 @@ ws_fini(void *arg)
nni_mtx_unlock(&ws->mtx);
if (ws->http) {
- nni_http_fini(ws->http);
+ nni_http_conn_fini(ws->http);
}
if (ws->req) {
- nni_http_req_fini(ws->req);
+ nni_http_req_free(ws->req);
}
if (ws->res) {
- nni_http_res_fini(ws->res);
+ nni_http_res_free(ws->res);
}
nni_strfree(ws->reqhdrs);
@@ -1201,7 +1209,7 @@ ws_http_cb_dialer(nni_ws *ws, nni_aio *aio)
// If we have no response structure, then this was completion of the
// send of the request. Prepare an empty response, and read it.
if (ws->res == NULL) {
- if ((rv = nni_http_res_init(&ws->res)) != 0) {
+ if ((rv = nni_http_res_alloc(&ws->res)) != 0) {
goto err;
}
nni_http_read_res(ws->http, ws->res, ws->httpaio);
@@ -1211,17 +1219,17 @@ ws_http_cb_dialer(nni_ws *ws, nni_aio *aio)
status = nni_http_res_get_status(ws->res);
switch (status) {
- case NNI_HTTP_STATUS_SWITCHING:
+ case NNG_HTTP_STATUS_SWITCHING:
break;
- case NNI_HTTP_STATUS_FORBIDDEN:
- case NNI_HTTP_STATUS_UNAUTHORIZED:
+ case NNG_HTTP_STATUS_FORBIDDEN:
+ case NNG_HTTP_STATUS_UNAUTHORIZED:
rv = NNG_EPERM;
goto err;
- case NNI_HTTP_STATUS_NOT_FOUND:
- case NNI_HTTP_STATUS_METHOD_NOT_ALLOWED:
+ case NNG_HTTP_STATUS_NOT_FOUND:
+ case NNG_HTTP_STATUS_METHOD_NOT_ALLOWED:
rv = NNG_ECONNREFUSED; // Treat these as refusals.
goto err;
- case NNI_HTTP_STATUS_BAD_REQUEST:
+ case NNG_HTTP_STATUS_BAD_REQUEST:
default:
// Perhaps we should use NNG_ETRANERR...
rv = NNG_EPROTO;
@@ -1360,36 +1368,30 @@ ws_handler(nni_aio *aio)
{
nni_ws_listener * l;
nni_ws * ws;
- nni_http * http;
+ nni_http_conn * conn;
nni_http_req * req;
nni_http_res * res;
nni_http_handler *h;
- nni_http_ctx * ctx;
const char * ptr;
const char * proto;
uint16_t status;
int rv;
char key[29];
- req = nni_aio_get_input(aio, 0);
- h = nni_aio_get_input(aio, 1);
- ctx = nni_aio_get_input(aio, 2);
- l = nni_http_handler_get_data(h, 0);
-
- if ((rv = nni_http_ctx_stream(ctx, &http)) != 0) {
- nni_aio_finish_error(aio, rv);
- return;
- }
+ req = nni_aio_get_input(aio, 0);
+ h = nni_aio_get_input(aio, 1);
+ conn = nni_aio_get_input(aio, 2);
+ l = nni_http_handler_get_data(h);
// Now check the headers, etc.
if (strcmp(nni_http_req_get_version(req), "HTTP/1.1") != 0) {
- status = NNI_HTTP_STATUS_HTTP_VERSION_NOT_SUPP;
+ status = NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP;
goto err;
}
if (strcmp(nni_http_req_get_method(req), "GET") != 0) {
// HEAD request. We can't really deal with it.
- status = NNI_HTTP_STATUS_BAD_REQUEST;
+ status = NNG_HTTP_STATUS_BAD_REQUEST;
goto err;
}
@@ -1399,7 +1401,7 @@ ws_handler(nni_aio *aio)
if ((((ptr = GETH("Content-Length")) != NULL) && (atoi(ptr) > 0)) ||
(((ptr = GETH("Transfer-Encoding")) != NULL) &&
(nni_strcasestr(ptr, "chunked") != NULL))) {
- status = NNI_HTTP_STATUS_PAYLOAD_TOO_LARGE;
+ status = NNG_HTTP_STATUS_PAYLOAD_TOO_LARGE;
goto err;
}
@@ -1410,13 +1412,13 @@ ws_handler(nni_aio *aio)
(!ws_contains_word(ptr, "upgrade")) ||
((ptr = GETH("Sec-WebSocket-Version")) == NULL) ||
(strcmp(ptr, "13") != 0)) {
- status = NNI_HTTP_STATUS_BAD_REQUEST;
+ status = NNG_HTTP_STATUS_BAD_REQUEST;
goto err;
}
if (((ptr = GETH("Sec-WebSocket-Key")) == NULL) ||
(ws_make_accept(ptr, key) != 0)) {
- status = NNI_HTTP_STATUS_BAD_REQUEST;
+ status = NNG_HTTP_STATUS_BAD_REQUEST;
goto err;
}
@@ -1427,51 +1429,50 @@ ws_handler(nni_aio *aio)
proto = GETH("Sec-WebSocket-Protocol");
if (proto == NULL) {
if (l->proto != NULL) {
- status = NNI_HTTP_STATUS_BAD_REQUEST;
+ status = NNG_HTTP_STATUS_BAD_REQUEST;
goto err;
}
} else if ((l->proto == NULL) ||
(!ws_contains_word(l->proto, proto))) {
- status = NNI_HTTP_STATUS_BAD_REQUEST;
+ status = NNG_HTTP_STATUS_BAD_REQUEST;
goto err;
}
- if ((rv = nni_http_res_init(&res)) != 0) {
+ if ((rv = nni_http_res_alloc(&res)) != 0) {
// Give a chance to reply to client.
- status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
goto err;
}
- if (nni_http_res_set_status(
- res, NNI_HTTP_STATUS_SWITCHING, "Switching Protocols") != 0) {
- nni_http_res_fini(res);
- status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ if (nni_http_res_set_status(res, NNG_HTTP_STATUS_SWITCHING) != 0) {
+ nni_http_res_free(res);
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
goto err;
}
if ((SETH("Connection", "Upgrade") != 0) ||
(SETH("Upgrade", "websocket") != 0) ||
(SETH("Sec-WebSocket-Accept", key) != 0)) {
- status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR;
- nni_http_res_fini(res);
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ nni_http_res_free(res);
goto err;
}
if ((proto != NULL) && (SETH("Sec-WebSocket-Protocol", proto) != 0)) {
- status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR;
- nni_http_res_fini(res);
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ nni_http_res_free(res);
goto err;
}
if (l->hookfn != NULL) {
rv = l->hookfn(l->hookarg, req, res);
if (rv != 0) {
- nni_http_res_fini(res);
+ nni_http_res_free(res);
nni_aio_finish_error(aio, rv);
return;
}
if (nni_http_res_get_status(res) !=
- NNI_HTTP_STATUS_SWITCHING) {
+ 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
@@ -1479,7 +1480,7 @@ ws_handler(nni_aio *aio)
// (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_http_req_fini(req);
+ nni_http_req_free(req);
nni_aio_set_output(aio, 0, res);
nni_aio_finish(aio, 0, 0);
return;
@@ -1492,12 +1493,12 @@ ws_handler(nni_aio *aio)
// We are good to go, provided we can get the websocket struct,
// and send the reply.
if ((rv = ws_init(&ws)) != 0) {
- nni_http_req_fini(req);
- nni_http_res_fini(res);
- status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR;
+ nni_http_req_free(req);
+ nni_http_res_free(res);
+ status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR;
goto err;
}
- ws->http = http;
+ ws->http = conn;
ws->req = req;
ws->res = res;
ws->mode = NNI_EP_MODE_LISTEN;
@@ -1506,14 +1507,14 @@ ws_handler(nni_aio *aio)
nni_list_append(&l->reply, ws);
nni_aio_set_data(ws->httpaio, 0, l);
- nni_http_write_res(http, res, ws->httpaio);
- (void) nni_http_hijack(ctx);
+ nni_http_write_res(conn, res, ws->httpaio);
+ (void) nni_http_hijack(conn);
nni_aio_set_output(aio, 0, NULL);
nni_aio_finish(aio, 0, 0);
return;
err:
- if ((rv = nni_http_res_init_error(&res, status)) != 0) {
+ if ((rv = nni_http_res_alloc_error(&res, status)) != 0) {
nni_aio_finish_error(aio, rv);
} else {
nni_aio_set_output(aio, 0, res);
@@ -1588,7 +1589,7 @@ nni_ws_listener_proto(nni_ws_listener *l, const char *proto)
static void
ws_accept_cancel(nni_aio *aio, int rv)
{
- nni_ws_listener *l = aio->a_prov_data;
+ nni_ws_listener *l = nni_aio_get_prov_data(aio);
nni_mtx_lock(&l->mtx);
if (nni_aio_list_active(aio)) {
@@ -1723,7 +1724,7 @@ ws_conn_cb(void *arg)
nni_ws_dialer *d;
nni_ws * ws;
nni_aio * uaio;
- nni_http * http;
+ nni_http_conn *http;
nni_http_req * req = NULL;
int rv;
uint8_t raw[16];
@@ -1757,7 +1758,7 @@ ws_conn_cb(void *arg)
nni_aio_set_output(ws->connaio, 0, NULL);
if (uaio == NULL) {
// This request was canceled for some reason.
- nni_http_fini(http);
+ nni_http_conn_fini(http);
nni_mtx_unlock(&ws->mtx);
nni_ws_fini(ws);
return;
@@ -1770,11 +1771,7 @@ ws_conn_cb(void *arg)
wskey[24] = '\0';
#define SETH(h, v) nni_http_req_set_header(req, h, v)
- if ((rv != 0) || ((rv = nni_http_req_init(&req)) != 0) ||
- ((rv = nni_http_req_set_uri(req, d->url->u_rawpath)) != 0) ||
- ((rv = nni_http_req_set_version(req, "HTTP/1.1")) != 0) ||
- ((rv = nni_http_req_set_method(req, "GET")) != 0) ||
- ((rv = SETH("Host", d->url->u_host)) != 0) ||
+ if ((rv != 0) || ((rv = nni_http_req_alloc(&req, d->url)) != 0) ||
((rv = SETH("Upgrade", "websocket")) != 0) ||
((rv = SETH("Connection", "Upgrade")) != 0) ||
((rv = SETH("Sec-WebSocket-Key", wskey)) != 0) ||
@@ -1805,10 +1802,10 @@ err:
nni_aio_finish_error(uaio, rv);
nni_mtx_unlock(&ws->mtx);
if (http != NULL) {
- nni_http_fini(http);
+ nni_http_conn_fini(http);
}
if (req != NULL) {
- nni_http_req_fini(req);
+ nni_http_req_free(req);
}
nni_ws_fini(ws);
}
@@ -1920,12 +1917,12 @@ nni_ws_dialer_proto(nni_ws_dialer *d, const char *proto)
static void
ws_dial_cancel(nni_aio *aio, int rv)
{
- nni_ws *ws = aio->a_prov_data;
+ nni_ws *ws = nni_aio_get_prov_data(aio);
nni_mtx_lock(&ws->mtx);
if (aio == ws->useraio) {
- nni_aio_cancel(ws->connaio, rv);
- nni_aio_cancel(ws->httpaio, rv);
+ nni_aio_abort(ws->connaio, rv);
+ nni_aio_abort(ws->httpaio, rv);
ws->useraio = NULL;
nni_aio_finish_error(aio, rv);
}
diff --git a/src/supplemental/websocket/websocket.h b/src/supplemental/websocket/websocket.h
index 2cabb9cc..546f41a9 100644
--- a/src/supplemental/websocket/websocket.h
+++ b/src/supplemental/websocket/websocket.h
@@ -13,15 +13,11 @@
#include <stdbool.h>
-// Pre-defined types for some prototypes. These are from other subsystems.
-typedef struct nni_http_req nni_http_req;
-typedef struct nni_http_res nni_http_res;
-
typedef struct nni_ws nni_ws;
typedef struct nni_ws_listener nni_ws_listener;
typedef struct nni_ws_dialer nni_ws_dialer;
-typedef int (*nni_ws_listen_hook)(void *, nni_http_req *, nni_http_res *);
+typedef int (*nni_ws_listen_hook)(void *, nng_http_req *, nng_http_res *);
// Specify URL as ws://[<host>][:port][/path]
// If host is missing, INADDR_ANY is assumed. If port is missing,
@@ -34,7 +30,7 @@ extern void nni_ws_listener_fini(nni_ws_listener *);
extern void nni_ws_listener_close(nni_ws_listener *);
extern int nni_ws_listener_proto(nni_ws_listener *, const char *);
extern int nni_ws_listener_listen(nni_ws_listener *);
-extern void nni_ws_listener_accept(nni_ws_listener *, nni_aio *);
+extern void nni_ws_listener_accept(nni_ws_listener *, nng_aio *);
extern void nni_ws_listener_hook(
nni_ws_listener *, nni_ws_listen_hook, void *);
extern int nni_ws_listener_set_tls(nni_ws_listener *, nng_tls_config *);
@@ -45,7 +41,7 @@ extern void nni_ws_dialer_fini(nni_ws_dialer *);
extern void nni_ws_dialer_close(nni_ws_dialer *);
extern int nni_ws_dialer_proto(nni_ws_dialer *, const char *);
extern int nni_ws_dialer_header(nni_ws_dialer *, const char *, const char *);
-extern void nni_ws_dialer_dial(nni_ws_dialer *, nni_aio *);
+extern void nni_ws_dialer_dial(nni_ws_dialer *, nng_aio *);
extern int nni_ws_dialer_set_tls(nni_ws_dialer *, nng_tls_config *);
extern int nni_ws_dialer_get_tls(nni_ws_dialer *, nng_tls_config **);
@@ -54,10 +50,10 @@ extern int nni_ws_dialer_get_tls(nni_ws_dialer *, nng_tls_config **);
// not confirm the server's response at the HTTP level. (It can still issue
// a websocket close).
-extern void nni_ws_send_msg(nni_ws *, nni_aio *);
-extern void nni_ws_recv_msg(nni_ws *, nni_aio *);
-extern nni_http_res *nni_ws_response(nni_ws *);
-extern nni_http_req *nni_ws_request(nni_ws *);
+extern void nni_ws_send_msg(nni_ws *, nng_aio *);
+extern void nni_ws_recv_msg(nni_ws *, nng_aio *);
+extern nng_http_res *nni_ws_response(nni_ws *);
+extern nng_http_req *nni_ws_request(nni_ws *);
extern int nni_ws_sock_addr(nni_ws *, nni_sockaddr *);
extern int nni_ws_peer_addr(nni_ws *, nni_sockaddr *);
extern void nni_ws_close(nni_ws *);
@@ -69,4 +65,4 @@ extern bool nni_ws_tls_verified(nni_ws *);
// The implementation will send periodic PINGs, and respond with PONGs.
-#endif // NNG_SUPPLEMENTAL_WEBSOCKET_WEBSOCKET_H \ No newline at end of file
+#endif // NNG_SUPPLEMENTAL_WEBSOCKET_WEBSOCKET_H