aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/ref/api/http.md18
-rw-r--r--docs/ref/xref.md2
-rw-r--r--include/nng/http.h7
-rw-r--r--src/supplemental/http/http_api.h3
-rw-r--r--src/supplemental/http/http_conn.c10
-rw-r--r--src/supplemental/http/http_public.c12
-rw-r--r--src/supplemental/http/http_server_test.c82
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 },