diff options
| -rw-r--r-- | docs/ref/api/http.md | 18 | ||||
| -rw-r--r-- | docs/ref/xref.md | 2 | ||||
| -rw-r--r-- | include/nng/http.h | 7 | ||||
| -rw-r--r-- | src/supplemental/http/http_api.h | 3 | ||||
| -rw-r--r-- | src/supplemental/http/http_conn.c | 10 | ||||
| -rw-r--r-- | src/supplemental/http/http_public.c | 12 | ||||
| -rw-r--r-- | src/supplemental/http/http_server_test.c | 82 |
7 files changed, 134 insertions, 0 deletions
diff --git a/docs/ref/api/http.md b/docs/ref/api/http.md index 772fe2ad..05821cbc 100644 --- a/docs/ref/api/http.md +++ b/docs/ref/api/http.md @@ -557,6 +557,17 @@ This function returns immediately, with no return value. Completion of the operation is signaled via the _aio_, and the final result may be obtained via [`nng_aio_result`]. +### Socket Addresses + +```c +nng_err nng_http_local_address(nng_http *conn, nng_sockaddr *addr); +nng_err nng_http_remote_address(nng_http *conn, nng_sockaddr *addr); +``` + +The {{i:`nng_http_local_address`}} and {{i:`nng_http_remote_address`}} functions +can be used to determine the local and remote addresses for an HTTP connection. +This can only be done while the connection is alive. + ### Response Body ## Server API @@ -781,6 +792,13 @@ exactly the value of the `Host` header sent by the client. > The port number may be ignored; at present the HTTP server framework > does not support a single server listening on different ports concurrently. +### Detecting Addresses + +The [`nng_http_local_address`] and [`nng_http_remote_address`] functions +can be used to determine the local and remote addresses for an HTTP connection +on the server side (in a handler) just like the can be for HTTP clients +This can be useful to provide different handling behaviors based on network identity. + ### Handling an Entire Tree ```c diff --git a/docs/ref/xref.md b/docs/ref/xref.md index ee561cd0..cbaeb7c1 100644 --- a/docs/ref/xref.md +++ b/docs/ref/xref.md @@ -312,6 +312,8 @@ [`nng_http_handler_set_data`]: ../api/http.md#setting-the-callback-argument [`nng_http_handler_set_tree`]: ../api/http.md#handling-an-entire-tree [`nng_http_transact`]: ../api/http.md#submitting-the-transaction +[`nng_http_local_address`]: ../api/http.md#socket-addresses +[`nng_http_remote_address`]: ../api/http.md#socket-addresses <!-- HTTP Status --> diff --git a/include/nng/http.h b/include/nng/http.h index 864dcc4f..0c1c39e0 100644 --- a/include/nng/http.h +++ b/include/nng/http.h @@ -180,6 +180,13 @@ NNG_DECL void nng_http_set_method(nng_http *, const char *); // nng_http_get_method returns the method. NNG_DECL const char *nng_http_get_method(nng_http *); +// nng_http_local_address obtains the local socket address for the connection. +NNG_DECL nng_err nng_http_local_address(nng_http *, nng_sockaddr *); + +// nng_http_remote_address obtains the remote socket address for the +// connection. +NNG_DECL nng_err nng_http_remote_address(nng_http *, nng_sockaddr *); + // These functions set (replacing any existing), or add (appending) // a header to either the request or response. Clients modify the request // headers, and servers (and callbacks on the server) modify response headers. diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index 6acc1ba5..74472f50 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -72,6 +72,9 @@ extern void nni_http_read_chunks( extern nni_http_req *nni_http_conn_req(nni_http_conn *); extern nni_http_res *nni_http_conn_res(nni_http_conn *); +extern nng_err nni_http_get_addr( + nni_http_conn *, const char *, nng_sockaddr *); + // 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 *); diff --git a/src/supplemental/http/http_conn.c b/src/supplemental/http/http_conn.c index 6f2ecef6..ac549649 100644 --- a/src/supplemental/http/http_conn.c +++ b/src/supplemental/http/http_conn.c @@ -159,6 +159,16 @@ nni_http_conn_close(nni_http_conn *conn) nni_mtx_unlock(&conn->mtx); } +nng_err +nni_http_get_addr(nni_http_conn *conn, const char *opt, nng_sockaddr *addrp) +{ + nng_err rv; + nni_mtx_lock(&conn->mtx); + rv = nng_stream_get_addr(conn->sock, opt, addrp); + nni_mtx_unlock(&conn->mtx); + return (rv); +} + // http_buf_pull_up pulls the content of the read buffer back to the // beginning, so that the next read can go at the end. This avoids the problem // of dealing with a read that might wrap. diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index e63c5f96..8c225e5e 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -307,6 +307,18 @@ nng_http_read_response(nng_http *conn, nng_aio *aio) } nng_err +nng_http_remote_address(nng_http *conn, nng_sockaddr *addrp) +{ + return (nni_http_get_addr(conn, NNG_OPT_REMADDR, addrp)); +} + +nng_err +nng_http_local_address(nng_http *conn, nng_sockaddr *addrp) +{ + return (nni_http_get_addr(conn, NNG_OPT_LOCADDR, addrp)); +} + +nng_err nng_http_handler_alloc( nng_http_handler **hp, const char *uri, nng_http_handler_func cb) { diff --git a/src/supplemental/http/http_server_test.c b/src/supplemental/http/http_server_test.c index ed63e136..d299cb97 100644 --- a/src/supplemental/http/http_server_test.c +++ b/src/supplemental/http/http_server_test.c @@ -14,6 +14,9 @@ #include <complex.h> #include <nng/http.h> #include <nng/nng.h> +#ifndef _WIN32 +#include <arpa/inet.h> // for endianness functions +#endif #include "../../testing/nuts.h" @@ -135,6 +138,56 @@ httpecho(nng_http *conn, void *arg, nng_aio *aio) } static void +httpaddrcheck(nng_http *conn, void *arg, nng_aio *aio) +{ + nng_err rv; + void *body; + size_t len; + nng_sockaddr loc; + nng_sockaddr rem; + + NNI_ARG_UNUSED(arg); + + if (((rv = nng_http_local_address(conn, &loc)) != NNG_OK) || + ((rv = nng_http_remote_address(conn, &rem)) != NNG_OK)) { + nng_aio_finish(aio, rv); + return; + } + if ((loc.s_family != NNG_AF_INET) || (rem.s_family != NNG_AF_INET)) { + nng_http_set_status(conn, NNG_HTTP_STATUS_BAD_REQUEST, + "Adddresses were not INET"); + nng_aio_finish(aio, 0); + return; + } + if ((loc.s_in.sa_addr != htonl(0x7F000001)) || + (rem.s_in.sa_addr != htonl(0x7F000001))) { + nng_http_set_status(conn, NNG_HTTP_STATUS_BAD_REQUEST, + "Adddresses were not localhost"); + nng_aio_finish(aio, 0); + return; + } + if ((loc.s_in.sa_port == 0) || (rem.s_in.sa_port == 0) || + (loc.s_in.sa_port == rem.s_in.sa_port)) { + nng_http_set_status( + conn, NNG_HTTP_STATUS_BAD_REQUEST, "Port checks failed"); + nng_aio_finish(aio, 0); + return; + } + + nng_http_get_body(conn, &body, &len); + + if (((rv = nng_http_copy_body(conn, body, len)) != 0) || + ((rv = nng_http_set_header(conn, "Content-type", "text/plain")) != + 0)) { + nng_aio_finish(aio, rv); + return; + } + + nng_http_set_status(conn, NNG_HTTP_STATUS_OK, NULL); + nng_aio_finish(aio, 0); +} + +static void server_setup(struct server_test *st, nng_http_handler *h) { nng_sockaddr sa; @@ -663,6 +716,34 @@ test_server_post_handler(void) } static void +test_server_addrs_handler(void) +{ + struct server_test st; + nng_http_handler *h; + char txdata[5]; + char *rxdata; + size_t size; + + NUTS_PASS(nng_http_handler_alloc(&h, "/addrs", httpaddrcheck)); + nng_http_handler_set_method(h, "POST"); + + server_setup(&st, h); + + snprintf(txdata, sizeof(txdata), "1234"); + + NUTS_PASS(nng_http_set_uri(st.conn, "/addrs", NULL)); + nng_http_set_body(st.conn, txdata, strlen(txdata)); + nng_http_set_method(st.conn, "POST"); + NUTS_PASS(httpdo(&st, (void **) &rxdata, &size)); + NUTS_HTTP_STATUS(st.conn, NNG_HTTP_STATUS_OK); + NUTS_TRUE(size == strlen(txdata)); + NUTS_TRUE(strncmp(txdata, rxdata, size) == 0); + nng_free(rxdata, size); + + server_free(&st); +} + +static void test_server_get_redirect(void) { const char *dest; @@ -1170,6 +1251,7 @@ NUTS_TESTS = { { "server tree redirect", test_server_tree_redirect }, { "server post redirect", test_server_post_redirect }, { "server post echo tree", test_server_post_echo_tree }, + { "server address checks", test_server_addrs_handler }, { "server error page", test_server_error_page }, { "server multiple trees", test_server_multiple_trees }, { "server serve directory", test_serve_directory }, |
