HTTP Support

NNG offers support for creation of HTTP clients, and servers. NNG supports HTTP/1.1 at present, and supports a subset of functionality, but the support should be sufficient for simple clients, REST API servers, static content servers, and gateways between HTTP and and other protocols. It also provides support for WebSocket based connections.

HTTP follows a request/reply model, where a client issues a request, and the server is expected to reply. Every request is answered with a single reply.

Header File

#include <nng/http.h>

Unlike the rest of NNG, the HTTP API in NNG requires including nng/http.h. It is not necessary to include the main nng/nng.h header, it will be included transitively by nng/http.h.

Connection Object

typedef struct nng_http nng_http;

The nng_http object represents a single logical HTTP connection to the server. For HTTP/1.1 and earlier, this will correspond to a single TCP connection, but the object also contains state relating to the transaction, such as the hostname used, HTTP method used, request headers, response status, response headers, and so forth.

An nng_http object can be reused, unless closed, so that additional transactions can be performed after the first transaction is complete.

At any given point in time, an nng_http object can only refer to a single HTTP transaction. In NNG, these nng_http objects are used in both the client and server APIs.

The nng_http object is created by either nng_http_client_connect or by an HTTP server object which then passes it to an [nng_http_handler] callback function.

HTTP Method

void nng_http_set_method(nng_http *conn, const char *method);
const char *nng_http_get_method(nng_http *conn);

Each HTTP transaction has a single verb, or method, that is used. The most common methods are “GET”, “HEAD”, and “POST”, but a number of others are possible.

The nng_http_set_method function specifies the HTTP method to use for the transaction. The default is “GET”. HTTP methods are case sensitive, and generally upper-case, such as “GET”, “POST”, “HEAD”, and so forth. This function silently truncates any method to 32-characters. (There are no defined methods longer than this.)

The nng_http_get_method function is used, typically on a server, to retrieve the method the client set when issuing the transaction.

HTTP URI

nng_err nng_http_set_uri(nng_http *conn, const char *uri, const char *query);
const char *nng_http_get_uri(nng_http *conn);

The nng_http_set_uri function sets the URI, which normally appears like a path such as “/docs/index.html”, for the next transaction on conn. It sets the URI to uri, and, if query is not NULL, also appends the contents of query, separated by either the ‘?’ or ‘&’ character, depending on whether uri already contains a query string. It may return NNG_ENOMEM, or NNG_EMSGSIZE if the the result is too long, or NNG_EINVAL if there is some other problem with the URI.

note

The uri and query must be already percent-encoded if necessary.

The nni_http_get_uri function is used to obtain the URI that was previously set by nng_http_set_uri. If the URI is unset (such as for a freshly created connection), then it returns NULL. The returned value will have any query concentated, for example “/api/get_user.cgi?name=garrett”.

HTTP Version

nng_err nng_http_set_version(nng_http *conn, const char *version);
const char *nng_http_get_version(nng_http *conn);

The nng_http_set_version function is used to select the HTTP protocol version to use for the exchange. At present, only the values NNG_HTTP_VERSION_1_0 and NNG_HTTP_VERSION_1_1 (corresponding to “HTTP/1.0” and “HTTP/1.1”) are supported. NNG will default to using “HTTP/1.1” if this function is not called. If an unsupported version is supplied, NNG_ENOTSUP will be returned, otherwise zero.

The nng_http_get_version function is used to determine the version the client selected. Normally there is little need to use this, but there are some subtle semantic differences between HTTP/1.0 and HTTP/1.1.

tip

There are few, if any, remaining HTTP/1.0 implementations that are not also capable of HTTP/1.1. It might be easiest to just fail any request coming in that is not HTTP/1.1.

note

NNG does not support HTTP/2 or HTTP/3 at this time.

HTTP Status

typedef enum ... nng_http_status;
nng_http_status nng_http_get_status(nng_http *conn);
const char *nng_http_get_reason(nng_http_conn *conn);
void nng_http_set_status(nng_http *conn, nng_http_status status, const char *reason);

The nng_http_get_status function obtains the numeric code (typipcally numbered from 100 through 599) returned by the server in the last exchange on conn. (If no exchange has been performed yet, the result is undefined.) The value is returned as an nng_http_status.

A descriptive message matching the status code is returned by nng_http_get_reason.

The nng_http_set_status function is used on a server in a handler callback to set the status code that will be reported to the client to status, and the associated text (reason) to reason. If reason is NULL, then a built in reason based on the status will be used instead.

tip

Callbacks used on the server may wish to use nng_http_server_set_error or nng_http_server_set_redirect instead of nng_http_set_status, because those functions will also set the response body to a suitable HTML document for display to users.

Status codes are defined by the IETF. Here are defininitions that NNG provides for convenience:

NameCodeReason TextNotes
NNG_HTTP_STATUS_CONTINUE100ContinuePartial transfer, client may send body.
NNG_HTTP_STATUS_SWITCHING101Switching ProtocolsUsed when upgrading or hijacking a connection.
NNG_HTTP_STATUS_PROCESSING102Processing
NNG_HTTP_STATUS_OK200OKSuccessful result.
NNG_HTTP_STATUS_CREATED201CreatedResource created successfully.
NNG_HTTP_STATUS_ACCEPTED202CreatedRequest accepted for future processing.
NNG_HTTP_STATUS_NOT_AUTHORITATIVE203Not AuthoritativeRequest successful, but modified by proxy.
NNG_HTTP_STATUS_NO_CONTENT204No ContentRequest successful, no content returned.
NNG_HTTP_STATUS_RESET_CONTENT205Reset ContentRequest successful, client should reload content.
NNG_HTTP_STATUS_PARTIAL_CONTENT206Partial ContentResponse to a range request.
NNG_HTTP_STATUS_MULTI_STATUS207Multi-StatusUsed with WebDAV.
NNG_HTTP_STATUS_ALREADY_REPORTED208Already ReportedUsed with WebDAV.
NNG_HTTP_STATUS_IM_USED226IM UsedUsed with delta encodings, rarely supported.
NNG_HTTP_STATUS_MULTIPLE_CHOICES300Multiple ChoicesMultiple responses possible, client should choose.
NNG_HTTP_STATUS_MOVED_PERMANENTLY301Moved PermanentlyPermanent redirection, may be saved by client.
NNG_HTTP_STATUS_FOUND302FoundTemporary redirection, client may switch to GET.
NNG_HTTP_STATUS_SEE_OTHER303See OtherRedirect, perhaps after a success POST or PUT.
NNG_HTTP_STATUS_NOT_MODIFIED304Not ModifiedResource not modified, client may use cached version.
NNG_HTTP_STATUS_USE_PROXY305Use Proxy
NNG_HTTP_STATUS_TEMPORARY_REDIRECT307Temporary RedirectTemporary redirect, preserves method.
NNG_HTTP_STATUS_PERMANENT_REDIRECT308Permanent RedirectPermanent redirect.
NNG_HTTP_STATUS_BAD_REQUEST400Bad RequestGeneric problem with the request.
NNG_HTTP_STATUS_UNAUTHORIZED401UnauthorizedIndicates a problem with authentication.
NNG_HTTP_STATUS_PAYMENT_REQUIRED402Payment Required
NNG_HTTP_STATUS_FORBIDDEN403ForbiddenNo permission to access resource.
NNG_HTTP_STATUS_NOT_FOUND404Not FoundResource does not exist.
NNG_HTTP_STATUS_METHOD_NOT_ALLOWED405Method Not AllowedResource does not support the method.
NNG_HTTP_STATUS_METHOD_NOT_ACCEPTABLE406Not AcceptableCould not satisfy accept requirements.
NNG_HTTP_STATUS_PROXY_AUTH_REQUIRED407Proxy Authentication RequiredProxy requires authentication.
NNG_HTTP_STATUS_REQUEST_TIMEOUT408Request TimeoutTimed out waiting for request.
NNG_HTTP_STATUS_CONFLICT409ConflictConflicting request.
NNG_HTTP_STATUS_GONE410GoneResource no longer exists.
NNG_HTTP_STATUS_LENGTH_REQUIRED411Length RequiredMissing Content-Length.
NNG_HTTP_STATUS_PRECONDITION_FAILED412Precondition Failed
NNG_HTTP_STATUS_CONTENT_TOO_LARGE413Content Too Large
NNG_HTTP_STATUS_URI_TOO_LONG414URI Too Long
NNG_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE415Unsupported Media Type
NNG_HTTP_STATUS_RANGE_NOT_SATISFIABLE416Range Not Satisfiable
NNG_HTTP_STATUS_EXPECTATION_FAILED417Expectation Failed
NNG_HTTP_STATUS_TEAPOT418I Am A TeapotRFC 2324.
NNG_HTTP_STATUS_UNPROCESSABLE_ENTITY422Unprocessable Entity
NNG_HTTP_STATUS_LOCKED423Locked
NNG_HTTP_STATUS_FAILED_DEPENDENCY424Failed Dependency
NNG_HTTP_STATUS_TOO_EARLY425Too Early
NNG_HTTP_STATUS_UPGRADE_REQUIRED426Upgrade Required
NNG_HTTP_STATUS_PRECONDITION_REQUIRED428Precondition Required
NNG_HTTP_STATUS_TOO_MANY_REQUESTS429Too Many Requests
NNG_HTTP_STATUS_HEADERS_TOO_LARGE431Headers Too Large
NNG_HTTP_STATUS_UNAVAIL_LEGAL_REASONS451Unavailabe For Legal Reasons
NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR500Internal Server Error
NNG_HTTP_STATUS_NOT_IMPLEMENTED501Not ImplementedServer does not implement method.
NNG_HTTP_STATUS_BAD_GATEWAY502Bad Gateway
NNG_HTTP_STATUS_SERVICE_UNAVAILALE503Service Unavailable
NNG_HTTP_STATUS_GATEWAY_TIMEOUT504Gateway TImeout
NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP505HTTP Version Not Supported
NNG_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES506Variant Also Negotiates
NNG_HTTP_STATUS_INSUFFICIENT_STORAGE507Variant Also Negotiates
NNG_HTTP_STATUS_LOOP_DETECTED508Loop Detected
NNG_HTTP_STATUS_NOT_EXTENDED510Not Extended
NNG_HTTP_STATUS_NETWORK_AUTH_REQUIRED511Network Authentication Required

Retrieving Headers

const char *nng_http_get_header(nng_http *conn, const char *key);
bool nng_next_header(nng_http *conn, const char **keyp, const char **valuep, void **next);

The nng_http_get_header returns the header value matching key that was received over conn, or NULL if no such header exists.

Thus, if conn is a client connection, then this function returns the the header value sent by the server as part of a response, whereas if it is a server connection, it returns the header value sent by the client as part of the request.

If multiple headers are present with the same key, they may be returned as a combined value, with individual values separated by commas, but this behavior is not guaranteed.

The nng_http_next_header function iterates over all the headers, using the same list that nng_http_get_header uses. To start, it is called with next initialized to NULL. If a header was found, then it returns true, and sets keyp and valuep to values containing the header name and value. It also updates next, which should be used for the next iteration.

Once nng_http_next_header returns false, further calls with the same parameters will continue to do so. The scan can be rest by setting next to NULL.

Modifying Headers

nng_err nng_http_add_header(nng_http *conn, const char *key, const char *val);
nng_err nng_http_set_header(nng_http *conn, const char *key, const char *val);
void nng_http_del_header(nng_http *conn, const char *key);

The nng_http_add_header, nng_http_set_header, and nng_http_del_header functions are used to add a modify either the request or response headers for conn prior to sending to the connected peer on conn.

Thus, if the conn is a client connection created by nng_http_client_connect, then the request headers are modified. Conversely, if it is a connection created by an HTTP server and used in a callback function, then the response headers are modified.

The nng_http_add_header function adds a header with the name key, and the value val, to the list of headers. In so doing, it may bring collapse multiple headers with the same name into a comma separated list, following the syntax specified in RFC 9110. The function may return NNG_ENOMEM, NNG_EMSGSIZE, or NNG_EINVAL.

The nng_http_set_header function adds the header if it does not already exist, but replaces any and all previously existing headers with the same name key, if they exist. In all other respects it behaves similarly to nng_http_add_header.

The nng_http_del_header removes all headers with name key.

note

Some HTTP headers have special semantics, such as the “Host”, “Content-Length”, and “Content-Type” headers. This implementation may apply those semantics, in order to conform to the specifications for HTTP, such as by guaranting that only a single instance of one of these headers is present.

Retrieving Body Content

void nng_http_get_body(nng_http_conn *conn, void **datap, size_t *sizep);

The nng_http_get_data obtains the most recently received request or response body. This will be NULL if the content has not been retrieved properly yet, or if the peer did not any content. (Some requests are defined to never have body content, such as “HEAD”.)

Storing Body Content

void nng_http_set_body(nng_http_conn *conn, void *data, size_t size);
void nng_http_copy_body(nng_http_conn *conn, const void *data, size_t size);

The nng_http_set_data function sets the outgoing body content to data, which must be size bytes long. The caller must ensure that data remains valid for the duration of the transaction.

The nng_http_copy_data function makes a copy of data, which will be freed automatically when the transaction is finished, but otherwise behaves like nng_http_set_data.

On client conn objects, these functions update the request object, but on server conn objects, they update the response object.

These functions also update the relevant “Content-Length” header.

note

The current framework does not support sending data via chunked transfer-encoding.

tip

It is a good idea to also set the Content-Type header.

Closing the Connection

void nng_http_close(nng_http *conn);

The nng_http_close function closes the supplied HTTP connection conn, including any disposing of any underlying file descriptors or related resources.

Once this function, no further access to the conn structure may be made.

Reset Connection State

void nng_http_reset(nng_http *conn);

The nng_http_reset function resets the request and response state of the the connection conn, so that it is just as if it had been freshly created with nng_http_client_connect or passed into a handler function for a server callback.

The intended purpose of this function is to clear the object state before reusing the conn for subsequent transactions.

Direct Read and Write

void nng_http_read(nng_http *conn, nng_aio *aio);
void nng_http_write(nng_http *conn, nng_aio *aio);
void nng_http_read_all(nng_http *conn, nng_aio *aio);
void nng_http_write_all(nng_http *conn, nng_aio *aio);

The nng_http_read and nng_http_write functions read or write data asynchronously from or to the connection conn, using the nng_iov that is set in aio with nng_aio_set_iov. These functions will complete as soon as any data is transferred. Use nng_aio_count to determine how much data was actually transferred.

The nng_http_read_all and nng_http_write_all functions perform the same task, but will keep resubmitting operations until the the entire amount of data requested by the nng_iov is transferred.

note

These functions perform no special handling for chunked transfers.

These functions are most likely to be useful after hijacking the connection with nng_http_hijack. They can be used to transfer request or response body data as well.

Hijacking Connections

nng_err nng_http_hijack(nng_http *conn);

TODO: This API will change to convert the conn into a stream object.

The nng_http_hijack function hijacks the connection conn, causing it to be disassociated from the HTTP server where it was created.

The purpose of this function is the creation of HTTP upgraders (such as WebSocket), where the underlying HTTP connection will be taken over for some other purpose, and should not be used any further by the server.

This function is most useful when called from a handler function. (See [nng_http_handler_alloc].)

note

It is the responsibility of the caller to dispose of the underlying connection when it is no longer needed. Furthermore, the HTTP server will no longer send any responses to the hijacked connection, so the caller should do that as well if appropriate. (See [nng_http_write_response].)

tip

This function is intended to facilitate uses cases that involve changing the protocol from HTTP, such as WebSocket. Most applications will never need to use this function.

Client API

The NNG client API consists of an API for creating connections, and an API for performing transactions on those connections.

Client Object

typedef struct nng_http_client nng_http_client;

The nng_http_client object is the client side creator for nng_http objects. It is analogous to a dialer object used elsewhere in NNG, but it specifically is only for HTTP.

Create a Client

void nng_http_client_alloc(nng_http_client *clientp, const nng_url *url);

The nng_http_client_alloc allocates an HTTP client suitable for connecting to the server identified by url and stores a pointer to it in the location referenced by clientp.

Destroy a Client

void nng_http_client_free(nng_http_client *client);

The nng_http_client_free connection destroys the client object and any of its resources.

note

Any connections created by nng_http_client_connect are not affected by this function, and must be closed explicitly as needed.

Client TLS

nng_err nng_http_client_get_tls(nng_http_client *client, nng_tls_config **tlsp);
nng_err nng_http_client_set_tls(nng_http_client *client, nng_tls_config *tls);

The nng_http_client_get_tls and nng_http_client_set_tls functions are used to retrieve or change the TLS configuration used when making outbound connections, enabling TLS as a result.

If TLS has not been previously configured on client, then nng_http_client_get_tls will return NNG_EINVAL. Both functions will return NNG_ENOTSUP if either HTTP or TLS is not supported.

Calling nng_http_client_set_tls invalidates any client previously obtained with nng_http_client_get_tls, unless a separate hold on the object was obtained.

Once TLS is enabled for an nng_http_client, it is not possible to disable TLS.

note

The TLS configuration itself cannnot be changed once it has been used to create a connection, such as by calling nng_http_client_connect, but a new one can be installed in the client. Existing connections will use the TLS configuration that there were created with.

Creating Connections

#include <nng/http.h>

void nng_http_client_connect(nng_http_client *client, nng_aio *aio);

The nng_http_client_connect function makes an outgoing connection to the server configured for client, and creates an nng_http object for the connection.

This is done asynchronously, and when the operation succeseds the connection may be retried from the aio using nng_aio_get_output with index 0.

Example 1: Connecting to Google

nng_aio *aio;
nng_url *url;
nng_http_client *client;
nng_http *conn;
nng_err rv;

// Error checks elided for clarity.
nng_url_parse(&url, "http://www.google.com");
nng_aio_alloc(&aio, NULL, NULL);
nng_http_client_alloc(&client, url);

nng_http_client_connect(client, aio);

// Wait for connection to establish (or attempt to fail).
nng_aio_wait(aio);

if ((rv = nng_aio_result(aio)) != 0) {
    printf("Connection failed: %s\n", nng_strerror(rv));
} else {
    // Connection established, get it.
    conn = nng_aio_get_output(aio, 0);

    // ... do something with it here

    // Close the connection when done to avoid leaking it.
    nng_http_close(conn);
}

Preparing a Transaction

Sending the Request

void nng_http_write_request(nng_http *conn, nng_aio *aio);

The nng_http_write_request function starts an asynchronous write of the HTTP request associated with conn. The entire request is sent, including headers, and if present, the request body data. (The request body can be set with [nng_http_set_data] or [nng_http_copy_data].)

This function returns immediately, with no return value. Completion of the operation is signaled via the aio, and the final result may be obtained via nng_aio_result.

tip

Consider using the [nng_http_transact] function, which provides a simpler interface for performing a complete HTTP client transaction.

Obtaining the Response

void nng_http_read_response(nng_http *conn, nng_aio *aio);

The nng_http_read_response function starts an asynchronous read from the HTTP connection conn, reading an HTTP response into the response associated with conn, including all of the related headers.

It does not transfer any response body. To do that, use nng_http_read_all or nng_http_read.

note

At this time we have no API support for reading chunked transfers directly. Applications that need to do so may use the direct read functions.

tip

An easier one-shot method for many use cases might be [nng_http_transact].

Submitting the Transaction

void nng_http_transact(nng_http *conn, nng_aio *aio);

The HTTP request is issued, and the response processed, asynchronously by the nng_http_transact function. When the function is complete, the aio will be notified.

The nng_http_transact function is used to perform a complete HTTP exchange over the connection conn, sending the request and attached body data to the remote server, and reading the response.

The entire response is read, including any associated body, which can subsequently be obtained using [nng_http_get_data].

This function is intended to make creation of client applications easier, by performing multiple asynchronous operations required to complete an entire HTTP transaction.

If an error occurs, the caller should close conn with nng_http_close, as it may not necessarily be usable with other transactions.

warning

If the remote server tries to send an extremely large buffer, then a corresponding allocation will be made, which can lead to denial of service attacks. Client applications should take care to use this only with reasonably trust-worthy servers.

note

A given connection conn should be used with only one operation or transaction at a time as HTTP/1.1 has no support for request interleaving.

This function returns immediately, with no return value. Completion of the operation is signaled via the aio, and the final result may be obtained via [nng_aio_result()].

Response Body

Server API

Handlers

typedef struct nng_http_handler nng_http_handler;

An nng_http_handler encapsulates a function used used to handle incoming requests on an HTTP server, routed based on method and URI, and the parameters used with that function.

Every handler has a Request-URI to which it refers, which is determined by the path argument. Only the path component of the Request URI is considered when determining whether the handler should be called.

This implementation limits the path length to 1024 bytes, including the zero termination byte. This does not prevent requests with much longer URIs from being supported, but doing so will require setting the handler to match a parent path in the tree using [nng_http_handler_set_tree].

tip

The NNG HTTP framework is optimized for URLs shorter than 200 characters.

Additionally each handler has a method it is registered to handle (the default is “GET” andc can be changed with [nng_http_handler_set_method]), and optionally a “Host” header it can be matched against (see [nng_http_handler_set_host]).

In some cases, a handler may reference a logical tree rather (directory) rather than just a single element. (See [nng_http_handler_set_tree]).

Implementing a Handler

typedef void (*nng_http_hander_func)(nng_http_conn *conn, void *arg, nng_aio *aio);

nng_err nng_http_handler_alloc(nng_http_handler **hp, const char *path, nng_http_handler_func cb);

The nng_http_handler_alloc function allocates a generic handler which will be used to process requests coming into an HTTP server. On success, a pointer to the handler is stored at the located pointed to by hp.

The handler function is specified by cb. This function uses the asynchronous I/O framework.

The function receives the connection on conn, and an optional data pointer that was set previously with [nng_http_handler_set_data] as the second argument. The final argument is the nng_aio aio, which must be “finished” to complete the operation.

The handler may call [nng_http_write_response] to send the response, or it may simply let the framework do so on its behalf. The server will perform this step if the callback has not already done so.

Response headers may be set using nng_http_set_header, and request headers may be accessed by using nng_http_get_header.

Likewise the request body may be accessed, using nng_http_get_body, and the response body may be set using either nng_http_set_body or nng_http_copy_body.

note

The request body is only collected for the handler if the [nng_http_handler_collect_body] function has been called for the handler.

The HTTP status should be set for the transaction using nng_http_set_status.

Finally, the handler should finish the operation by calling the nng_aio_finish function after having set the status to [NNG_OK]. If any other status is set on the aio, then a generic 500 response will be created and sent, if possible, and the connection will be closed.

The aio may be scheduled for deferred completion using the nng_aio_start.

Serving Directories and Files

nng_err nng_http_handler_alloc_directory(nng_http_handler **hp, const char *path, const char *dirname);
nng_err nng_http_handler_alloc_file(nng_http_handler **hp, const char *path, const char *filename);

The nng_http_handler_alloc_directory and nng_http_handler_alloc_file create handlers pre-configured to act as static content servers for either a full directory at dirname, or the single file at filename. These support the “GET” and “HEAD” methods, and the directory variant will dynamically generate index.html content based on the directory contents. These will also set the “Content-Type” if the file extension matches one of the built-in values already known. If the no suitable MIME type can be determined, the content type is set to “application/octet-stream”.

Static Handler

nng_err nng_http_handler_alloc_static(nng_http_handler **hp, const char *path,
        const void *data, size_t size, const char *content_type);

The nng_http_handler_alloc_static function creates a handler that serves the content located in data (consisting of size bytes) at the URI path. The content_type determines the “Content-Type” header. If NULL is specified then a value of application/octet-stream is assumed.

Redirect Handler

nng_err nng_http_handler_alloc_redirect(nng_http_handler **hp, const char *path,
        nng_http_status status, const char *location);

The nng_http_handler_alloc_redirect function creates a handler with a function that simply directions from the URI at path to the given location.

The HTTP reply it creates will be with [status code][nng_http_status] status, which should be a 3XX code such as 301, and a Location: header will contain the URL referenced by location, with any residual suffix from the request URI appended.

tip

Use [nng_http_handler_set_tree] to redirect an entire tree. For example, it is possible to redirect an entire HTTP site to another HTTPS site by specifying / as the path and then using the base of the new site, such as https://newsite.example.com as the new location.

tip

Be sure to use the appropriate value for status. Permanent redirection should use [NNG_HTTP_STATUS_STATUS_MOVED_PERMANENTLY] (301) and temporary redirections should use [NNG_HTTP_STATUS_TEMPORARY_REDIRECT] (307). In REST APIs, using a redirection to supply the new location of an object created with POST should use [NNG_HTTP_STATUS_SEE_OTHER] (303).

Collecting Request Body

void nng_http_handler_collect_body(nng_http_handler *handler, bool want, size_t maxsz);

The nng_http_handler_collect_body function requests that HTTP server framework collect any reuqest body for the request and attach it to the connection before calling the callback for the handler.

Subsequently the data can be retrieved by the handler from the request with the nng_http_get_body function.

The collection is enabled if want is true. Furthermore, the data that the client may sent is limited by the value of maxsz. If the client attempts to send more data than maxsz, then the request will be terminated with [NNG_HTTP_STATUS_CONTENT_TOO_LARGE] (413).

tip

Limiting the size of incoming request data can provide protection against denial of service attacks, as a buffer of the client-supplied size must be allocated to receive the data.

In order to provide an unlimited size, use (size_t)-1 for maxsz. The value 0 for maxsz can be used to prevent any data from being passed by the client.

The built-in handlers for files, directories, and static data limit the maxsz to zero by default. Otherwise the default setting is to enable this capability with a default value of maxsz of 1 megabyte.

note

NNG specifically does not support the Chunked transfer-encoding. This is considered a bug, and is a deficiency for full HTTP/1.1 compliance. However, few clients send data in this format, so in practice this should create few limitations.

Setting Callback Argument

void nng_http_handler_set_data(nng_http_handler *handler, void *data,
    void (*dtor)(void *));

The nng_http_handler_set_data function is used to set the data argument that will be passed to the callback.

Additionally, when the handler is deallocated, if dtor is not NULL, then it will be called with data as its argument. The intended use of this function is deallocate any resources associated with data.

Setting the Method

void nng_http_handler_set_method(nng_http_handler *handler, const char *method);

The nng_http_handler_set_method function sets the method that the handler will be called for, such as “GET” or “POST”. (By default the “GET” method is handled.)

If method is NULL the handler will be executed for all methods. The handler may determine the actual method used with the nng_http_get_method function.

The server will automatically call “GET” handlers if the client sends a “HEAD” request, and will suppress HTTP body data in the responses sent for such requests.

note

If method is longer than 32-bytes, it may be truncated silently.

Filtering by Host

void nng_http_handler_set_host(nng_http_handler *handler, const char *host);

The nng_http_handler_set_host function is used to limit the scope of the handler so that it will only be called when the specified host matches the value of the Host: HTTP header.

This can be used to create servers with different content for different virtual hosts.

The value of the host can include a colon and port, and should match exactly the value of the Host header sent by the client. (Canonicalization of the host name is performed.)

note

The port number may be ignored; at present the HTTP server framework does not support a single server listening on different ports concurrently.

Handling an Entire Tree

void nng_http_handler_set_tree(nng_http_handler *handler);

The nng_http_handler_set_tree function causes the handler to be matched if the request URI sent by the client is a logical child of the path for handler, and no more specific handler has been registered.

This is useful in cases when the handler would like to examine the entire path and possibly behave differently; for example a REST API that uses the rest of the path to pass additional parameters.

tip

This function is useful when constructing API handlers where a single service address (path) supports dynamically generated children. It can also provide a logical fallback instead of relying on a 404 error code.

Sending the Response Explicitly

void nng_http_write_response(nng_http *conn, nng_aio *aio);

Normally the server will send any attached response, but there are circumstances where a response must be sent manually, such as when hijacking a connection.

In such a case, nng_http_write_response can be called, which will send the response and any attached data, asynchronously using the nng_aio aio.

By default, for HTTP/1.1 connections, the connection is kept open, and will be reused to receive new requests. For HTTP/1.0, or if the client has requested explicitly by setting the “Connection: close” header, the connection will be closed after the response is fully sent.