| /* |
| * Copyright (c) 2017 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef __HTTP_H__ |
| #define __HTTP_H__ |
| |
| #include <net/net_context.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @brief HTTP client and server library |
| * @defgroup http HTTP Library |
| * @{ |
| */ |
| |
| #if defined(CONFIG_HTTPS) |
| #if defined(CONFIG_MBEDTLS) |
| #if !defined(CONFIG_MBEDTLS_CFG_FILE) |
| #include "mbedtls/config.h" |
| #else |
| #include CONFIG_MBEDTLS_CFG_FILE |
| #endif /* CONFIG_MBEDTLS_CFG_FILE */ |
| |
| #if defined(MBEDTLS_PLATFORM_C) |
| #include "mbedtls/platform.h" |
| #else |
| #include <stdlib.h> |
| #define mbedtls_time_t time_t |
| #define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS |
| #define MBEDTLS_EXIT_FAILURE EXIT_FAILURE |
| #endif /* MBEDTLS_PLATFORM_C */ |
| |
| #include <mbedtls/ssl_cookie.h> |
| #include <mbedtls/entropy.h> |
| #include <mbedtls/ctr_drbg.h> |
| #include <mbedtls/net_sockets.h> |
| #include <mbedtls/x509.h> |
| #include <mbedtls/x509_crt.h> |
| #include <mbedtls/ssl.h> |
| #include <mbedtls/error.h> |
| #include <mbedtls/debug.h> |
| #endif /* CONFIG_MBEDTLS */ |
| #endif /* CONFIG_HTTPS */ |
| |
| #define HTTP_CRLF "\r\n" |
| |
| #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) |
| void http_heap_init(void); |
| #else |
| #define http_heap_init() |
| #endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ |
| |
| typedef int (*http_send_data_t)(struct net_pkt *pkt, |
| net_context_send_cb_t cb, |
| s32_t timeout, |
| void *token, |
| void *user_data); |
| |
| #if defined(CONFIG_HTTPS) |
| /* Internal information for managing HTTPS data */ |
| struct https_context { |
| struct net_pkt *rx_pkt; |
| struct net_buf *frag; |
| struct k_sem tx_sem; |
| struct k_fifo rx_fifo; |
| struct k_fifo tx_fifo; |
| int remaining; |
| }; |
| |
| /** |
| * @typedef https_entropy_src_cb_t |
| * @brief Callback used when the API user needs to setup the entropy source. |
| * @detail This is the same as mbedtls_entropy_f_source_ptr callback. |
| * |
| * @param data Callback-specific data pointer |
| * @param output Data to fill |
| * @param len Maximum size to provide |
| * @param olen The actual amount of bytes put into the buffer (Can be 0) |
| */ |
| typedef int (*https_entropy_src_cb_t)(void *data, unsigned char *output, |
| size_t len, size_t *olen); |
| #endif /* CONFIG_HTTPS */ |
| |
| #if defined(CONFIG_HTTP_CLIENT) |
| |
| #include <net/http_parser.h> |
| #include <net/net_context.h> |
| |
| /* Is there more data to come */ |
| enum http_final_call { |
| HTTP_DATA_MORE = 0, |
| HTTP_DATA_FINAL = 1, |
| }; |
| |
| #ifndef HTTP_PROTOCOL |
| #define HTTP_PROTOCOL "HTTP/1.1" |
| #endif |
| |
| /* Some generic configuration options, these can be overriden if needed. */ |
| #ifndef HTTP_STATUS_STR_SIZE |
| #define HTTP_STATUS_STR_SIZE 32 |
| #endif |
| |
| /* It seems enough to hold 'Content-Length' and its value */ |
| #define HTTP_CONTENT_LEN_SIZE 48 |
| |
| /* Default HTTP Header Field values for HTTP Requests if using the |
| * HTTP_HEADER_FIELDS define. |
| */ |
| #ifndef HTTP_ACCEPT |
| #define HTTP_ACCEPT "text/plain" |
| #endif |
| |
| #ifndef HTTP_ACCEPT_ENC |
| #define HTTP_ACCEPT_ENC "identity" |
| #endif |
| |
| #ifndef HTTP_ACCEPT_LANG |
| #define HTTP_ACCEPT_LANG "en-US" |
| #endif |
| |
| #ifndef HTTP_CONNECTION |
| #define HTTP_CONNECTION "Close" |
| #endif |
| |
| #ifndef HTTP_USER_AGENT |
| #define HTTP_USER_AGENT "Zephyr-HTTP-Client/1.8" |
| #endif |
| |
| /* This can be used in http_client_send_get_req() when supplying |
| * extra_header_fields parameter. |
| */ |
| #ifndef HTTP_HEADER_FIELDS |
| #define HTTP_HEADER_FIELDS \ |
| "Accept: " HTTP_ACCEPT HTTP_CRLF \ |
| "Accept-Encoding: " HTTP_ACCEPT_ENC HTTP_CRLF \ |
| "Accept-Language: " HTTP_ACCEPT_LANG HTTP_CRLF \ |
| "User-Agent: " HTTP_USER_AGENT HTTP_CRLF \ |
| "Connection: " HTTP_CONNECTION HTTP_CRLF |
| #endif |
| |
| struct http_client_ctx; |
| |
| /** |
| * @typedef http_receive_cb_t |
| * @brief Callback used when TCP data has been received from peer. |
| * |
| * @param ctx HTTP context. |
| * @param pkt Network packet. |
| */ |
| typedef void (*http_receive_cb_t)(struct http_client_ctx *ctx, |
| struct net_pkt *pkt); |
| |
| /** |
| * @typedef http_response_cb_t |
| * @brief Callback used when a response has been received from peer. |
| * |
| * @param ctx HTTP context. |
| * @param data Received data buffer |
| * @param buflen Data buffer len (as specified by user) |
| * @param datalen Received data len, if this is larger than buflen, |
| * then some data was skipped. |
| * @param final_data Does this data buffer contain all the data or |
| * is there still more data to come. |
| * @param user_data A valid pointer on some user data or NULL |
| */ |
| typedef void (*http_response_cb_t)(struct http_client_ctx *ctx, |
| u8_t *data, size_t buflen, |
| size_t datalen, |
| enum http_final_call final_data, |
| void *user_data); |
| |
| #if defined(CONFIG_HTTPS) |
| /** |
| * @typedef https_ca_cert_cb_t |
| * @brief Callback used when the API user needs to setup the |
| * HTTPS certs. |
| * |
| * @param ctx HTTPS client context. |
| * @param ca_cert MBEDTLS certificate. This is of type mbedtls_x509_crt |
| * if MBEDTLS_X509_CRT_PARSE_C is defined. |
| * |
| * @return 0 if ok, <0 if there is an error |
| */ |
| typedef int (*https_ca_cert_cb_t)(struct http_client_ctx *ctx, |
| void *ca_cert); |
| #endif /* CONFIG_HTTPS */ |
| |
| /** |
| * HTTP client context information. This contains all the data that is |
| * needed when doing HTTP requests. |
| */ |
| struct http_client_ctx { |
| struct http_parser parser; |
| struct http_parser_settings settings; |
| |
| /** Server name */ |
| const char *server; |
| |
| #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) |
| /** Network packet (net_pkt) memory pool for network contexts attached |
| * to this http_client context. |
| */ |
| net_pkt_get_slab_func_t tx_slab; |
| |
| /** Network data net_buf pool for network contexts attached to this |
| * http_client context. |
| */ |
| net_pkt_get_pool_func_t data_pool; |
| #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ |
| |
| /** Is this instance HTTPS or not. |
| */ |
| bool is_https; |
| |
| #if defined(CONFIG_DNS_RESOLVER) |
| /** Remember the DNS query id so that it can be cancelled |
| * if the HTTP context is released and the query is active |
| * at that time. |
| */ |
| u16_t dns_id; |
| #endif |
| |
| struct { |
| /** Local socket address */ |
| struct sockaddr local; |
| |
| /** Remote (server) socket address */ |
| struct sockaddr remote; |
| |
| /** IP stack network context */ |
| struct net_context *ctx; |
| |
| /** Network timeout */ |
| s32_t timeout; |
| |
| /** User can define this callback if it wants to have |
| * special handling of the received raw data. Note that this |
| * callback is not called for HTTPS data. |
| */ |
| http_receive_cb_t receive_cb; |
| |
| /** Internal function that is called when HTTP data is |
| * received from network. |
| */ |
| net_context_recv_cb_t recv_cb; |
| |
| /** Internal function that is called when HTTP data is sent to |
| * network. |
| */ |
| http_send_data_t send_data; |
| } tcp; |
| |
| /** HTTP request information */ |
| struct { |
| /** |
| * Semaphore to signal HTTP request completion |
| */ |
| struct k_sem wait; |
| |
| /** Hostname to be used in the request */ |
| const char *host; |
| |
| /** User provided data */ |
| void *user_data; |
| |
| /** What method we used here (GET, POST, HEAD etc.) |
| */ |
| enum http_method method; |
| } req; |
| |
| /** HTTP response information */ |
| struct { |
| /** User provided HTTP response callback which is called |
| * when a response is received to a sent HTTP request. |
| */ |
| http_response_cb_t cb; |
| |
| /** Where the response is stored, this is to be provided |
| * by the user. |
| */ |
| u8_t *response_buf; |
| |
| /** Where the body starts. |
| */ |
| u8_t *body_start; |
| |
| /** Response buffer maximum length */ |
| size_t response_buf_len; |
| |
| /** Length of the data in the result buf. If the value is |
| * larger than response_buf_len, then it means that the data |
| * is truncated and could not be fully copied into |
| * response_buf. This can only happen if the user did not |
| * set the response callback. If the callback is set, then |
| * the HTTP client API will call response callback many times |
| * so that all the data is delivered to the user. |
| */ |
| size_t data_len; |
| |
| /** HTTP Content-Length field value */ |
| size_t content_length; |
| |
| /** Content length parsed. This should be the same as the |
| * content_length field if parsing was ok. |
| */ |
| size_t processed; |
| |
| /* https://tools.ietf.org/html/rfc7230#section-3.1.2 |
| * The status-code element is a 3-digit integer code |
| * |
| * The reason-phrase element exists for the sole purpose of |
| * providing a textual description associated with the |
| * numeric status code. A client SHOULD ignore the |
| * reason-phrase content. |
| */ |
| char http_status[HTTP_STATUS_STR_SIZE]; |
| |
| u8_t cl_present:1; |
| u8_t body_found:1; |
| u8_t message_complete:1; |
| } rsp; |
| |
| #if defined(CONFIG_HTTPS) |
| struct { |
| /** HTTPS stack for mbedtls library. */ |
| k_thread_stack_t *stack; |
| |
| /** HTTPS stack size. */ |
| int stack_size; |
| |
| /** HTTPS thread id */ |
| k_tid_t tid; |
| |
| /** HTTPS thread */ |
| struct k_thread thread; |
| |
| /** Memory pool for RX data */ |
| struct k_mem_pool *pool; |
| |
| /** Hostname to be used in the certificate verification */ |
| const char *cert_host; |
| |
| /** mbedtls related configuration. */ |
| struct { |
| struct https_context ssl_ctx; |
| https_ca_cert_cb_t cert_cb; |
| https_entropy_src_cb_t entropy_src_cb; |
| mbedtls_entropy_context entropy; |
| mbedtls_ctr_drbg_context ctr_drbg; |
| mbedtls_ssl_context ssl; |
| mbedtls_ssl_config conf; |
| mbedtls_x509_crt ca_cert; |
| u8_t *personalization_data; |
| size_t personalization_data_len; |
| } mbedtls; |
| } https; |
| #endif /* CONFIG_HTTPS */ |
| }; |
| |
| /** |
| * HTTP client request. This contains all the data that is needed when doing |
| * a HTTP request. |
| */ |
| struct http_client_request { |
| /** The HTTP method: GET, HEAD, OPTIONS, POST, ... */ |
| enum http_method method; |
| |
| /** The URL for this request, for example: /index.html */ |
| const char *url; |
| |
| /** The HTTP protocol: HTTP/1.1 */ |
| const char *protocol; |
| |
| /** The HTTP header fields (application specific) |
| * The Content-Type may be specified here or in the next field. |
| * Depending on your application, the Content-Type may vary, however |
| * some header fields may remain constant through the application's |
| * life cycle. |
| */ |
| const char *header_fields; |
| |
| /** The value of the Content-Type header field, may be NULL */ |
| const char *content_type_value; |
| |
| /** Hostname to be used in the request */ |
| const char *host; |
| |
| /** Payload, may be NULL */ |
| const char *payload; |
| |
| /** Payload size, may be 0 */ |
| u16_t payload_size; |
| }; |
| |
| /** |
| * @brief Generic function to send a HTTP request to the network. Normally |
| * applications would not need to use this function. |
| * |
| * @param ctx HTTP client context. |
| * @param req HTTP request to perform. |
| * @param timeout Timeout when doing net_buf allocations. |
| * |
| * @return Return 0 if ok, and <0 if error. |
| */ |
| int http_request(struct http_client_ctx *ctx, |
| struct http_client_request *req, |
| s32_t timeout); |
| |
| /** |
| * @brief Send a HTTP request to peer. |
| * |
| * @param http_ctx HTTP context. |
| * @param req HTTP request to perform. |
| * @param cb Callback to call when the response has been received from peer. |
| * @param response_buf Caller-supplied buffer where the HTTP response will be |
| * stored |
| * @param response_buf_len Length of the caller-supplied buffer. |
| * @param user_data A valid pointer on some user data or NULL |
| * @param timeout Amount of time to wait for a reply. If the timeout is 0, |
| * then we return immediately and the callback (if set) will be called later. |
| * |
| * @return Return 0 if ok, and <0 if error. |
| */ |
| int http_client_send_req(struct http_client_ctx *http_ctx, |
| struct http_client_request *req, |
| http_response_cb_t cb, |
| u8_t *response_buf, |
| size_t response_buf_len, |
| void *user_data, |
| s32_t timeout); |
| |
| /** |
| * @brief Send a HTTP GET request to peer. |
| * |
| * @param http_ctx HTTP context. |
| * @param url URL to use. |
| * @param host Host field in HTTP header. If set to NULL, then server |
| * name is used. |
| * @param extra_header_fields Any extra header fields that caller wants |
| * to add. This can be set to NULL. The format is "name: value\r\n" |
| * Example: "Accept: text/plain\r\nConnection: Close\r\n" |
| * @param cb Callback to call when the response has been received from peer. |
| * @param response_buf Caller-supplied buffer where the HTTP request will be |
| * stored |
| * @param response_buf_len Length of the caller-supplied buffer. |
| * @param user_data A valid pointer on some user data or NULL |
| * @param timeout Amount of time to wait for a reply. If the timeout is 0, |
| * then we return immediately and the callback (if set) will be called later. |
| * |
| * @return Return 0 if ok, and <0 if error. |
| */ |
| static inline int http_client_send_get_req(struct http_client_ctx *http_ctx, |
| const char *url, |
| const char *host, |
| const char *extra_header_fields, |
| http_response_cb_t cb, |
| u8_t *response_buf, |
| size_t response_buf_len, |
| void *user_data, |
| s32_t timeout) |
| { |
| struct http_client_request req = { |
| .method = HTTP_GET, |
| .url = url, |
| .host = host, |
| .protocol = " " HTTP_PROTOCOL HTTP_CRLF, |
| .header_fields = extra_header_fields, |
| }; |
| |
| return http_client_send_req(http_ctx, &req, cb, response_buf, |
| response_buf_len, user_data, timeout); |
| } |
| |
| /** |
| * @brief Send a HTTP POST request to peer. |
| * |
| * @param http_ctx HTTP context. |
| * @param url URL to use. |
| * @param host Host field in HTTP header. If set to NULL, then server |
| * name is used. |
| * @param extra_header_fields Any extra header fields that caller wants |
| * to add. This can be set to NULL. The format is "name: value\r\n" |
| * Example: "Accept: text/plain\r\nConnection: Close\r\n" |
| * @param content_type Content type of the data. |
| * @param payload Payload data. |
| * @param cb Callback to call when the response has been received from peer. |
| * @param response_buf Caller-supplied buffer where the HTTP response will be |
| * stored |
| * @param response_buf_len Length of the caller-supplied buffer. |
| * @param user_data A valid pointer on some user data or NULL |
| * @param timeout Amount of time to wait for a reply. If the timeout is 0, |
| * then we return immediately and the callback (if set) will be called later. |
| * |
| * @return Return 0 if ok, and <0 if error. |
| */ |
| static inline int http_client_send_post_req(struct http_client_ctx *http_ctx, |
| const char *url, |
| const char *host, |
| const char *extra_header_fields, |
| const char *content_type, |
| const char *payload, |
| http_response_cb_t cb, |
| u8_t *response_buf, |
| size_t response_buf_len, |
| void *user_data, |
| s32_t timeout) |
| { |
| struct http_client_request req = { |
| .method = HTTP_POST, |
| .url = url, |
| .host = host, |
| .protocol = " " HTTP_PROTOCOL HTTP_CRLF, |
| .header_fields = extra_header_fields, |
| .content_type_value = content_type, |
| .payload = payload, |
| }; |
| |
| return http_client_send_req(http_ctx, &req, cb, response_buf, |
| response_buf_len, user_data, timeout); |
| } |
| |
| /** |
| * @brief Initialize user-supplied HTTP context. |
| * |
| * @detail Caller can set the various fields in http_ctx after this call |
| * if needed. |
| * |
| * @param http_ctx HTTP context. |
| * @param server HTTP server address or host name. If host name is given, |
| * then DNS resolver support (CONFIG_DNS_RESOLVER) must be enabled. If caller |
| * sets the server parameter as NULL, then no attempt is done to figure out |
| * the remote address and caller must set the address in http_ctx.tcp.remote |
| * itself. |
| * @param server_port HTTP server TCP port. |
| * |
| * @return Return 0 if ok, <0 if error. |
| */ |
| int http_client_init(struct http_client_ctx *http_ctx, |
| const char *server, u16_t server_port); |
| |
| #if defined(CONFIG_HTTPS) |
| /** |
| * @brief Initialize user-supplied HTTP context when using HTTPS. |
| * |
| * @detail Caller can set the various fields in http_ctx after this call |
| * if needed. |
| * |
| * @param http_ctx HTTPS context. |
| * @param server HTTPS server address or host name. If host name is given, |
| * then DNS resolver support (CONFIG_DNS_RESOLVER) must be enabled. If caller |
| * sets the server parameter as NULL, then no attempt is done to figure out |
| * the remote address and caller must set the address in http_ctx.tcp.remote |
| * itself. |
| * @param server_port HTTPS server TCP port. |
| * @param personalization_data Personalization data (Device specific |
| * identifiers) for random number generator. (Can be NULL). |
| * @param personalization_data_len Length of the personalization data. |
| * @param cert_cb User-supplied callback that setups the certificates. |
| * @param cert_host Hostname that is used to verify the server certificate. |
| * This value is used when HTTP client API calls mbedtls_ssl_set_hostname() |
| * which sets the hostname to check against the received server certificate. |
| * See https://tls.mbed.org/kb/how-to/use-sni for more details. |
| * This can be left NULL in which case mbedtls will silently skip certificate |
| * verification entirely. This option is only used if MBEDTLS_X509_CRT_PARSE_C |
| * is enabled in mbedtls config file. |
| * @param entropy_src_cb User-supplied callback that setup the entropy. This |
| * can be set to NULL, in which case default entropy source is used. |
| * @param pool Memory pool for RX data reads. |
| * @param https_stack HTTPS thread stack. |
| * @param https_stack_len HTTP thread stack size. |
| * |
| * @return Return 0 if ok, <0 if error. |
| */ |
| int https_client_init(struct http_client_ctx *http_ctx, |
| const char *server, u16_t server_port, |
| u8_t *personalization_data, |
| size_t personalization_data_len, |
| https_ca_cert_cb_t cert_cb, |
| const char *cert_host, |
| https_entropy_src_cb_t entropy_src_cb, |
| struct k_mem_pool *pool, |
| k_thread_stack_t *https_stack, |
| size_t https_stack_size); |
| #endif /* CONFIG_HTTPS */ |
| |
| /** |
| * @brief Release all the resources allocated for HTTP context. |
| * |
| * @param http_ctx HTTP context. |
| */ |
| void http_client_release(struct http_client_ctx *http_ctx); |
| |
| #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) |
| /** |
| * @brief Configure the net_pkt pool for this context. |
| * |
| * @details Use of this function is optional and if the pools are not set, |
| * then the default TX and DATA pools are used. This needs to be called before |
| * http init function, as that will setup net_context which needs the net_pkt |
| * pool information. |
| * |
| * @param ctx HTTP client context |
| * @param tx_slab Function which is used when allocating TX network packet. |
| * This can be NULL in which case default TX memory pool is used. |
| * @param data_pool Function which is used when allocating data network buffer. |
| * This can be NULL in which case default DATA net_buf pool is used. |
| */ |
| int http_client_set_net_pkt_pool(struct http_client_ctx *ctx, |
| net_pkt_get_slab_func_t tx_slab, |
| net_pkt_get_pool_func_t data_pool); |
| #else |
| #define http_client_set_net_pkt_pool(...) |
| #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ |
| #endif /* CONFIG_HTTP_CLIENT */ |
| |
| #if defined(CONFIG_HTTP_SERVER) |
| |
| #include <net/net_context.h> |
| #include <net/http_parser.h> |
| |
| struct http_server_ctx; |
| |
| enum http_url_flags { |
| HTTP_URL_STANDARD = 0, |
| }; |
| |
| /* HTTP header fields struct */ |
| struct http_field_value { |
| /** Field name, this variable will point to the beginning of the string |
| * containing the HTTP field name |
| */ |
| const char *key; |
| |
| /** Value, this variable will point to the beginning of the string |
| * containing the field value |
| */ |
| const char *value; |
| |
| /** Length of the field name */ |
| u16_t key_len; |
| |
| /** Length of the field value */ |
| u16_t value_len; |
| }; |
| |
| typedef int (*http_url_cb_t)(struct http_server_ctx *ctx); |
| |
| /* HTTP root URL struct, used for pattern matching */ |
| struct http_root_url { |
| /** URL */ |
| const char *root; |
| |
| /** Callback that is called when this URL is received */ |
| http_url_cb_t write_cb; |
| |
| /** Length of the URL */ |
| u16_t root_len; |
| |
| /** Flags for this URL (values are from enum http_url_flags) */ |
| u8_t flags; |
| |
| /** Is this URL resource used or not */ |
| u8_t is_used; |
| }; |
| |
| /* Collection of URLs that this server will handle */ |
| struct http_server_urls { |
| /* First item is the default handler and it is always there. |
| */ |
| struct http_root_url default_url; |
| struct http_root_url urls[CONFIG_HTTP_SERVER_NUM_URLS]; |
| }; |
| |
| #if defined(CONFIG_HTTPS) |
| /** |
| * @typedef https_server_cert_cb_t |
| * @brief Callback used when the API user needs to setup the |
| * HTTPS certs. |
| * |
| * @param ctx HTTPS server context. |
| * @param cert MBEDTLS certificate |
| * @param pkey MBEDTLS private key |
| * |
| * @return 0 if ok, <0 if there is an error |
| */ |
| typedef int (*https_server_cert_cb_t)(struct http_server_ctx *ctx, |
| mbedtls_x509_crt *cert, |
| mbedtls_pk_context *pkey); |
| #endif /* CONFIG_HTTPS */ |
| |
| /* The HTTP server context struct */ |
| struct http_server_ctx { |
| /** Collection of URLs that this server context will handle */ |
| struct http_server_urls *urls; |
| |
| #if defined(CONFIG_NET_IPV4) |
| /** IPv4 stack network context for listening */ |
| struct net_context *net_ipv4_ctx; |
| #endif |
| #if defined(CONFIG_NET_IPV6) |
| /** IPv6 stack network context for listening */ |
| struct net_context *net_ipv6_ctx; |
| #endif |
| |
| /** Function that is called when data is received from network. */ |
| net_context_recv_cb_t recv_cb; |
| |
| /** Function that is called when data is sent to network. */ |
| http_send_data_t send_data; |
| |
| #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) |
| /** Network packet (net_pkt) memory pool for network contexts attached |
| * to this http server context. |
| */ |
| net_pkt_get_slab_func_t tx_slab; |
| |
| /** Network data net_buf pool for network contexts attached to this |
| * http server context. |
| */ |
| net_pkt_get_pool_func_t data_pool; |
| #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ |
| |
| #if defined(CONFIG_NET_DEBUG_HTTP_CONN) |
| sys_snode_t node; |
| #endif |
| |
| /** Network timeout */ |
| s32_t timeout; |
| |
| /** Running status of the server. If true, then the server is enabled. |
| * If false then it is disabled and will not serve clients. |
| * The server is disabled by default after initialization and will need |
| * to be enabled manually. |
| */ |
| bool enabled; |
| |
| /** Is this instance HTTPS or not. |
| */ |
| bool is_https; |
| |
| struct { |
| /** From which net_context the request came from */ |
| struct net_context *net_ctx; |
| |
| /** HTTP request timer. After sending a response to the |
| * client, it is possible to wait for any request back via |
| * the same socket. If no response is received, then this |
| * timeout is activated and connection is tore down. |
| */ |
| struct k_delayed_work timer; |
| |
| /** HTTP parser */ |
| struct http_parser parser; |
| |
| /** HTTP parser settings */ |
| struct http_parser_settings settings; |
| |
| /** Collection of header fields */ |
| struct http_field_value |
| field_values[CONFIG_HTTP_HEADER_FIELD_ITEMS]; |
| |
| /** HTTP Request URL */ |
| const char *url; |
| |
| /** Where the request is stored, this is to be provided |
| * by the user. |
| */ |
| u8_t *request_buf; |
| |
| /** Request buffer maximum length */ |
| size_t request_buf_len; |
| |
| /** Length of the data in the request buf. */ |
| size_t data_len; |
| |
| /** Number of header field elements */ |
| u16_t field_values_ctr; |
| |
| /** URL's length */ |
| u16_t url_len; |
| } req; |
| |
| #if defined(CONFIG_HTTPS) |
| struct { |
| /** HTTPS stack for mbedtls library. */ |
| k_thread_stack_t *stack; |
| |
| /** HTTPS stack size. */ |
| int stack_size; |
| |
| /** HTTPS thread id */ |
| k_tid_t tid; |
| |
| /** HTTPS thread */ |
| struct k_thread thread; |
| |
| /** Memory pool for RX data */ |
| struct k_mem_pool *pool; |
| |
| /** mbedtls related configuration. */ |
| struct { |
| struct https_context ssl_ctx; |
| https_server_cert_cb_t cert_cb; |
| https_entropy_src_cb_t entropy_src_cb; |
| mbedtls_entropy_context entropy; |
| mbedtls_ctr_drbg_context ctr_drbg; |
| mbedtls_ssl_context ssl; |
| mbedtls_ssl_config conf; |
| mbedtls_x509_crt srvcert; |
| mbedtls_pk_context pkey; |
| u8_t *personalization_data; |
| size_t personalization_data_len; |
| } mbedtls; |
| } https; |
| #endif /* CONFIG_HTTPS */ |
| }; |
| |
| #if defined(CONFIG_NET_DEBUG_HTTP_CONN) |
| typedef void (*http_server_cb_t)(struct http_server_ctx *entry, |
| void *user_data); |
| |
| void http_server_conn_foreach(http_server_cb_t cb, void *user_data); |
| void http_server_conn_monitor(http_server_cb_t cb, void *user_data); |
| #else |
| #define http_server_conn_foreach(...) |
| #define http_server_conn_monitor(...) |
| #endif /* CONFIG_NET_DEBUG_HTTP_CONN */ |
| |
| /** |
| * @brief Initialize user-supplied HTTP context. |
| * |
| * @detail Caller can set the various callback fields in http_ctx and |
| * http_ctx.req.parser after this call if needed. |
| * |
| * @param http_ctx HTTP context. |
| * @param urls Array of URLs that the server instance will serve. If the |
| * server receives a HTTP request into one of the URLs, it will call user |
| * supplied callback. If no such URL is registered, a default handler will |
| * be called (if set by the user). If no data handler is found, the request |
| * is dropped. |
| * @param server_addr Socket address of the local network interface and TCP |
| * port where the data is being waited. If the socket family is set to |
| * AF_UNSPEC, then both IPv4 and IPv6 is started to be listened. If the |
| * address is set to be INADDR_ANY (for IPv4) or unspecified address (all bits |
| * zeros for IPv6), then the HTTP server will select proper IP address to bind |
| * to. If caller has not specified HTTP listening port, then port 80 is being |
| * listened. The parameter can be left NULL in which case a listener to port 80 |
| * using IPv4 and IPv6 is created. Note that if IPv4 or IPv6 is disabled, then |
| * the corresponding disabled service listener is not created. |
| * @param request_buf Caller-supplied buffer where the HTTP request will be |
| * stored |
| * @param request_buf_len Length of the caller-supplied buffer. |
| * @param server_banner Print information about started service. This is only |
| * printed if HTTP debugging is activated. The parameter can be set to NULL if |
| * no extra prints are needed. |
| * |
| * @return Return 0 if ok, <0 if error. |
| */ |
| int http_server_init(struct http_server_ctx *http_ctx, |
| struct http_server_urls *urls, |
| struct sockaddr *server_addr, |
| u8_t *request_buf, |
| size_t request_buf_len, |
| const char *server_banner); |
| |
| #if defined(CONFIG_HTTPS) |
| /** |
| * @brief Initialize user-supplied HTTP context. This function must be |
| * used if HTTPS server is created. |
| * |
| * @detail Caller can set the various callback fields in http_ctx and |
| * http_ctx.req.parser after this call if needed. |
| * |
| * @param http_ctx HTTP context. |
| * @param urls Array of URLs that the server instance will serve. If the |
| * server receives a HTTP request into one of the URLs, it will call user |
| * supplied callback. If no such URL is registered, a default handler will |
| * be called (if set by the user). If no data handler is found, the request |
| * is dropped. |
| * @param server_addr Socket address of the local network interface and TCP |
| * port where the data is being waited. If the socket family is set to |
| * AF_UNSPEC, then both IPv4 and IPv6 is started to be listened. If the |
| * address is set to be INADDR_ANY (for IPv4) or unspecified address (all bits |
| * zeros for IPv6), then the HTTP server will select proper IP address to bind |
| * to. If caller has not specified HTTP listening port, then port 80 is being |
| * listened. The parameter can be left NULL in which case a listener to port 80 |
| * using IPv4 and IPv6 is created. Note that if IPv4 or IPv6 is disabled, then |
| * the corresponding disabled service listener is not created. |
| * @param request_buf Caller-supplied buffer where the HTTP request will be |
| * stored |
| * @param request_buf_len Length of the caller-supplied buffer. |
| * @param server_banner Print information about started service. This is only |
| * printed if HTTP debugging is activated. The parameter can be set to NULL if |
| * no extra prints are needed. |
| * @param personalization_data Personalization data (Device specific |
| * identifiers) for random number generator. (Can be NULL). |
| * @param personalization_data_len Length of the personalization data. |
| * @param cert_cb User-supplied callback that setups the certificates. |
| * @param entropy_src_cb User-supplied callback that setup the entropy. This |
| * can be set to NULL, in which case default entropy source is used. |
| * @param pool Memory pool for RX data reads. |
| * @param https_stack HTTPS thread stack. |
| * @param https_stack_len HTTP thread stack size. |
| * |
| * @return Return 0 if ok, <0 if error. |
| */ |
| int https_server_init(struct http_server_ctx *http_ctx, |
| struct http_server_urls *urls, |
| struct sockaddr *server_addr, |
| u8_t *request_buf, |
| size_t request_buf_len, |
| const char *server_banner, |
| u8_t *personalization_data, |
| size_t personalization_data_len, |
| https_server_cert_cb_t cert_cb, |
| https_entropy_src_cb_t entropy_src_cb, |
| struct k_mem_pool *pool, |
| k_thread_stack_t *https_stack, |
| size_t https_stack_len); |
| #endif /* CONFIG_HTTPS */ |
| |
| /** |
| * @brief Release all the resources allocated for HTTP context. |
| * |
| * @param http_ctx HTTP context. |
| */ |
| void http_server_release(struct http_server_ctx *http_ctx); |
| |
| /** |
| * @brief Enable HTTP server that is related to this context. |
| * |
| * @detail The HTTP server will start to serve request after this. |
| * |
| * @param http_ctx HTTP context. |
| * |
| * @return Previous status of the server. |
| */ |
| bool http_server_enable(struct http_server_ctx *http_ctx); |
| |
| /** |
| * @brief Disable HTTP server that is related to this context. |
| * |
| * @detail The HTTP server will stop to serve request after this. |
| * |
| * @param http_ctx HTTP context. |
| * |
| * @return Previous status of the server. |
| */ |
| bool http_server_disable(struct http_server_ctx *http_ctx); |
| |
| /** |
| * @brief Helper function that can be used to fill the server (local) sockaddr |
| * struct. |
| * |
| * @param addr Sockaddr struct to be filled. |
| * @param myaddr Address that the local IP address. If left NULL, then the |
| * proper system address is used. |
| * @param port TCP port to use. |
| * |
| * @return 0 if ok, <0 if error. |
| */ |
| int http_server_set_local_addr(struct sockaddr *addr, const char *myaddr, |
| u16_t port); |
| |
| /** |
| * @brief Add a handler for a given URL. |
| * |
| * @detail Register a handler which is called if the server receives a |
| * request to a given URL. |
| * |
| * @param urls URL struct that will contain all the URLs the user wants to |
| * register. |
| * @param url URL string. |
| * @param flags Flags for the URL. |
| * @param write_cb Callback that is called when URL is requested. |
| * |
| * @return NULL if the URL is already registered, pointer to URL if |
| * registering was ok. |
| */ |
| struct http_root_url *http_server_add_url(struct http_server_urls *urls, |
| const char *url, u8_t flags, |
| http_url_cb_t write_cb); |
| |
| /** |
| * @brief Delete the handler for a given URL. |
| * |
| * @detail Unregister the previously registered URL handler. |
| * |
| * @param urls URL struct that will contain all the URLs the user has |
| * registered. |
| * @param url URL string. |
| * |
| * @return 0 if ok, <0 if error. |
| */ |
| int http_server_del_url(struct http_server_urls *urls, const char *url); |
| |
| /** |
| * @brief Add default URL handler. |
| * |
| * @detail If no URL handler is found, then call this handler. There can |
| * be only one default handler in the URL struct. |
| * |
| * @param urls URL struct that will contain all the URLs the user has |
| * registered. |
| * @param write_cb Callback that is called when non-registered URL is |
| * requested. |
| * |
| * @return NULL if default URL is already registered, pointer to default |
| * URL if registering was ok. |
| */ |
| struct http_root_url *http_server_add_default(struct http_server_urls *urls, |
| http_url_cb_t write_cb); |
| |
| /** |
| * @brief Delete the default URL handler. |
| * |
| * @detail Unregister the previously registered default URL handler. |
| * |
| * @param urls URL struct that will contain all the URLs the user has |
| * registered. |
| * |
| * @return 0 if ok, <0 if error. |
| */ |
| int http_server_del_default(struct http_server_urls *urls); |
| |
| /** |
| * @brief Send HTTP response to client. |
| * |
| * @detail After sending a response, an optional timeout is started |
| * which will wait for any new requests from the peer. |
| * |
| * @param ctx HTTP context. |
| * @param http_header HTTP headers to send. |
| * @param html_payload HTML payload to send. |
| * @param timeout Timeout to wait until the connection is shutdown. |
| * |
| * @return 0 if ok, <0 if error. |
| */ |
| int http_response_wait(struct http_server_ctx *ctx, const char *http_header, |
| const char *html_payload, s32_t timeout); |
| |
| /** |
| * @brief Send HTTP response to client. |
| * |
| * @detail The connection to peer is torn down right after the response |
| * is sent. |
| * |
| * @param ctx HTTP context. |
| * @param http_header HTTP headers to send. |
| * @param html_payload HTML payload to send. |
| * |
| * @return 0 if ok, <0 if error. |
| */ |
| int http_response(struct http_server_ctx *ctx, const char *http_header, |
| const char *html_payload); |
| |
| /** |
| * @brief Send HTTP 400 response to client. |
| * |
| * @detail HTTP 400 error code indicates a Bad Request |
| * |
| * @param ctx HTTP context. |
| * @param html_payload HTML payload to send. |
| * |
| * @return 0 if ok, <0 if error. |
| */ |
| int http_response_400(struct http_server_ctx *ctx, const char *html_payload); |
| |
| /** |
| * @brief Send HTTP 403 response to client. |
| * |
| * @detail HTTP 403 error code indicates a Forbidden Request |
| * |
| * @param ctx HTTP context. |
| * @param html_payload HTML payload to send. |
| * |
| * @return 0 if ok, <0 if error. |
| */ |
| int http_response_403(struct http_server_ctx *ctx, const char *html_payload); |
| |
| /** |
| * @brief Send HTTP 404 response to client. |
| * |
| * @detail HTTP 404 error code indicates a Not Found resource. |
| * |
| * @param ctx HTTP context. |
| * @param html_payload HTML payload to send. |
| * |
| * @return 0 if ok, <0 if error. |
| */ |
| int http_response_404(struct http_server_ctx *ctx, const char *html_payload); |
| |
| /** |
| * @brief Send some data to the client. |
| * |
| * @detail Send a piece of data to the client. If html_payload is NULL, then |
| * we close the connection. |
| * |
| * @param ctx HTTP context. |
| * @param http_header HTTP header to be sent. Can be NULL. |
| * @param html_payload HTML payload to send. |
| * @param timeout Timeout to wait until the connection is teared down. |
| * |
| * @return 0 if ok, <0 if error. |
| */ |
| int http_response_send_data(struct http_server_ctx *ctx, |
| const char *http_header, |
| const char *html_payload, |
| s32_t timeout); |
| |
| #if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) |
| /** |
| * @brief Configure the net_pkt pool for this context. |
| * |
| * @details Use of this function is optional and if the pools are not set, |
| * then the default TX and DATA pools are used. This needs to be called before |
| * http init function, as that will setup net_context which needs the net_pkt |
| * pool information. |
| * |
| * @param ctx HTTP server context |
| * @param tx_slab Function which is used when allocating TX network packet. |
| * This can be NULL in which case default TX memory pool is used. |
| * @param data_pool Function which is used when allocating data network buffer. |
| * This can be NULL in which case default DATA net_buf pool is used. |
| */ |
| int http_server_set_net_pkt_pool(struct http_server_ctx *ctx, |
| net_pkt_get_slab_func_t tx_slab, |
| net_pkt_get_pool_func_t data_pool); |
| #else |
| #define http_server_set_net_pkt_pool(...) |
| #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ |
| |
| #endif /* CONFIG_HTTP_SERVER */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| /** |
| * @} |
| */ |
| |
| #endif /* __HTTP_H__ */ |