picow-http 0.12.1-4-g9d4fd13
HTTP server for the Raspberry Pi PicoW
|
Data Structures | |
struct | resp |
HTTP response. More... | |
Macros | |
#define | RESP_HDR_SMALL_BUF_SZ (512) |
Size of "small" buffers for response headers. More... | |
#define | RESP_HDR_LARGE_BUF_SZ (TCP_MSS) |
Size of "large" buffers for response headers. More... | |
#define | RESP_HDR_SMALL_POOL_SZ (MAX_CONCURRENT_CX_HINT) |
Number of buffers in the "small" memory pool for response headers. More... | |
#define | RESP_HDR_LARGE_POOL_SZ (RESP_HDR_SMALL_POOL_SZ / 2) |
Number of buffers in the "large" memory pool for response headers. More... | |
#define | http_resp_set_hdr_ltrl(resp, name, val) |
Set a response header to a literal string. More... | |
#define | http_resp_set_type_ltrl(resp, type) http_resp_set_type((resp), (type), STRLEN_LTRL(type)) |
Set the Content-Type response header to a literal string. More... | |
Typedefs | |
typedef err_t(* | hndlr_f) (struct http *http, void *priv) |
Function type for custom response handlers. More... | |
Functions | |
static struct resp * | http_resp (struct http *http) |
Get the current response object. More... | |
static err_t | http_resp_set_status (struct resp *resp, uint16_t status) |
Set the response status code. More... | |
static uint16_t | http_resp_status (struct resp *resp) |
Get the response status code. More... | |
err_t | http_resp_set_hdr (struct resp *resp, const char *name, size_t name_len, const char *val, size_t val_len) |
Set a response header. More... | |
static err_t | http_resp_set_hdr_str (struct resp *resp, const char *name, const char *val) |
Set a response header to a nul-terminated string. More... | |
static err_t | http_resp_set_type (struct resp *resp, const char *type, size_t type_len) |
Set the Content-Type response header. More... | |
static err_t | http_resp_set_type_str (struct resp *resp, const char *type) |
Set the Content-Type response header to a nul-terminated string. More... | |
err_t | http_resp_set_len (struct resp *resp, size_t len) |
Set the Content-Length response header. More... | |
static err_t | http_resp_set_xfer_chunked (struct resp *resp) |
Set the Transfer-Encdoing response header to "chunked". More... | |
err_t | http_resp_send_hdr (struct http *http) |
Send the response header. More... | |
err_t | http_resp_send_buf (struct http *http, const uint8_t *buf, size_t len, bool durable) |
Send the contents of a buffer as the response body. More... | |
err_t | http_resp_send_chunk (struct http *http, const uint8_t *buf, size_t len, bool durable) |
Send a chunk in a chunked-encoded response body. More... | |
static err_t | http_resp_err (struct http *http, uint16_t status) |
Send an error response. More... | |
err_t | register_hndlr_methods (struct server_cfg *cfg, const char *path, hndlr_f hndlr, uint8_t methods, void *priv) |
Register a response handler for request methods and a path. More... | |
static err_t | register_hndlr (struct server_cfg *cfg, const char *path, hndlr_f hndlr, enum http_method_t method, void *priv) |
Register a response handler for a request method and path. More... | |
err_t | register_default_hndlr (struct server_cfg *cfg, hndlr_f hndlr, void *priv, priv_fini_f fini) |
Register a default response handler. More... | |
err_t | register_error_hndlr (struct server_cfg *cfg, hndlr_f hndlr, void *priv, priv_fini_f fini) |
Register a custom error response handler. More... | |
Set HTTP response headers and body, and send responses to the client
The API includes two functions for sending response bodies:
Content-Length
response header.Transfer-Encoding: chunked
.Use only one or the other of these two mechanisms to send a response body. Exactly one of Content-Length
or Transfer-Encoding: chunked
must be included in the response header.
Both of these functions have a boolean parameter durable
to indicate whether the response contents can be queued for send without copying the buffer.
Packets containing the response contents are sent asynchronously, and are retained by the TCP stack (potentially for re-send if not acknowledged by the network peer). This process may continue after the handler calling the send function has completed. Set durable
to true if the buffer passed to the function is allocated for a lifetime that persists at least until the TCP send operation is fully complete – in this case the buffer will not be copied. Set durable
to false otherwise, so that the buffer is copied for the TCP stack.
For example, if the pointer to response contents points to static storage, or has been returned from malloc()
, then durable
may be set to true. If it points to memory on the stack, such as an array declared as a local variable within a handler, then durable
MUST be false, since the TCP stack must retain a copy that persists after completion of the handler invocation.
Zero-copy send is more efficient, in terms of both RAM usage and processing time. If your application allows it, prefer sending response bodies with the durable
parameter set to true.
http_resp_err() is an alternative to http_resp_send_buf() and http_resp_send_chunk() that may be used when the response status is >= 400. By default, it sends a simple, standard error response body built in to the library. Optionally, register_error_hndlr() may be used to register a custom error handler for response codes specified in the build configuration.
The response header may be sent separately from the body with http_resp_send_hdr(). If the response status has not been set (with http_resp_set_status()) before sending the header, it set to 200.
Functions that send the response body also send the header, if it has not already been sent. http_resp_send_chunk() sends the header, if needed, before sending the first chunk. Calling http_resp_send_hdr() before sending the body is not necessary (but harmless).
To use the API properly, be aware of the kinds of responses that, according to HTTP standards, may only contain a header, but no body. These are:
HEAD
method.In these cases, just http_resp_send_hdr() is sufficient. If either of http_resp_send_buf() or http_resp_send_chunk() are called for such a response, a debug level message is printed to the log, the body contents are ignored, but the functions return ERR_OK
. Only using a function that sends a body is a convenient way for a handler to respond to both GET
and HEAD
requests – the function does the right thing for HEAD
requests transparently.
picow-http uses lwIP's memory pools to allocate space for response headers; no dynamic allocation for response headers takes place at runtime. This is done transparently by the library, with no requirements for the application developer. But you can configure the pools and buffer sizes, for example to lower the memory footprint, or if the application requires large headers.
Two pools are used, for "small" and "large" response headers. The assumption is that most response headers will require no more than the small size, and the large size will only be used in rare exceptions. A buffer from the small pool is always used initially; a buffer from the large pool is used if the header exceeds the small buffer size. No response header may exceed the large size. Buffers are returned to their pools after a response has been sent.
http_resp_set_hdr() and its variants fail with the ERR_MEM
error code if it needs a buffer from a memory pool that is exhausted, of if the header's size exceeds the large buffer size.
The memory pools are configured by these macros, whose default values can be overridden with compile-time definitions:
#define http_resp_set_hdr_ltrl | ( | resp, | |
name, | |||
val | |||
) |
Add a response header field named name
with the value val
. name
and val
MUST be literal strings (compile-time constant strings).
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from http_resp() |
[in] | name | response header name MUST be a literal string |
[in] | val | header value MUST be a literal string |
ERR_OK
on successERR_MEM
if there is insufficient memory for the header #define http_resp_set_type_ltrl | ( | resp, | |
type | |||
) | http_resp_set_type((resp), (type), STRLEN_LTRL(type)) |
Add the Content-Type response header with the value type
. type
MUST be a literal string (compile-time constant string).
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from http_resp() |
[in] | type | value to set for the Content-Type header MUST be a literal string |
ERR_OK
on successERR_MEM
if there is insufficient memory for the header #define RESP_HDR_LARGE_BUF_SZ (TCP_MSS) |
The maximum size in bytes for a response header. Buffers of this size are obtained from a memory pool if the header exceeds the "small" size (RESP_HDR_SMALL_BUF_SZ). By default, there are fewer buffers in the "large" pool, on the assumption that they will only rarely be necessary.
The default is the TCP maximum segment size (MSS) configured for lwIP, which in most cases is 1460 bytes. The default value can be overridden by #define
-ing RESP_HDR_LARGE_BUF_SZ
prior to including picow_http/http.h
, or by passing in a definition as a compile option.
#define RESP_HDR_LARGE_POOL_SZ (RESP_HDR_SMALL_POOL_SZ / 2) |
The number of buffers of size RESP_HDR_LARGE_BUF_SZ that are allocated in the "large" memory pool for response headers. The default value is half the size of the "small" pool for response headers.
The default value can be overridden by #define
-ing RESP_HDR_LARGE_POOL_SZ
prior to including picow_http/http.h
, or by passing in a definition as a compile option.
#define RESP_HDR_SMALL_BUF_SZ (512) |
The size in bytes of memory pool buffers that are initally used for response headers. To save memory footprint, this value is set to a small size that is sufficient for most or all response headers.
The default value can be overridden by #define
-ing RESP_HDR_SMALL_BUF_SZ
prior to including picow_http/http.h
, or by passing in a definition as a compile option.
#define RESP_HDR_SMALL_POOL_SZ (MAX_CONCURRENT_CX_HINT) |
The number of buffers of size RESP_HDR_SMALL_BUF_SZ that are allocated in the "small" memory pool for response headers.
The default value is set to accomodate the maximum number of concurrent connections for all of the servers (listeners) configured for the application. If the macro MAX_CONCURRENT_CX_HINT
has been defined (for "max concurrent connection hint", see the documentation for the sample lwipopts.h
), then the value is MAX_CONCURRENT_CX_HINT
times the number of listeners. Otherwise, the likely maximum for concurrent connections is inferred from lwIP settings.
The default value can be overridden by #define
-ing RESP_HDR_SMALL_POOL_SZ
prior to including picow_http/http.h
, or by passing in a definition as a compile option.
Function typedef for custom response handlers. Custom handlers implement a function with this signature, which is responsible for generating HTTP responses to requests received at the endpoint for which it is registered.
[in] | http | HTTP object for the current connection. Objects representing the current request and response are accessed via http_req() and http_resp(). |
[in] | priv | Optional pointer passed to the register functionNULL if no such object was configured |
ERR_OK
on success, or an error status on failure enum http_status_t |
Enum representing HTTP response status codes
Get the object representing the current response on an HTTP connection.
Example:
[in] | http | MUST be a valid HTTP object passed into a handler function |
|
inlinestatic |
Initiate sending a standard error response with response code status
. By default, the server sends a simple and small (but not very aesthetic) built-in response. If a custom error handler has been regsitered that is configured for status
, the custom handler is called.
The header includes the field "Connection: close", and the connection to the client is closed after the response is sent.
Example:
[in] | http | MUST be a valid HTTP object passed into a handler function |
[in] | status | response status code MUST be >= 400 |
ERR_OK
on successerr_t http_resp_send_buf | ( | struct http * | http, |
const uint8_t * | buf, | ||
size_t | len, | ||
bool | durable | ||
) |
Initiate sending len
bytes in the fixed-length buffer buf
as the response body to the client. If the response header has not already been sent, it is sent as well. The contents of the response (header and) body are queued by the TCP stack, which then begins the process of sending packets over the network.
The response header Content-Length
should have been set to the value of len
; http_resp_set_len() does this as a convenience. The header must not include the field Transfer-Encoding: chunked
.
buf
may not be NULL
. Set durable
to true if the contents of buf
can be queued for send without copying, as described above.
If the response status has not already been set, it is set to 200. After calling this function, it is no longer possible to modify any part of the response header or body.
If the properties of the response are such that it is header-only, a debug level message is issued to the log, the body is not sent, and the function returns ERR_OK
.
Example:
[in] | http | MUST be a valid HTTP object passed into a handler function |
[in] | buf | pointer to the buffer containing the response body |
[in] | len | number of bytes in buf to send |
[in] | durable | set to true iff buf points to durable storage, as described above |
ERR_OK
on success (the response header and/or body is queued for send)ERR_VAL
if buf
is NULL
ERR_ALREADY
if sending the body has already begunerr_t http_resp_send_chunk | ( | struct http * | http, |
const uint8_t * | buf, | ||
size_t | len, | ||
bool | durable | ||
) |
Add len
bytes at buf
as a chunk in a response body sent with chunked transfer encoding. Each chunk is queued for immediate send by the TCP stack. Call with len
== 0 to finalize sending the response.
buf
may not be NULL
unless len
is 0. Set durable
to true if the contents of buf
can be queued for send without copying, as described above.
If the response header has not already been sent, it is sent before the first chunk. If the response status has not already been set, it is set to 200. The header cannot be modified after the first chunk is sent.
Arbitrarily many chunks with len
> 0 may be sent, but after an invocation with len
= 0, it is no longer possible to modify the response body.
It is the programmer's responsibility to use this function in such a way that the response is successfully transmitted. Make sure that these requirements are met:
Transfer-Encoding: chunked
. http_resp_set_xfer_chunked() does this as a convenience.Content-Length
header must not be set.len
= 0 (and no further chunks may follow).If the properties of the response are such that it is header-only, a debug level message is issued to the log, the chunk is ignored, and the function returns ERR_OK
.
Example:
[in] | http | MUST be a valid HTTP object passed into a handler function |
[in] | buf | pointer to the buffer containing the chunk contents |
[in] | len | number of bytes in buf to send, or 0 to finalize the response |
[in] | durable | set to true iff buf points to durable storage, as described above |
ERR_OK
on success (the chunk and if necessary the response header are queued for send)ERR_VAL
if buf
is NULL
but len
> 0err_t http_resp_send_hdr | ( | struct http * | http | ) |
Initiate sending the response header to the client. The contents of the header are queued by the TCP stack, which then begins the process of sending packets over the network. If the response status has not already been set, it is set to 200. After calling this function, it is no longer possible to change the status or add a response header.
See Sending response headers above for notes about the use of this function.
Example:
[in] | http | MUST be a valid HTTP object passed into a handler function |
ERR_OK
on successERR_ALREADY
if the header has already been sentERR_VAL
if the response status is out of range (< 100 or >= 1000)ERR_MEM
if there is insufficient memory to send the header err_t http_resp_set_hdr | ( | struct resp * | resp, |
const char * | name, | ||
size_t | name_len, | ||
const char * | val, | ||
size_t | val_len | ||
) |
Add a response header field named name
with the value val
. name
and val
do not necessarily have to be nul-terminated.
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from the handler |
[in] | name | response header name |
[in] | name_len | length of name |
[in] | val | header value |
[in] | val_len | length of val |
ERR_OK
on successERR_VAL
if either of name
or val
is NULL
ERR_MEM
if there is insufficient memory for the header
|
inlinestatic |
Add a response header field named name
with the value val
. name
and val
MUST be nul-terminated.
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from http_resp() |
[in] | name | response header name MAY NOT be NULL , and MUST be nul-terminated |
[in] | val | header value MAY NOT be NULL , and MUST be nul-terminated |
ERR_OK
on successERR_MEM
if there is insufficient memory for the header err_t http_resp_set_len | ( | struct resp * | resp, |
size_t | len | ||
) |
Add the Content-Length response header with the value len
.
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from http_resp() |
[in] | len | value to set for the Content-Length header may not be greater than INT32_MAX |
ERR_OK
on successERR_VAL
if len
is out of range (> INT32_MAX
)ERR_MEM
if there is insufficient memory for the header
|
inlinestatic |
Set the response status code. If the status is not set by the time the response header is sent , the status is set to 200 ("OK").
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from http_resp() |
[in] | status | response status |
status
is out of range (< 100 or >= 1000)
|
inlinestatic |
Add the Content-Type response header with the value type
. type
does not necessarily have to be nul-terminated.
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from http_resp() |
[in] | type | value to set for the Content-Type header |
[in] | type_len | length of type |
ERR_OK
on successERR_VAL
if type
is NULL
ERR_MEM
if there is insufficient memory for the header
|
inlinestatic |
Add the Content-Type response header with the value type
. type
MUST be nul-terminated.
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from http_resp() |
[in] | type | value to set for the Content-Type header MAY NOT be NULL , and MUST be nul-terminated |
ERR_OK
on successERR_MEM
if there is insufficient memory for the header
|
inlinestatic |
Add the Transfer-Encoding response header with the value "chunked"
. This is required for chunked transfer encoding.
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from http_resp() |
ERR_OK
on successERR_MEM
if there is insufficient memory for the header
|
inlinestatic |
Get the response status code currently set for resp
. This may be a status previously set with http_resp_set_status(), or the default 200 ("OK").
Example:
[in] | resp | resp object for the current response MUST be a valid resp pointer obtained from http_resp() |
err_t register_default_hndlr | ( | struct server_cfg * | cfg, |
hndlr_f | hndlr, | ||
void * | priv, | ||
priv_fini_f | fini | ||
) |
Register hndlr
as the default response handler for the server configured by cfg
. If a default handler has been registered, it is invoked for any request whose path does not match any path specified in the static
or custom
elements of the build configuration. hndlr
MUST have the function signature defined for hndlr_f.
A default response handler is optional. If no default handler is registered, the server returns an error response with status 404 ("Not found") for requests whose path does not match the build configuration. If a default handler is registered, it may choose to generate responses for any other path and method, and takes on the role of returning 404 responses when appropriate.
priv
is an optional pointer to private data for the default handler that is passed in the priv
parameter of hndlr
. fini
is an optional finalizer for priv
. Set one or both or priv
and fini
to NULL
if not needed; see Application private data.
Example:
[in] | cfg | server configuration MUST be a valid configuration returned from http_cfg() or http_default_cfg() |
[in] | hndlr | default handler function to be registered MUST satisfy typedef hndlr_f |
[in] | priv | pointer to private data passed into the handler set to NULL if private data is not needed for the default handler |
[in] | fini | pointer to a finalizer function for priv set to NULL if not needed |
ERR_OK
on successERR_VAL
if either of cfg
or hndlr
is NULL
err_t register_error_hndlr | ( | struct server_cfg * | cfg, |
hndlr_f | hndlr, | ||
void * | priv, | ||
priv_fini_f | fini | ||
) |
Register hndlr
as the custom error response handler for the server configured by cfg
, to generate responses with status codes in the 400 and 500 range. A custom error handler can only be registered if response codes were defined for it in the optional custom_error
section of the build configuration (www.yaml
).
The custom_error
configuration specifies selected error response status codes in the range 400 to 599. If an error handler is registered, it is invoked for responses with those status codes that are to be generated by the server under various conditions, including:
custom_error
, the error responses for requests whose path and method do not match any combination configured for static
or custom
in the build configuration (unless a default handler is registered)Accept-Encoding
header does not match any encoding configured for the resourcecustom
, but no handler has been registered for itA custom error handler is optional. If for any such cases the response code was not configured for a custom error handler, or if no error handler has been registered, the server generates a built-in (small but plain) error response.
Before the error handler is called, the response header Connection
is added with the value close
. Accordingly, the connection with the client is closed after the response is sent. The handler code does not need to add the Connection
header.
priv
is an optional pointer to private data for the error handler that is passed in the priv
parameter of hndlr
. fini
is an optional finalizer for priv
. Set one or both or priv
and fini
to NULL
if not needed; see Application private data.
Example:
[in] | cfg | server configuration MUST be a valid configuration returned from http_cfg() or http_default_cfg() |
[in] | hndlr | error handler function to be registered MUST satisfy typedef hndlr_f |
[in] | priv | pointer to private data passed into the handler set to NULL if private data is not needed for the error handler |
[in] | fini | pointer to a finalizer function for priv set to NULL if not needed |
ERR_OK
on successERR_VAL
if either of cfg
or hndlr
is NULL
ERR_ARG
if custom_error
did not appear in the build configuration
|
inlinestatic |
Register hndlr
as the response handler for requests with method
and path
, for the server configued by cfg
. A custom handler MUST have been configured for method
and path
in the build configuration. hndlr
MUST have the function signature defined for hndlr_f.
A query string is not considered part of the path. So requests for method
and path
with any query string (or none) are directed to the handler.
register_hndlr() may be called prior to server start, so that the custom handler is immediately active for requests for which it is configured. If the server is started and requests are received for which register_hndlr() has not yet been invoked, the server sends an error response with status 501 ("Not Implemented").
priv
is an optional pointer that is passed in the priv
parameter of the handler, so that application code can access handler-specific data. If a priv
pointer is used, ensure that it points to storage that is allocated for the lifetime of the server. See the discussion in Application private data.
Unlike other API functions that provide for private data, register_hndlr() and register_hndlr_methods() do not have a parameter for a finalizer function. If you need to de-allocate resources associated with priv
, do so after calling http_srv_fini(). See the discussion in Application private data.
If the same handler should be invoked for more than one method for the same path, for example to use the same handler for GET
and HEAD
requests, use register_hndlr_methods(), or call register_hndlr() with each method for that path.
Example:
[in] | cfg | server configuration MUST be a valid configuration returned from http_cfg() or http_default_cfg() |
[in] | path | URL path for which the handler is registered query strings do not form a part of the path |
[in] | hndlr | handler function to be registered MUST satisfy the typedef for hndlr_f |
[in] | method | enum value representing the request method for which the handler is registered |
[in] | priv | pointer to private data passed into the handler set to NULL if handler-specific private data is not needed |
ERR_OK
on successERR_VAL
if either of path
or hndlr
is NULL
, or if method
is invalid (not a valid value of enum http_method_t)ERR_ARG
if no custom handler was configured for method
and path
at build time err_t register_hndlr_methods | ( | struct server_cfg * | cfg, |
const char * | path, | ||
hndlr_f | hndlr, | ||
uint8_t | methods, | ||
void * | priv | ||
) |
Register hndlr
as the response handler for requests with the methods designated in methods
and the URL path
, for the server configured by cfg
. A custom handler MUST have been configured for path
and each of the methods
in the build configuration.
methods
is a bit map, where the bit positions are values of enum http_method_t. For example, set bit (1U << HTTP_METHOD_GET)
in methods
to register hndlr
for the GET
method.
Otherwise, the same conditions apply as for register_hndlr().
Example:
[in] | cfg | server configuration MUST be a valid configuration returned from http_cfg() or http_default_cfg() |
[in] | path | URL path for which the handler is registered query strings do not form a part of the path |
[in] | hndlr | handler function to be registered MUST satisfy the typedef for hndlr_f |
[in] | methods | bitmap representing the request methods for which the handler is registered the bit positions are values of enum http_method_t |
[in] | priv | pointer to private data passed into the handler set to NULL if handler-specific private data is not needed |
ERR_OK
on successERR_VAL
if either of path
or hndlr
is NULL
ERR_ARG
if no custom handler was configured for method
and path
at build time