picow-http 0.12.1-4-g9d4fd13
HTTP server for the Raspberry Pi PicoW
Responses

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...
 

Enumerations

enum  http_status_t {
  HTTP_STATUS_CONTINUE = 100 , HTTP_STATUS_SWITCHING_PROTOCOLS = 101 , HTTP_STATUS_OK = 200 , HTTP_STATUS_CREATED = 201 ,
  HTTP_STATUS_ACCEPTED = 202 , HTTP_STATUS_NON_AUTHORITATIVE_INFO = 203 , HTTP_STATUS_NO_CONTENT = 204 , HTTP_STATUS_RESET_CONTENT = 205 ,
  HTTP_STATUS_PARTIAL_CONTENT = 206 , HTTP_STATUS_MULTIPLE_CHOICES = 300 , HTTP_STATUS_MOVED_PERMANENTLY = 301 , HTTP_STATUS_FOUND = 302 ,
  HTTP_STATUS_SEE_OTHER = 303 , HTTP_STATUS_NOT_MODIFIED = 304 , HTTP_STATUS_USE_PROXY = 305 , HTTP_STATUS_TEMPORARY_REDIRECT = 307 ,
  HTTP_STATUS_PERMANENT_REDIRECT = 308 , HTTP_STATUS_BAD_REQUEST = 400 , HTTP_STATUS_UNAUTHORIZED = 401 , HTTP_STATUS_PAYMENT_REQUIRED = 402 ,
  HTTP_STATUS_FORBIDDEN = 403 , HTTP_STATUS_NOT_FOUND = 404 , HTTP_STATUS_METHOD_NOT_ALLOWED = 405 , HTTP_STATUS_NOT_ACCEPTABLE = 406 ,
  HTTP_STATUS_PROXY_AUTH_REQUIRED = 407 , HTTP_STATUS_REQUEST_TIMEOUT = 408 , HTTP_STATUS_CONFLICT = 409 , HTTP_STATUS_GONE = 410 ,
  HTTP_STATUS_LENGTH_REQUIRED = 411 , HTTP_STATUS_PRECONDITION_FAILED = 412 , HTTP_STATUS_CONTENT_TOO_LARGE = 413 , HTTP_STATUS_URI_TOO_LONG = 414 ,
  HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415 , HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416 , HTTP_STATUS_EXPECTATION_FAILED = 417 , HTTP_STATUS_IM_A_TEAPOT = 418 ,
  HTTP_STATUS_MISDIRECTED_REQUEST = 421 , HTTP_STATUS_UNPROCESSABLE_CONTENT = 422 , HTTP_STATUS_UPGRADE_REQUIRED = 426 , HTTP_STATUS_REQ_HDR_FIELDS_TOO_LARGE = 431 ,
  HTTP_STATUS_INTERNAL_SERVER_ERROR = 500 , HTTP_STATUS_NOT_IMPLEMENTED = 501 , HTTP_STATUS_BAD_GATEWAY = 502 , HTTP_STATUS_SERVICE_UNAVAILABLE = 503 ,
  HTTP_STATUS_GATEWAY_TIMEOUT = 504 , HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505
}
 enum for HTTP response status codes More...
 

Functions

static struct resphttp_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...
 

Detailed Description

Set HTTP response headers and body, and send responses to the client

Sending response bodies

The API includes two functions for sending response bodies:

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.

Sending response headers

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:

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.

Memory allocation for response headers

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:

Macro Definition Documentation

◆ http_resp_set_hdr_ltrl

#define http_resp_set_hdr_ltrl (   resp,
  name,
  val 
)
Value:
http_resp_set_hdr((resp), (name), STRLEN_LTRL(name), (val), \
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.
#define STRLEN_LTRL(s)
Length of a literal string.
Definition: http.h:662
HTTP response.

Add a response header field named name with the value val. name and val MUST be literal strings (compile-time constant strings).

Example:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
// ...
// Set the Cache-Control to cache for one week
if (http_resp_set_hdr_str(resp, "Cache-Control", "max-age=604800")
!= ERR_OK) {
// Error handling
}
}
static struct resp * http_resp(struct http *http)
Get the current response object.
Definition: http.h:2729
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.
Definition: http.h:3001
Current HTTP connection, request and response.
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from http_resp()
[in]nameresponse header name
MUST be a literal string
[in]valheader value
MUST be a literal string
Returns
ERR_OK on success
ERR_MEM if there is insufficient memory for the header
See also
http_resp_set_hdr(), lwIP err_t

◆ http_resp_set_type_ltrl

#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:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
// ...
if (http_resp_set_type(resp, "application/json") != ERR_OK) {
// Error handling
}
}
static err_t http_resp_set_type(struct resp *resp, const char *type, size_t type_len)
Set the Content-Type response header.
Definition: http.h:3086
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from http_resp()
[in]typevalue to set for the Content-Type header
MUST be a literal string
Returns
ERR_OK on success
ERR_MEM if there is insufficient memory for the header
See also
http_resp_set_hdr(), lwIP err_t

◆ RESP_HDR_LARGE_BUF_SZ

#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.

See also
Memory allocation for response headers

◆ RESP_HDR_LARGE_POOL_SZ

#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.

See also
Memory allocation for response headers

◆ RESP_HDR_SMALL_BUF_SZ

#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.

See also
Memory allocation for response headers

◆ RESP_HDR_SMALL_POOL_SZ

#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.

See also
Memory allocation for response headers

Typedef Documentation

◆ hndlr_f

typedef err_t(* hndlr_f) (struct http *http, void *priv)

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.

Parameters
[in]httpHTTP object for the current connection.
Objects representing the current request and response are accessed via http_req() and http_resp().
[in]privOptional pointer passed to the register function
NULL if no such object was configured
Returns
ERR_OK on success, or an error status on failure
See also
http_req(), http_resp(), register_hndlr(), register_hndlr_methods(), register_default_hndlr(), register_error_hndlr(), lwIP err_t

Enumeration Type Documentation

◆ http_status_t

Enum representing HTTP response status codes

Enumerator
HTTP_STATUS_CONTINUE 

100 Continue

HTTP_STATUS_SWITCHING_PROTOCOLS 

101 Switching Protocols

HTTP_STATUS_OK 

200 OK

HTTP_STATUS_CREATED 

201 Created

HTTP_STATUS_ACCEPTED 

202 Accepted

HTTP_STATUS_NON_AUTHORITATIVE_INFO 

203 Non-Authoritative Information

HTTP_STATUS_NO_CONTENT 

204 No Content

HTTP_STATUS_RESET_CONTENT 

205 Reset Content

HTTP_STATUS_PARTIAL_CONTENT 

206 Partial Content

HTTP_STATUS_MULTIPLE_CHOICES 

300 Multiple Choices

HTTP_STATUS_MOVED_PERMANENTLY 

301 Moved Permanently

HTTP_STATUS_FOUND 

302 Found

HTTP_STATUS_SEE_OTHER 

303 See Other

HTTP_STATUS_NOT_MODIFIED 

304 Not Modified

HTTP_STATUS_USE_PROXY 

305 Use Proxy (deprecated)

HTTP_STATUS_TEMPORARY_REDIRECT 

307 Temporary Redirect

HTTP_STATUS_PERMANENT_REDIRECT 

308 Permanent Redirect

HTTP_STATUS_BAD_REQUEST 

400 Bad Request

HTTP_STATUS_UNAUTHORIZED 

401 Unauthorized

HTTP_STATUS_PAYMENT_REQUIRED 

402 Payment Required

HTTP_STATUS_FORBIDDEN 

403 Forbidden

HTTP_STATUS_NOT_FOUND 

404 Not Found

HTTP_STATUS_METHOD_NOT_ALLOWED 

405 Method Not Allowed

HTTP_STATUS_NOT_ACCEPTABLE 

406 Not Acceptable

HTTP_STATUS_PROXY_AUTH_REQUIRED 

407 Proxy Authentication Required

HTTP_STATUS_REQUEST_TIMEOUT 

408 Request Timeout

HTTP_STATUS_CONFLICT 

409 Conflict

HTTP_STATUS_GONE 

410 Gone

HTTP_STATUS_LENGTH_REQUIRED 

411 Length Required

HTTP_STATUS_PRECONDITION_FAILED 

412 Precondition Failed

HTTP_STATUS_CONTENT_TOO_LARGE 

413 Content Too Large

HTTP_STATUS_URI_TOO_LONG 

414 URI Too Long

HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE 

415 Unsupported Media Type

HTTP_STATUS_RANGE_NOT_SATISFIABLE 

416 Range Not Satisfiable

HTTP_STATUS_EXPECTATION_FAILED 

417 Expectation Failed

HTTP_STATUS_IM_A_TEAPOT 

418 I'm A Teapot

HTTP_STATUS_MISDIRECTED_REQUEST 

421 Misdirected Request

HTTP_STATUS_UNPROCESSABLE_CONTENT 

422 Unprocessable Content

HTTP_STATUS_UPGRADE_REQUIRED 

426 Upgrade Required

HTTP_STATUS_REQ_HDR_FIELDS_TOO_LARGE 

431 Request Header Fields Too Large

HTTP_STATUS_INTERNAL_SERVER_ERROR 

500 Internal Server Error

HTTP_STATUS_NOT_IMPLEMENTED 

501 Not Implemented

HTTP_STATUS_BAD_GATEWAY 

502 Bad Gateway

HTTP_STATUS_SERVICE_UNAVAILABLE 

503 Service Unavailable

HTTP_STATUS_GATEWAY_TIMEOUT 

504 Gateway Timeout

HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED 

505 HTTP Version Not Supported

Function Documentation

◆ http_resp()

static struct resp * http_resp ( struct http http)
inlinestatic

Get the object representing the current response on an HTTP connection.

Example:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp;
// ...
}
Parameters
[in]httpMUST be a valid HTTP object passed into a handler function
Returns
pointer to the current response object

◆ http_resp_err()

static err_t http_resp_err ( struct http http,
uint16_t  status 
)
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:

// This handler includes an implementation of error handling (a
// possible solution for what is glossed over as "Error handling ..."
// elsewhere in this documentation).
err_t
my_handler(struct http *http, void *priv)
{
err_t err;
// ...
// If setting the header fails, send an error response with status
// 500 (Internal Server Error).
err = http_resp_set_hdr_literal(resp, "Foo", "bar");
if (err != ERR_OK) {
HTTP_LOG_ERROR("Error setting response header: %d", err);
}
// ...
}
#define HTTP_LOG_ERROR(...)
Log an error message.
Definition: log.h:213
static err_t http_resp_err(struct http *http, uint16_t status)
Send an error response.
Definition: http.h:3540
@ HTTP_STATUS_INTERNAL_SERVER_ERROR
Definition: http.h:575
Parameters
[in]httpMUST be a valid HTTP object passed into a handler function
[in]statusresponse status code
MUST be >= 400
Returns
ERR_OK on success
or any error that may result from setting headers or sending the response
See also
register_error_hndlr(), lwIP err_t

◆ http_resp_send_buf()

err_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:

// This handler uses a local array for the response body.
err_t
a_handler(struct http *http, void *priv)
{
const uint8_t body[] = "Hello, world!";
size_t body_len = sizeof(body) - 1;
// Set response status and headers as required ...
// Set durable to false, so that the array is copied for send.
// Also sends the response header, if not already sent.
if (http_resp_send_buf(http, body, body_len, false) != ERR_OK) {
// Error handling ...
}
// ...
}
// The next handler uses a static const array for the response body.
static const uint8_t durable_body[] = "Hello, universe!";
#define DURABLE_LEN ((sizeof(durable_body) - 1)
err_t
another_handler(struct http *http, void *priv)
{
// Set response status and headers as required ...
// Set durable to true, since the array need not be copied for send.
if (http_resp_send_buf(http, durable_body, DURABLE_LEN, true)
!= ERR_OK) {
// Error handling ...
}
// ...
}
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.
Parameters
[in]httpMUST be a valid HTTP object passed into a handler function
[in]bufpointer to the buffer containing the response body
[in]lennumber of bytes in buf to send
[in]durableset to true iff buf points to durable storage, as described above
Returns
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 begun
any error that may be returned from http_resp_send_hdr(), if the header must be sent
any error that may be returned from the TCP stack for queueing the response
See also
Sending response bodies, http_resp_send_chunk(), http_resp_send_hdr(), lwIP err_t

◆ http_resp_send_chunk()

err_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:

  • The response header must include the field Transfer-Encoding: chunked. http_resp_set_xfer_chunked() does this as a convenience.
  • A Content-Length header must not be set.
  • A sequence of chunks must always be concluded by calling the function with len = 0 (and no further chunks may follow).
  • Do not use both of http_resp_send_chunk() and http_resp_send_buf() for the same response.

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:

#define CHUNK_SZ (1024)
static uint8_t chunk_buf[CHUNK_SZ];
void
next_chunk(uint8_t *buf, int n)
{
// ... A function that fills the contents of the nth chunk.
}
// This handler sends a 10 KB response body, 1 KiB at a time.
err_t
chunk_handler(struct http *http, void *priv)
{
// Set response status and headers as required ...
// Set the header for chunked encoding
if (http_resp_set_xfer_chunked(resp) != ERR_OK) {
// Error handling
}
for (int i = 0; i < 10; i++) {
next_chunk(chunk_buf, i);
if (http_resp_send_chunk(http, chunk_buf, CHUNK_SZ, false)
!= ERR_OK) {
// Error handling ...
}
}
// Finalize the response by sending a "null chunk".
if (http_resp_send_chunk(http, NULL, 0, false) != ERR_OK) {
// Error handling ...
}
// ...
}
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.
static err_t http_resp_set_xfer_chunked(struct resp *resp)
Set the Transfer-Encdoing response header to "chunked".
Definition: http.h:3246
Parameters
[in]httpMUST be a valid HTTP object passed into a handler function
[in]bufpointer to the buffer containing the chunk contents
[in]lennumber of bytes in buf to send, or 0 to finalize the response
[in]durableset to true iff buf points to durable storage, as described above
Returns
ERR_OK on success (the chunk and if necessary the response header are queued for send)
ERR_VAL if buf is NULL but len > 0
any error that may be returned from http_resp_send_hdr(), if the header must be sent
any error that may be returned from the TCP stack for queueing the response
See also
Sending response bodies, http_resp_send_hdr(), http_resp_send_buf(), lwIP err_t

◆ http_resp_send_hdr()

err_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:

err_t
my_handler(struct http *http, void *priv)
{
// Set the response status and headers as required ...
if (http_resp_send_hdr(http) != ERR_OK) {
// Error handling
}
}
err_t http_resp_send_hdr(struct http *http)
Send the response header.
Parameters
[in]httpMUST be a valid HTTP object passed into a handler function
Returns
ERR_OK on success
ERR_ALREADY if the header has already been sent
ERR_VAL if the response status is out of range (< 100 or >= 1000)
ERR_MEM if there is insufficient memory to send the header
See also
Sending response headers, lwIP err_t

◆ http_resp_set_hdr()

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:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp;
// ...
// Set response header "Foo: bar"
if (http_resp_set_hdr(resp, "Foo", 3, "bar", 3) != ERR_OK) {
// Error handling
}
}
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from the handler
[in]nameresponse header name
[in]name_lenlength of name
[in]valheader value
[in]val_lenlength of val
Returns
ERR_OK on success
ERR_VAL if either of name or val is NULL
ERR_MEM if there is insufficient memory for the header
See also
lwIP err_t

◆ http_resp_set_hdr_str()

static err_t http_resp_set_hdr_str ( struct resp resp,
const char *  name,
const char *  val 
)
inlinestatic

Add a response header field named name with the value val. name and val MUST be nul-terminated.

Example:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
const char *hdr = "Baz", *val = "quux";
// ...
// Set response header "Baz: quux"
if (http_resp_set_hdr_str(resp, hdr, val) != ERR_OK) {
// Error handling
}
}
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from http_resp()
[in]nameresponse header name
MAY NOT be NULL, and MUST be nul-terminated
[in]valheader value
MAY NOT be NULL, and MUST be nul-terminated
Returns
ERR_OK on success
ERR_MEM if there is insufficient memory for the header
See also
http_resp_set_hdr(), lwIP err_t

◆ http_resp_set_len()

err_t http_resp_set_len ( struct resp resp,
size_t  len 
)

Add the Content-Length response header with the value len.

Example:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
// ...
// Set Content-Length to this value
if (http_resp_set_len(resp, 4711) != ERR_OK) {
// Error handling
}
}
err_t http_resp_set_len(struct resp *resp, size_t len)
Set the Content-Length response header.
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from http_resp()
[in]lenvalue to set for the Content-Length header
may not be greater than INT32_MAX
Returns
ERR_OK on success
ERR_VAL if len is out of range (> INT32_MAX)
ERR_MEM if there is insufficient memory for the header
See also
lwIP err_t

◆ http_resp_set_status()

static err_t http_resp_set_status ( struct resp resp,
uint16_t  status 
)
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:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
// ...
// Set response status 202 "Accepted"
// Error handling
}
}
static err_t http_resp_set_status(struct resp *resp, uint16_t status)
Set the response status code.
Definition: http.h:2774
@ HTTP_STATUS_ACCEPTED
Definition: http.h:503
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from http_resp()
[in]statusresponse status
Returns
ERR_OK on success
ERR_VAL if status is out of range (< 100 or >= 1000)
See also
http_resp_status(), enum http_status_t, lwIP err_t

◆ http_resp_set_type()

static err_t http_resp_set_type ( struct resp resp,
const char *  type,
size_t  type_len 
)
inlinestatic

Add the Content-Type response header with the value type. type does not necessarily have to be nul-terminated.

Example:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
// ...
if (http_resp_set_type(resp, "text/html", 9) != ERR_OK) {
// Error handling
}
}
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from http_resp()
[in]typevalue to set for the Content-Type header
[in]type_lenlength of type
Returns
ERR_OK on success
ERR_VAL if type is NULL
ERR_MEM if there is insufficient memory for the header
See also
http_resp_set_hdr(), lwIP err_t

◆ http_resp_set_type_str()

static err_t http_resp_set_type_str ( struct resp resp,
const char *  type 
)
inlinestatic

Add the Content-Type response header with the value type. type MUST be nul-terminated.

Example:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
const char *jpg_type = "image/jpeg";
// ...
if (http_resp_set_type(resp, jpeg_type) != ERR_OK) {
// Error handling
}
}
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from http_resp()
[in]typevalue to set for the Content-Type header
MAY NOT be NULL, and MUST be nul-terminated
Returns
ERR_OK on success
ERR_MEM if there is insufficient memory for the header
See also
http_resp_set_hdr(), lwIP err_t

◆ http_resp_set_xfer_chunked()

static err_t http_resp_set_xfer_chunked ( struct resp resp)
inlinestatic

Add the Transfer-Encoding response header with the value "chunked". This is required for chunked transfer encoding.

Example:

err_t
my_handler(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
// ...
// Set the header for chunked encoding
if (http_resp_set_xfer_chunked(resp) != ERR_OK) {
// Error handling
}
// ...
}
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from http_resp()
Returns
ERR_OK on success
ERR_MEM if there is insufficient memory for the header
See also
Sending response bodies, http_resp_send_chunk(), lwIP err_t

◆ http_resp_status()

static uint16_t http_resp_status ( struct resp resp)
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:

// This is a custom error handler, see register_error_hndlr().
// If the handler was configured for mutliple error status codes,
// http_resp_status() can be used to distinguish them.
err_t
err_handler(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
uint16_t status;
// ...
switch (status) {
// ... generate the 404 response ...
break;
// ... cases for other status codes ...
}
return ERR_OK;
}
static uint16_t http_resp_status(struct resp *resp)
Get the response status code.
Definition: http.h:2827
@ HTTP_STATUS_NOT_FOUND
Definition: http.h:537
Parameters
[in]respresp object for the current response
MUST be a valid resp pointer obtained from http_resp()
Returns
response status
See also
http_resp_set_status(), enum http_status_t, lwIP err_t

◆ register_default_hndlr()

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:

// Default handler that generates responses to POST requests whose path
// begins with "/foo". Return a 404 response for any other request.
// No private data is used.
err_t
foo_hndlr(struct http *http, void *priv)
{
struct req *req = http_req(http);
const char *path;
size_t path_len;
(void)priv;
path = http_req_path(req, &path_len);
// Return a 404 response if the path prefix is not "/foo".
if (path_len < STRLEN_LTRL("/foo") ||
memcmp(path, "/foo", STRLEN_LTRL("/foo")) != 0)
// Return a 405 response if the method is not POST.
// ... generate a response for POST /foo* ...
return ERR_OK;
}
// Register the default handler.
if ((err = register_default_hndlr(&cfg, foo_hndlr, NULL, NULL)) != ERR_OK) {
// ... error handling ...
}
static struct req * http_req(struct http *http)
Get the current request object.
Definition: http.h:1330
static enum http_method_t http_req_method(struct req *req)
Return the request method.
Definition: http.h:2115
static const uint8_t * http_req_path(struct req *req, size_t *len)
Return the path from the first request line.
Definition: http.h:2163
err_t register_default_hndlr(struct server_cfg *cfg, hndlr_f hndlr, void *priv, priv_fini_f fini)
Register a default response handler.
static struct server_cfg http_default_cfg(void)
Get the default HTTP server configuration.
Definition: http.h:894
@ HTTP_METHOD_POST
Definition: http.h:382
@ HTTP_STATUS_METHOD_NOT_ALLOWED
Definition: http.h:539
HTTP request.
HTTP server configuration.
Definition: http.h:774
Parameters
[in]cfgserver configuration
MUST be a valid configuration returned from http_cfg() or http_default_cfg()
[in]hndlrdefault handler function to be registered
MUST satisfy typedef hndlr_f
[in]privpointer to private data passed into the handler
set to NULL if private data is not needed for the default handler
[in]finipointer to a finalizer function for priv
set to NULL if not needed
Returns
ERR_OK on success
ERR_VAL if either of cfg or hndlr is NULL
See also
register_hndlr(), register_hndlr_methods(), typedef hndlr_f, lwIP err_t, Application private data

◆ register_error_hndlr()

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:

  • responses generated by http_resp_err()
  • if status codes 404 ("Not found") and/or 405 ("Method not allowed") were configured in 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)
  • if status 406 ("Not acceptable") was configured, the error response for a static resource when the request's Accept-Encoding header does not match any encoding configured for the resource
  • if status 500 ("Internal server error") was configured, the error response generated when any response handler does not return ERR_OK
  • if status 501 ("Not implemented") was configured, the error response generated if the path and method of a request match a combination configured for custom, but no handler has been registered for it

A 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:

static const uint8_t err_body[] =
"... HTML for an aesthetic error response goes here ...";
static const size_t body_len = sizeof(err_body) - 1;
// Custom error handler that returns the aesthetic error response
// for response status codes configured in the custom_error section
// of www.yaml.
static err_t
err_hndlr(struct http *http, void *priv)
{
struct resp *resp = http_resp(http);
err_t err;
// The response status will have already been set.
// Connection: close is added automatically to the response header.
// The client connection will be closed after the response is sent.
// Set Content-Type to text/html
if ((err = http_resp_set_type_ltrl(resp, "text/html")) != ERR_OK)
return err;
// Set Content-Length
if ((err = http_resp_set_len(resp, body_len)) != ERR_OK)
return err;
// Send the response header and body
return http_resp_send_buf(http, body, body_len, true);
}
// Register the error handler.
if ((err = register_error_hndlr(&cfg, err_hndlr, NULL, NULL)) != ERR_OK) {
// ... error handling ...
}
#define http_resp_set_type_ltrl(resp, type)
Set the Content-Type response header to a literal string.
Definition: http.h:3169
err_t register_error_hndlr(struct server_cfg *cfg, hndlr_f hndlr, void *priv, priv_fini_f fini)
Register a custom error response handler.
Parameters
[in]cfgserver configuration
MUST be a valid configuration returned from http_cfg() or http_default_cfg()
[in]hndlrerror handler function to be registered
MUST satisfy typedef hndlr_f
[in]privpointer to private data passed into the handler
set to NULL if private data is not needed for the error handler
[in]finipointer to a finalizer function for priv
set to NULL if not needed
Returns
ERR_OK on success
ERR_VAL if either of cfg or hndlr is NULL
ERR_ARG if custom_error did not appear in the build configuration
See also
register_hndlr(), register_hndlr_methods(), register_default_hndlr(), typedef hndlr_f, lwIP err_t, Application private data

◆ register_hndlr()

static err_t register_hndlr ( struct server_cfg cfg,
const char *  path,
hndlr_f  hndlr,
enum http_method_t  method,
void *  priv 
)
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:

// Declaration of the private data type to be used by the foo handler.
// Using the "magic number" idiom, to enable checks from assertion.h
struct foo_data {
unsigned magic;
#define FOO_MAGIC 0xf9d15092
// ... additional struct members ...
};
// Static declaration and initialization of private data for the
// foo handler
static struct foo_data foo = {
.magic = FOO_MAGIC,
// ... additional struct member initalizations ...
};
// Handler for POST /foo requests
err_t
foo_handler(struct http *http, void *priv)
{
struct foo_data *hndlr_data;
// Using checks from assertion.h
CHECK_OBJ_NOTNULL(http, HTTP_MAGIC);
// In debug builds, this verifies the type of the priv pointer
CAST_OBJ_NOTNULL(hndlr_data, priv, FOO_MAGIC);
// ... generate a response for POST /foo
}
// Handler for GET or HEAD /bar requests
// Also invoked with any query string, such as /bar?baz=quux
err_t
bar_handler(struct http *http, void *priv)
{
// Using a check from assertion.h.
CHECK_OBJ_NOTNULL(http, HTTP_MAGIC);
// No priv pointer is used by this handler
(void)priv;
// ... generate a response for GET or HEAD /foo
}
int
main(void)
{
struct server *srv;
struct server_cfg cfg;
// Get the default configuration
// Register foo_handler for POST /foo
&cfg, "/foo", foo_handler, HTTP_METHOD_POST, &foo)
!= ERR_OK) {
// Error handling ...
}
// Register bar_handler for GET and HEAD /bar
// Here we call register_hndlr() for both methods separately;
// the same could be accomplished by calling register_hndlr_methods()
// with the bitmap defined in HTTP_METHODS_GET_HEAD.
// Set priv to NULL, since the handler doesn't use private data
&cfg, "/bar", bar_handler, HTTP_METHOD_GET, NULL)
!= ERR_OK) {
// Error handling ...
}
&cfg, "/bar", bar_handler, HTTP_METHOD_HEAD, NULL)
!= ERR_OK) {
// Error handling ...
}
// Start the server.
// The handlers registered above are immediately active.
if (http_srv_init(&srv, &cfg) != ERR_OK) {
// Error handling ...
}
}
#define CHECK_OBJ_NOTNULL(ptr, type_magic)
Assert that a pointer is not NULL, and points to an object that is valid for its type.
Definition: assertion.h:362
#define CAST_OBJ_NOTNULL(to, from, type_magic)
Cast a pointer, and assert that it it is not NULL and points to an object that is valid for its type.
Definition: assertion.h:506
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.
Definition: http.h:3803
err_t http_srv_init(struct server **server, struct server_cfg *cfg)
Start an HTTP server.
@ HTTP_METHOD_HEAD
Definition: http.h:381
@ HTTP_METHOD_GET
Definition: http.h:380
HTTP server.
Parameters
[in]cfgserver configuration
MUST be a valid configuration returned from http_cfg() or http_default_cfg()
[in]pathURL path for which the handler is registered
query strings do not form a part of the path
[in]hndlrhandler function to be registered
MUST satisfy the typedef for hndlr_f
[in]methodenum value representing the request method for which the handler is registered
[in]privpointer to private data passed into the handler
set to NULL if handler-specific private data is not needed
Returns
ERR_OK on success
ERR_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
See also
register_hndlr_methods(), register_default_hndlr(), register_error_hndlr(), typedef hndlr_f, enum http_method_t, lwIP err_t, Application private data

◆ register_hndlr_methods()

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:

// Bitmap representing the REST methods.
#define REST_METHODS \
((1U << HTTP_METHOD_GET) | (1U << HTTP_METHOD_POST) | \
(1U << HTTP_METHOD_PUT) | (1U << HTTP_METHOD_DELETE))
// Handler for a REST endpoint
err_t
rest_handler(struct http *http, void *priv)
{
// ... generate a response for GET, POST, PUT or DELETE /rest
}
// Handler for GET or HEAD /foo requests
// Also invoked with any query string, such as /foo?bar=baz
err_t
foo_handler(struct http *http, void *priv)
{
// ... generate a response for GET or HEAD /foo
}
int
main(void)
{
struct server *srv;
struct server_cfg cfg;
// Get the default configuration
// Register rest_handler for the REST endpoint
&cfg, "/rest", rest_handler, REST_METHODS, NULL) != ERR_OK) {
// Error handling ...
}
// Register foo_handler for GET and HEAD /foo
// Using HTTP_METHODS_GET_HEAD defined in http.h
&cfg, "/foo", foo_handler, HTTP_METHODS_GET_HEAD, NULL)
!= ERR_OK) {
// Error handling ...
}
// Start the server.
// The handlers registered above are immediately active.
if (http_srv_init(&srv, &cfg) != ERR_OK) {
// Error handling ...
}
}
#define HTTP_METHODS_GET_HEAD
Bitmap for methods GET and HEAD.
Definition: http.h:402
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.
Parameters
[in]cfgserver configuration
MUST be a valid configuration returned from http_cfg() or http_default_cfg()
[in]pathURL path for which the handler is registered
query strings do not form a part of the path
[in]hndlrhandler function to be registered
MUST satisfy the typedef for hndlr_f
[in]methodsbitmap representing the request methods for which the handler is registered
the bit positions are values of enum http_method_t
[in]privpointer to private data passed into the handler
set to NULL if handler-specific private data is not needed
Returns
ERR_OK on success
ERR_VAL if either of path or hndlr is NULL
ERR_ARG if no custom handler was configured for method and path at build time
See also
register_hndlr(), register_default_hndlr(), register_error_hndlr(), typedef hndlr_f, http_cfg(), http_default_cfg(), enum http_method_t, lwIP err_t, Application private data