diff --git a/doc/api/networking.rst b/doc/api/networking.rst index bbef76c3846..1611c5a239e 100644 --- a/doc/api/networking.rst +++ b/doc/api/networking.rst @@ -210,12 +210,6 @@ DNS Resolve .. doxygengroup:: dns_resolve :project: Zephyr -HTTP -==== - -.. doxygengroup:: http - :project: Zephyr - TLS credentials *************** diff --git a/doc/subsystems/networking/overview.rst b/doc/subsystems/networking/overview.rst index f970528a8b0..18016a2e85d 100644 --- a/doc/subsystems/networking/overview.rst +++ b/doc/subsystems/networking/overview.rst @@ -55,14 +55,6 @@ can be disabled if not needed. configuration options for sockets API. Secure functions for the implementation are provided by mbedTLS library. -* **HTTP** Hypertext Transfer Protocol (RFC 2116) is supported. A simple - library is provided that applications can use. Sample applications are - implemented for :ref:`http-client-sample` and :ref:`http-server-sample`. - Both :ref:`http-client-sample` and :ref:`http-server-sample` can use - TLS (Transport Layer Security) v1.2 (RFC 5246) or SSL (Secure Sockets - Layer) v3.0 (RFC 6101) functionality to encrypt the network traffic. - The secured connections are provided by mbed library. - * **MQTT** Message Queue Telemetry Transport (ISO/IEC PRF 20922) is supported. A sample :ref:`mqtt-publisher-sample` client application for MQTT v3.1.1 is implemented. diff --git a/include/net/http.h b/include/net/http.h deleted file mode 100644 index c696342342e..00000000000 --- a/include/net/http.h +++ /dev/null @@ -1,1125 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * - * @brief HTTP server and client implementation for Zephyr. - */ - -#ifndef ZEPHYR_INCLUDE_NET_HTTP_H_ -#define ZEPHYR_INCLUDE_NET_HTTP_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(ZEPHYR_USER_AGENT) -#define ZEPHYR_USER_AGENT "Zephyr" -#endif - -#if !defined(CONFIG_HTTP_SERVER_NUM_URLS) -#define CONFIG_HTTP_SERVER_NUM_URLS 1 -#endif - -#if !defined(CONFIG_HTTP_HEADERS) -#define CONFIG_HTTP_HEADERS 1 -#endif - -#if !defined(HTTP_PROTOCOL) -#define HTTP_PROTOCOL "HTTP/1.1" -#endif - -/** - * @brief HTTP client and server library - * @defgroup http HTTP Library - * @ingroup networking - * @{ - */ - -#define HTTP_CRLF "\r\n" - -struct http_ctx; - -enum http_state { - HTTP_STATE_CLOSED, - HTTP_STATE_WAITING_HEADER, - HTTP_STATE_RECEIVING_HEADER, - HTTP_STATE_HEADER_RECEIVED, - HTTP_STATE_OPEN, -} __packed; - -enum http_url_flags { - HTTP_URL_STANDARD = 0, - HTTP_URL_WEBSOCKET, -} __packed; - -enum http_connection_type { - HTTP_CONNECTION = 1, - WS_CONNECTION, -}; - -/* 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; -}; - -/* HTTP root URL struct, used for pattern matching */ -struct http_root_url { - /** URL */ - const char *root; - - /** URL specific user data */ - u8_t *user_data; - - /** 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; -}; - -enum http_verdict { - HTTP_VERDICT_DROP, - HTTP_VERDICT_ACCEPT, -}; - -/** - * @typedef http_url_cb_t - * @brief Default URL callback. - * - * @details This callback is called if there is a connection to unknown URL. - * - * @param ctx The context to use. - * @param type Connection type (websocket or HTTP) - * @param dst Remote socket address - * - * @return HTTP_VERDICT_DROP if connection is to be dropped, - * HTTP_VERDICT_ACCEPT if the application wants to accept the unknown URL. - */ -typedef enum http_verdict (*http_url_cb_t)(struct http_ctx *ctx, - enum http_connection_type type, - const struct sockaddr *dst); - -/* 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; - - /** Callback that is called when unknown (default) URL is received */ - http_url_cb_t default_cb; - - struct http_root_url urls[CONFIG_HTTP_SERVER_NUM_URLS]; -}; - -/** - * @typedef http_recv_cb_t - * @brief Network data receive callback. - * - * @details The recv callback is called after a network data is - * received. - * - * @param ctx The context to use. - * @param pkt Network buffer that is received. If the pkt is not NULL, - * then the callback will own the buffer and it needs to to unref the pkt - * as soon as it has finished working with it. On EOF, pkt will be NULL. - * @param status Value is set to 0 if some data or the connection is - * at EOF, <0 if there was an error receiving data, in this case the - * pkt parameter is set to NULL. - * @param flags Flags related to http. For example contains information - * if the data is text or binary etc. - * @param dst Remote socket address from where HTTP packet is received. - * @param user_data The user data given in init call. - */ -typedef void (*http_recv_cb_t)(struct http_ctx *ctx, - struct net_pkt *pkt, - int status, - u32_t flags, - const struct sockaddr *dst, - void *user_data); - -/** - * @typedef http_connect_cb_t - * @brief Connection callback. - * - * @details The connect callback is called after there was a connection to - * non-default URL. - * - * @param ctx The context to use. - * @param type Connection type (websocket or HTTP) - * @param dst Remote socket address where the connection is established. - * @param user_data The user data given in init call. - */ -typedef void (*http_connect_cb_t)(struct http_ctx *ctx, - enum http_connection_type type, - const struct sockaddr *dst, - void *user_data); - -/** - * @typedef http_send_cb_t - * @brief Network data send callback. - * - * @details The send callback is called after a network data is - * sent. - * - * @param ctx The context to use. - * @param status Value is set to 0 if all data was sent ok, <0 if - * there was an error sending data. >0 amount of data that was - * sent when not all data was sent ok. - * @param user_data_send The user data given in http_send() call. - * @param user_data The user data given in init call. - */ -typedef void (*http_send_cb_t)(struct http_ctx *ctx, - int status, - void *user_data_send, - void *user_data); - -/** - * @typedef http_close_cb_t - * @brief Close callback. - * - * @details The close callback is called after a connection was shutdown. - * - * @param ctx The context to use. - * @param status Error code for the closing. - * @param user_data The user data given in init call. - */ -typedef void (*http_close_cb_t)(struct http_ctx *ctx, - int status, - void *user_data); - -/** Websocket and HTTP callbacks */ -struct http_cb { - /** Function that is called when a connection is established. - */ - http_connect_cb_t connect; - - /** Function that is called when data is received from network. - */ - http_recv_cb_t recv; - - /** Function that is called when net_pkt is sent. - */ - http_send_cb_t send; - - /** Function that is called when connection is shutdown. - */ - http_close_cb_t close; -}; - -#if defined(CONFIG_HTTP_CLIENT) -/* Is there more data to come */ -enum http_final_call { - HTTP_DATA_MORE = 0, - HTTP_DATA_FINAL = 1, -}; - -/* Some generic configuration options, these can be overridden if needed. */ -#if !defined(HTTP_STATUS_STR_SIZE) -#define HTTP_STATUS_STR_SIZE 32 -#endif - -/** - * @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_ctx *ctx, - u8_t *data, - size_t buflen, - size_t datalen, - enum http_final_call final_data, - void *user_data); - -/** - * HTTP client request. This contains all the data that is needed when doing - * a HTTP request. - */ -struct http_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; -}; -#endif /* CONFIG_HTTP_CLIENT */ - -/** - * Http context information. This contains all the data that is - * needed when working with http API. - */ -struct http_ctx { - /** Net app context. The http connection is handled via - * the net app API. - */ - struct net_app_ctx app_ctx; - - /** Local endpoint IP address */ - struct sockaddr local; - - /** Original server address */ - struct sockaddr *server_addr; - - /** Pending data to be sent */ - struct net_pkt *pending; - -#if defined(CONFIG_HTTP_CLIENT) - /** Server name */ - const char *server; -#endif /* CONFIG_HTTP_CLIENT */ - - struct { -#if defined(CONFIG_HTTP_CLIENT) - /** Semaphore to signal HTTP connection creation. */ - struct k_sem connect_wait; - - /** 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 body starts. - */ - u8_t *body_start; - - /** Where the response is stored, this is to be - * provided by the user. - */ - u8_t *response_buf; - - /** 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; -#endif /* CONFIG_HTTP_CLIENT */ - - /** HTTP parser for parsing the initial request */ - struct http_parser parser; - - /** HTTP parser settings */ - struct http_parser_settings parser_settings; - -#if defined(CONFIG_HTTP_SERVER) - /** Collection of HTTP header fields */ - struct http_field_value field_values[CONFIG_HTTP_HEADERS]; - - /** Collection of HTTP URLs that this context will handle. */ - struct http_server_urls *urls; - - /** Where the request is stored, this needs 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; -#endif /* CONFIG_HTTP_SERVER */ - - /** HTTP Request URL */ - const char *url; - - /** URL's length */ - u16_t url_len; - } http; - -#if defined(CONFIG_WEBSOCKET) - struct { - /** Pending data that is not yet ready for processing */ - struct net_pkt *pending; - - /** Amount of data that needs to be read still */ - u32_t data_waiting; - - /** Websocket connection masking value */ - u32_t masking_value; - - /** How many bytes we have read */ - u32_t data_read; - - /** Message type flag. Value is one of WS_FLAG_XXX flag values - * defined in weboscket.h - */ - u32_t msg_type_flag; - } websocket; -#endif /* CONFIG_WEBSOCKET */ - -#if defined(CONFIG_NET_DEBUG_HTTP_CONN) - sys_snode_t node; -#endif /* CONFIG_HTTP_DEBUG_HTTP_CONN */ - - /** HTTP callbacks */ - struct http_cb cb; - - /** User specified data that is passed in callbacks. */ - u8_t *user_data; - - /** State of the websocket */ - enum http_state state; - - /** Network buffer allocation timeout */ - s32_t timeout; - - /** Is this context setup or not */ - u8_t is_init : 1; - - /** Is this context setup for client or server */ - u8_t is_client : 1; - - /** Is this instance supporting TLS or not. */ - u8_t is_tls : 1; - - /** Are we connected or not (only used in client) */ - u8_t is_connected : 1; -}; - -#if defined(CONFIG_HTTP_SERVER) -/** - * @brief Create a HTTP listener. - * - * @details Note that the context must be valid for the whole duration of the - * http life cycle. This usually means that it cannot be allocated from - * stack. - * - * @param ctx Http context. This init function will initialize it. - * @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 user_data User specific data that is passed as is to the connection - * callbacks. - * - * @return 0 if ok, <0 if error. - */ -int http_server_init(struct http_ctx *ctx, - struct http_server_urls *urls, - struct sockaddr *server_addr, - u8_t *request_buf, - size_t request_buf_len, - const char *server_banner, - void *user_data); - -#if defined(CONFIG_HTTPS) -/** - * @brief Initialize TLS support for this http context - * - * @param ctx Http context - * @param server_banner Print information about started service. This is only - * printed if net_app 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 stack TLS thread stack. - * @param stack_len TLS thread stack size. - * - * @return Return 0 if ok, <0 if error. - */ -int http_server_set_tls(struct http_ctx *ctx, - const char *server_banner, - u8_t *personalization_data, - size_t personalization_data_len, - net_app_cert_cb_t cert_cb, - net_app_entropy_src_cb_t entropy_src_cb, - struct k_mem_pool *pool, - k_thread_stack_t *stack, - size_t stack_len); - -#endif /* CONFIG_HTTPS */ - -/** - * @brief Enable HTTP server that is related to this context. - * - * @detail The HTTP server will start to serve request after this. - * - * @param ctx Http context. - * - * @return 0 if server is enabled, <0 otherwise - */ -int http_server_enable(struct http_ctx *ctx); - -/** - * @brief Disable HTTP server that is related to this context. - * - * @detail The HTTP server will stop to serve request after this. - * - * @param ctx Http context. - * - * @return 0 if server is disabled, <0 if there was an error - */ -int http_server_disable(struct http_ctx *ctx); - -/** - * @brief Add an URL to a list of URLs that are tied to certain webcontext. - * - * @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. - * - * @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); - -/** - * @brief Delete the URL from list of URLs that are tied to certain - * webcontext. - * - * @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. The callback can decide - * if the connection request is dropped or passed. - * - * @param urls URL struct that will contain all the URLs the user has - * registered. - * @param 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 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); - -#else /* CONFIG_HTTP_SERVER */ - -static inline int http_server_init(struct http_ctx *ctx, - struct http_server_urls *urls, - struct sockaddr *server_addr, - u8_t *request_buf, - size_t request_buf_len, - const char *server_banner) -{ - ARG_UNUSED(ctx); - ARG_UNUSED(urls); - ARG_UNUSED(server_addr); - ARG_UNUSED(request_buf); - ARG_UNUSED(request_buf_len); - ARG_UNUSED(server_banner); - - return -ENOTSUP; -} - -#if defined(CONFIG_HTTPS) && defined(CONFIG_NET_APP_SERVER) -static inline int http_server_set_tls(struct http_ctx *ctx, - const char *server_banner, - u8_t *personalization_data, - size_t personalization_data_len, - net_app_cert_cb_t cert_cb, - net_app_entropy_src_cb_t entropy_src_cb, - struct k_mem_pool *pool, - k_thread_stack_t *stack, - size_t stack_len) -{ - ARG_UNUSED(ctx); - ARG_UNUSED(server_banner); - ARG_UNUSED(personalization_data); - ARG_UNUSED(personalization_data_len); - ARG_UNUSED(cert_cb); - ARG_UNUSED(entropy_src_cb); - ARG_UNUSED(pool); - ARG_UNUSED(stack); - ARG_UNUSED(stack_len); - - return -ENOTSUP; -} -#endif /* CONFIG_HTTPS && CONFIG_NET_APP_SERVER */ - -static inline int http_server_enable(struct http_ctx *ctx) -{ - ARG_UNUSED(ctx); - return -ENOTSUP; -} - -static inline int http_server_disable(struct http_ctx *ctx) -{ - ARG_UNUSED(ctx); - return -ENOTSUP; -} - -static inline -struct http_root_url *http_server_add_url(struct http_server_urls *urls, - const char *url, u8_t flags) -{ - ARG_UNUSED(urls); - ARG_UNUSED(url); - ARG_UNUSED(flags); - - return NULL; -} -#endif /* CONFIG_HTTP_SERVER */ - -#if defined(CONFIG_HTTP_CLIENT) -/** - * @brief Generic function to send a HTTP request to the network. Normally - * applications would not need to use this function. - * - * @param ctx HTTP context. - * @param req HTTP request to perform. - * @param timeout Timeout when doing net_buf allocations. - * @param user_data User data related to this request. This is passed - * to send callback if user has specified that. - * - * @return Return 0 if ok, and <0 if error. - */ -int http_request(struct http_ctx *ctx, - struct http_request *req, - s32_t timeout, - void *user_data); - -/** - * @brief Cancel a pending request. - * - * @param ctx HTTP context. - * - * @return Return 0 if ok, and <0 if error. - */ -int http_request_cancel(struct http_ctx *ctx); - -/** - * @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_ctx *http_ctx, - struct http_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_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_request req = { - .method = HTTP_GET, - .url = url, - .host = host, - .protocol = " " HTTP_PROTOCOL, - .header_fields = extra_header_fields, - }; - - 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 the server_addr parameter must be - * set by the user and it is used when connecting to the server. - * @param server_port HTTP server TCP port. If server parameter is NULL, then - * this value is ignored. - * @param server_addr HTTP server IP address and port. This is only used if - * server parameter is not set. - * @param timeout If server address needs to be resolved, then this value is - * used as a timeout. - * - * @return Return 0 if ok, <0 if error. - */ -int http_client_init(struct http_ctx *http_ctx, - const char *server, - u16_t server_port, - struct sockaddr *server_addr, - s32_t timeout); - -#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 ctx HTTPS context. - * @param request_buf Caller-supplied buffer where the TLS request will be - * stored - * @param request_buf_len Length of the caller-supplied buffer. - * @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 http_client_set_tls(struct http_ctx *ctx, - u8_t *request_buf, - size_t request_buf_len, - u8_t *personalization_data, - size_t personalization_data_len, - net_app_ca_cert_cb_t cert_cb, - const char *cert_host, - net_app_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 */ -#endif /* CONFIG_HTTP_CLIENT */ - -/** - * @brief Close a network connection to peer. - * - * @param ctx Http context. - * - * @return 0 if ok, <0 if error. - */ -int http_close(struct http_ctx *ctx); - -/** - * @brief Release this http context. - * - * @details No network data will be received via this context after this - * call. - * - * @param ctx Http context. - * - * @return 0 if ok, <0 if error. - */ -int http_release(struct http_ctx *ctx); - -/** - * @brief Set various callbacks that are called at various stage of ws session. - * - * @param ctx Http context. - * @param connect_cb Connect callback. - * @param recv_cb Data receive callback. - * @param send_cb Data sent callback. - * @param close_cb Close callback. - * - * @return 0 if ok, <0 if error. - */ -int http_set_cb(struct http_ctx *ctx, - http_connect_cb_t connect_cb, - http_recv_cb_t recv_cb, - http_send_cb_t send_cb, - http_close_cb_t close_cb); - -/** - * @brief Send a message to peer. The data can be either HTTP or websocket - * data. - * - * @details This does not modify the network packet but sends it as is. - * - * @param ctx Http context. - * @param pkt Network packet to send - * @param user_send_data User specific data to this connection. This is passed - * as a parameter to sent cb after the packet has been sent. - * - * @return 0 if ok, <0 if error. - */ -int http_send_msg_raw(struct http_ctx *ctx, struct net_pkt *pkt, - void *user_send_data); - -/** - * @brief Prepare HTTP data to be sent to peer. If there is enough data, the - * function will then send it too. - * - * @param ctx Http context. - * @param payload Application data to send - * @param payload_len Length of application data - * @param dst Remote socket address - * @param user_send_data User specific data to this connection. This is passed - * as a parameter to sent cb after the packet has been sent. - * - * @return 0 if ok, <0 if error. - */ -int http_prepare_and_send(struct http_ctx *ctx, const char *payload, - size_t payload_len, - const struct sockaddr *dst, - void *user_send_data); - -/** - * @brief Send HTTP data chunk to peer. - * - * @param ctx Http context. - * @param payload Application data to send - * @param payload_len Length of application data - * @param dst Remote socket address - * @param user_send_data User specific data to this connection. This is passed - * as a parameter to sent cb after the packet has been sent. - * - * @return 0 if ok, <0 if error. - */ -int http_send_chunk(struct http_ctx *ctx, const char *payload, - size_t payload_len, - const struct sockaddr *dst, - void *user_send_data); - -/** - * @brief Send any pending data immediately. - * - * @param ctx Http context. - * @param user_send_data Optional user_data for that is used as a parameter in - * send callback if that is specified. - * - * @return 0 if ok, <0 if error. - */ -int http_send_flush(struct http_ctx *ctx, void *user_send_data); - -/** - * @brief Send HTTP error message to peer. - * - * @param ctx Http context. - * @param code HTTP error code - * @param html_payload Extra payload, can be null - * @param html_len Payload length - * @param dst Remote socket address - * - * @return 0 if ok, <0 if error. - */ -int http_send_error(struct http_ctx *ctx, int code, - u8_t *html_payload, size_t html_len, - const struct sockaddr *dst); - -/** - * @brief Add HTTP header field to the message. - * - * @details This can be called multiple times to add pieces of HTTP header - * fields into the message. Caller must put the "\\r\\n" characters to the - * input http_header_field variable. - * - * @param ctx Http context. - * @param http_header_field All or part of HTTP header to be added. - * @param dst Remote socket address. - * @param user_send_data User data value that is used in send callback. - * Note that this value is only used if this function call causes a HTTP - * message to be sent. - * - * @return <0 if error, other value tells how many bytes were added - */ -int http_add_header(struct http_ctx *ctx, const char *http_header_field, - const struct sockaddr *dst, - void *user_send_data); - -/** - * @brief Add HTTP header field to the message. - * - * @details This can be called multiple times to add pieces of HTTP header - * fields into the message. If name is "Foo" and value is "bar", then this - * function will add "Foo: bar\\r\\n" to message. - * - * @param ctx Http context. - * @param name Name of the header field - * @param value Value of the header field - * @param dst Remote socket address - * @param user_send_data User data value that is used in send callback. - * Note that this value is only used if this function call causes a HTTP - * message to be sent. - * - * @return <0 if error, other value tells how many bytes were added - */ -int http_add_header_field(struct http_ctx *ctx, const char *name, - const char *value, - const struct sockaddr *dst, - void *user_send_data); - -/** - * @brief Find a handler function for a given URL. - * - * @details This is internal function, do not call this from application. - * - * @param ctx Http context. - * @param flags Tells if the URL is either HTTP or websocket URL - * - * @return URL handler or NULL if no such handler was found. - */ -struct http_root_url *http_url_find(struct http_ctx *ctx, - enum http_url_flags flags); - -#define http_change_state(ctx, new_state) \ - _http_change_state(ctx, new_state, __func__, __LINE__) - -/** - * @brief Change the state of the HTTP engine - * - * @details This is internal function, do not call this from application. - * - * @param ctx HTTP context. - * @param new_state New state of the context. - * @param func Function that changed the state (for debugging) - * @param line Line number of the function (for debugging) - */ -void _http_change_state(struct http_ctx *ctx, - enum http_state new_state, - const char *func, int line); - -#if defined(CONFIG_HTTP_SERVER) && defined(CONFIG_NET_DEBUG_HTTP_CONN) -/** - * @typedef http_server_cb_t - * @brief HTTP connection monitoring callback. - * - * @details This callback is called by server if new HTTP connection is - * established or disconnected. Requires that HTTP connection monitoring - * is enabled. - * - * @param ctx The HTTP context to use. - * @param user_data User specified data. - */ -typedef void (*http_server_cb_t)(struct http_ctx *entry, - void *user_data); - -/** - * @brief Go through all the HTTP connections in the server and call - * user provided callback for each connection. - * - * @param cb Callback to call for each HTTP connection. - * @param user_data User provided data that is passed to callback. - */ -void http_server_conn_foreach(http_server_cb_t cb, void *user_data); - -/** - * @brief Register a callback that is called if HTTP connection is - * established or disconnected. - * - * @details This is normally called only by "net http monitor" shell command. - * - * @param cb Callback to call for each HTTP connection created or - * deleted. - * @param user_data User provided data that is passed to callback. - */ -void http_server_conn_monitor(http_server_cb_t cb, void *user_data); - -/** - * @brief HTTP connection was established. - * - * @details This is internal function, do not call this from application. - * - * @param ctx HTTP context. - */ -void http_server_conn_add(struct http_ctx *ctx); - -/** - * @brief HTTP connection was disconnected. - * - * @details This is internal function, do not call this from application. - * - * @param ctx HTTP context. - */ -void http_server_conn_del(struct http_ctx *ctx); -#else -#define http_server_conn_foreach(...) -#define http_server_conn_monitor(...) -#define http_server_conn_add(...) -#define http_server_conn_del(...) -#endif /* CONFIG_HTTP_SERVER && CONFIG_NET_DEBUG_HTTP_CONN */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_INCLUDE_NET_HTTP_H_ */ diff --git a/samples/net/http_client/CMakeLists.txt b/samples/net/http_client/CMakeLists.txt deleted file mode 100644 index cae183d98ba..00000000000 --- a/samples/net/http_client/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -cmake_minimum_required(VERSION 3.13.1) -include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) -project(http_client) - -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) - -include($ENV{ZEPHYR_BASE}/samples/net/common/common.cmake) - -generate_inc_file_for_target( - app - src/echo-apps-cert.der - ${ZEPHYR_BINARY_DIR}/include/generated/echo-apps-cert.der.inc - ) diff --git a/samples/net/http_client/README.rst b/samples/net/http_client/README.rst deleted file mode 100644 index a3b1fb157af..00000000000 --- a/samples/net/http_client/README.rst +++ /dev/null @@ -1,148 +0,0 @@ -.. _http-client-sample: - -HTTP Client -########### - -Overview -******** - -This sample application shows how to create HTTP 1.1 requests to -an HTTP server and how to parse the incoming responses. -Supported HTTP 1.1 methods are: GET, HEAD and POST. - -The source code for this sample application can be found at: -:file:`samples/net/http_client`. - -Requirements -************ - -- :ref:`networking_with_qemu` -- Terminal emulator software -- HTTP Server -- DNS server (optional) - - -Building and Running -******************** - -Open the project configuration file for your platform, for example: -:file:`prj_qemu_x86.conf` is the configuration file for QEMU. - -To use QEMU for testing, follow the :ref:`networking_with_qemu` guide. - -For IPv4 networks, set the following variables: - -.. code-block:: console - - CONFIG_NET_IPV4=y - CONFIG_NET_IPV6=n - -IPv6 is the preferred routing technology for this sample application, -if CONFIG_NET_IPV6=y is set, the value of CONFIG_NET_IPV4=y is ignored. - -In this sample application, both static IP addresses and DHCPv4 are supported. -Static IP addresses are specified in the project configuration file, -for example: - -.. code-block:: console - - CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" - CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" - -are the IPv6 addresses for the HTTP client running Zephyr and the -HTTP server, respectively. The application also supports DNS resolving so the -peer address is resolved automatically if host name is given, so you -can also write the HTTP server name like this: - -.. code-block:: console - - CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" - CONFIG_NET_CONFIG_PEER_IPV6_ADDR="6.zephyr.test" - -Open the :file:`src/config.h` file and set the server port -to match the HTTP server setup, for example: - -.. code-block:: c - - #define SERVER_PORT 8000 - -assumes that the HTTP server is listening at the TCP port 8000. - -HTTP Server -=========== - -Sample code for a very simple HTTP server can be downloaded from the -zephyrproject-rtos/net-tools project area: -https://github.com/zephyrproject-rtos/net-tools - -Open a terminal window and type: - -.. code-block:: console - - $ cd net-tools - $ ./http-server.sh - - -DNS setup -========= - -The net-tools project provides a simple DNS resolver. You can activate -it like this if you want to test the DNS resolving with HTTP client. - -Open a terminal window and type: - -.. code-block:: console - - $ cd net-tools - $ ./dnsmasq.sh - - -Sample Output -============= - -This sample application loops a specified number of times doing several -HTTP 1.1 requests and printing some output. The requests are: - -- GET "/index.html" -- HEAD "/" -- POST "/post_test.php" -- GET "/big-file.html" - -The terminal window where QEMU is running will show something similar -to the following: - -.. code-block:: console - - [http-client] [INF] do_sync_http_req: [19] Send /index.html - [http-client] [INF] do_sync_http_req: HTTP server response status: OK - [http-client] [INF] do_sync_http_req: HTTP body: 170 bytes, expected: 170 bytes - [http-client] [INF] do_sync_http_req: [19] Send / - [http-client] [INF] do_sync_http_req: HTTP server response status: OK - [http-client] [INF] do_sync_http_req: [19] Send /post_test.php - [http-client] [INF] do_sync_http_req: HTTP server response status: OK - [http-client] [INF] do_sync_http_req: HTTP body: 24 bytes, expected: 24 bytes - [http-client] [INF] do_sync_http_req: [20] Send /index.html - [http-client] [INF] do_sync_http_req: HTTP server response status: OK - [http-client] [INF] do_sync_http_req: HTTP body: 170 bytes, expected: 170 bytes - [http-client] [INF] do_sync_http_req: [20] Send / - [http-client] [INF] do_sync_http_req: HTTP server response status: OK - [http-client] [INF] do_sync_http_req: [20] Send /post_test.php - [http-client] [INF] do_sync_http_req: HTTP server response status: OK - [http-client] [INF] do_sync_http_req: HTTP body: 24 bytes, expected: 24 bytes - [http-client] [INF] main: --------Sending 20 async request-------- - [http-client] [INF] do_async_http_req: [1] Send /index.html - [http-client] [INF] response: Received 356 bytes piece of data - [http-client] [INF] response: HTTP server response status: OK - [http-client] [INF] response: HTTP body: 170 bytes, expected: 170 bytes - [http-client] [INF] do_async_http_req: [1] Send / - [http-client] [INF] response: HTTP server response status: OK - [http-client] [INF] do_async_http_req: [1] Send /post_test.php - [http-client] [INF] response: Received 163 bytes piece of data - [http-client] [INF] response: HTTP server response status: OK - [http-client] [INF] response: HTTP body: 24 bytes, expected: 24 bytes - [http-client] [INF] do_async_http_req: [1] Send /big-file.html - [http-client] [INF] response: Received 657 bytes piece of data - [http-client] [INF] response: Received 640 bytes piece of data - [http-client] [INF] response: Received 418 bytes piece of data - [http-client] [INF] response: HTTP server response status: OK - [http-client] [INF] response: HTTP body: 1528 bytes, expected: 1528 bytes diff --git a/samples/net/http_client/prj.conf b/samples/net/http_client/prj.conf deleted file mode 100644 index 5946d6a96cd..00000000000 --- a/samples/net/http_client/prj.conf +++ /dev/null @@ -1,44 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_NET_TCP=y -CONFIG_ENTROPY_GENERATOR=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_LOG=y -CONFIG_LOG=y -CONFIG_INIT_STACKS=y - -CONFIG_NET_PKT_RX_COUNT=32 -CONFIG_NET_PKT_TX_COUNT=32 -CONFIG_NET_BUF_RX_COUNT=32 -CONFIG_NET_BUF_TX_COUNT=32 - -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 - -CONFIG_NET_MAX_CONTEXTS=16 - -CONFIG_HTTP=y -CONFIG_HTTP_CLIENT=y - -CONFIG_NET_IPV6=y -CONFIG_NET_IPV4=y -#CONFIG_NET_DHCPV4=y - -CONFIG_HTTPS=n -CONFIG_MBEDTLS=n - -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" -CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" -CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" - -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_CONFIG_NEED_IPV4=y - -CONFIG_NET_SHELL=y -CONFIG_NET_STATISTICS=y - -CONFIG_NET_MGMT=y -CONFIG_NET_MGMT_EVENT=y - -CONFIG_MAIN_STACK_SIZE=2048 diff --git a/samples/net/http_client/prj_bt.conf b/samples/net/http_client/prj_bt.conf deleted file mode 100644 index bbab6ba3f24..00000000000 --- a/samples/net/http_client/prj_bt.conf +++ /dev/null @@ -1,51 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_NET_TCP=y -CONFIG_ENTROPY_GENERATOR=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_LOG=y -CONFIG_LOG=y -CONFIG_INIT_STACKS=y - -CONFIG_NET_PKT_RX_COUNT=32 -CONFIG_NET_PKT_TX_COUNT=32 -CONFIG_NET_BUF_RX_COUNT=32 -CONFIG_NET_BUF_TX_COUNT=32 - -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 - -CONFIG_NET_MAX_CONTEXTS=16 - -CONFIG_HTTP=y -CONFIG_HTTP_CLIENT=y - -CONFIG_NET_IPV6=y - -CONFIG_HTTPS=n -CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_BUILTIN=y -CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h" -CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2500 -CONFIG_MBEDTLS_ENABLE_HEAP=y -CONFIG_MBEDTLS_HEAP_SIZE=12000 - -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" - -CONFIG_NET_CONFIG_NEED_IPV6=y - -CONFIG_NET_SHELL=y -CONFIG_NET_STATISTICS=y - -CONFIG_NET_MGMT=y -CONFIG_NET_MGMT_EVENT=y - -CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Test Http_Client" -CONFIG_NET_L2_BT=y - diff --git a/samples/net/http_client/prj_tls.conf b/samples/net/http_client/prj_tls.conf deleted file mode 100644 index 96ac0cf61c6..00000000000 --- a/samples/net/http_client/prj_tls.conf +++ /dev/null @@ -1,50 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_NET_TCP=y -CONFIG_ENTROPY_GENERATOR=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_LOG=y -CONFIG_LOG=y -CONFIG_INIT_STACKS=y - -CONFIG_NET_PKT_RX_COUNT=32 -CONFIG_NET_PKT_TX_COUNT=32 -CONFIG_NET_BUF_RX_COUNT=32 -CONFIG_NET_BUF_TX_COUNT=32 - -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 - -CONFIG_NET_MAX_CONTEXTS=16 - -CONFIG_HTTP=y -CONFIG_HTTP_CLIENT=y - -CONFIG_NET_IPV6=y -CONFIG_NET_IPV4=y -#CONFIG_NET_DHCPV4=y - -CONFIG_HTTPS=y -CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_BUILTIN=y -CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h" -CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2500 -CONFIG_MBEDTLS_ENABLE_HEAP=y -CONFIG_MBEDTLS_HEAP_SIZE=30000 - -CONFIG_NET_APP_TLS=y -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" -CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" -CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" - -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_CONFIG_NEED_IPV4=y - -CONFIG_NET_SHELL=y -CONFIG_NET_STATISTICS=y - -CONFIG_NET_MGMT=y -CONFIG_NET_MGMT_EVENT=y - -CONFIG_MAIN_STACK_SIZE=1504 diff --git a/samples/net/http_client/sample.yaml b/samples/net/http_client/sample.yaml deleted file mode 100644 index 6bedb8a42f8..00000000000 --- a/samples/net/http_client/sample.yaml +++ /dev/null @@ -1,15 +0,0 @@ -common: - harness: net - tags: net http -sample: - name: HTTP Client -tests: - test: - depends_on: netif - min_flash: 140 - test_bt: - extra_args: CONF_FILE="prj_bt.conf" - platform_whitelist: qemu_x86 qemu_cortex_m3 - test_tls: - extra_args: CONF_FILE="prj_tls.conf" - platform_whitelist: qemu_x86 qemu_cortex_m3 diff --git a/samples/net/http_client/src/config.h b/samples/net/http_client/src/config.h deleted file mode 100644 index 051e713bafa..00000000000 --- a/samples/net/http_client/src/config.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define APP_REQ_TIMEOUT K_SECONDS(10) - -/* The startup time needs to be longish if DHCP is enabled as setting - * DHCP up takes some time. - */ -#define APP_STARTUP_TIME K_SECONDS(20) - -#define POST_CONTENT_TYPE "application/x-www-form-urlencoded" -#define POST_PAYLOAD "os=ZephyrRTOS&arch=" CONFIG_ARCH - -#if defined(CONFIG_HTTPS) -#define SERVER_PORT 4443 -#else -#define SERVER_PORT 8000 -#endif - -#if defined(CONFIG_NET_IPV6) -#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV6_ADDR -#else -#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV4_ADDR -#endif diff --git a/samples/net/http_client/src/echo-apps-cert.der b/samples/net/http_client/src/echo-apps-cert.der deleted file mode 100644 index bfcb335e31c..00000000000 Binary files a/samples/net/http_client/src/echo-apps-cert.der and /dev/null differ diff --git a/samples/net/http_client/src/main.c b/samples/net/http_client/src/main.c deleted file mode 100644 index 5c5379ea992..00000000000 --- a/samples/net/http_client/src/main.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(net_http_client_sample, LOG_LEVEL_DBG); - -#include -#include - -#include -#include - -#include - -#include - -#include "config.h" - -#define MAX_ITERATIONS 20 -#define WAIT_TIME (APP_REQ_TIMEOUT * 2) - -/* The OPTIONS method is problematic as the HTTP server might not support - * it so turn it off by default. - */ -#define SEND_OPTIONS 0 - -/* - * Note that the http_ctx is quite large so be careful if that is - * allocated from stack. - */ -static struct http_ctx http_ctx; - -#if defined(CONFIG_HTTPS) -#define HOSTNAME "localhost" /* for cert verification if that is enabled */ - -/* The result buf size is set to large enough so that we can receive max size - * buf back. Note that mbedtls needs also be configured to have equal size - * value for its buffer size. See MBEDTLS_SSL_MAX_CONTENT_LEN option in TLS - * config file. - */ -#define RESULT_BUF_SIZE MBEDTLS_SSL_MAX_CONTENT_LEN -static u8_t https_result_buf[RESULT_BUF_SIZE]; - -#define INSTANCE_INFO "Zephyr HTTPS client #1" - -#define HTTPS_STACK_SIZE (8 * 1024) - -NET_STACK_DEFINE(HTTPS, https_stack, HTTPS_STACK_SIZE, HTTPS_STACK_SIZE); - -NET_APP_TLS_POOL_DEFINE(ssl_pool, 10); -#endif /* CONFIG_HTTPS */ - -#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) -NET_PKT_TX_SLAB_DEFINE(http_cli_tx, 15); -NET_PKT_DATA_POOL_DEFINE(http_cli_data, 30); - -static struct k_mem_slab *tx_slab(void) -{ - return &http_cli_tx; -} - -static struct net_buf_pool *data_pool(void) -{ - return &http_cli_data; -} -#else -#if defined(CONFIG_NET_L2_BT) -#error "TCP connections over Bluetooth need CONFIG_NET_CONTEXT_NET_PKT_POOL "\ - "defined." -#endif /* CONFIG_NET_L2_BT */ - -#define tx_slab NULL -#define data_pool NULL -#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ - -#if !defined(RESULT_BUF_SIZE) -#define RESULT_BUF_SIZE 1600 -#endif - -/* This will contain the returned HTTP response to a sent request */ -static u8_t result[RESULT_BUF_SIZE]; - -struct waiter { - struct http_ctx *ctx; - struct k_sem wait; - size_t total_len; - size_t header_len; -}; - -#if defined(CONFIG_HTTPS) -/* Load the certificates etc. In this sample app, we verify that - * the server is the test server we are communicating against to. - */ - -static const char echo_apps_cert_der[] = { -#include "echo-apps-cert.der.inc" -}; - -#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) -static const unsigned char client_psk[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f -}; - -static const char client_psk_id[] = "Client_identity"; -#endif - -static int setup_cert(struct net_app_ctx *ctx, void *cert) -{ -#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) - mbedtls_ssl_conf_psk(&ctx->tls.mbedtls.conf, - client_psk, sizeof(client_psk), - (const unsigned char *)client_psk_id, - sizeof(client_psk_id) - 1); -#endif - -#if defined(MBEDTLS_X509_CRT_PARSE_C) - { - mbedtls_x509_crt *ca_cert = cert; - int ret; - - ret = mbedtls_x509_crt_parse_der(ca_cert, - echo_apps_cert_der, - sizeof(echo_apps_cert_der)); - if (ret != 0) { - LOG_ERR("mbedtls_x509_crt_parse_der failed " - "(-0x%x)", -ret); - return ret; - } - - mbedtls_ssl_conf_ca_chain(&ctx->tls.mbedtls.conf, - ca_cert, NULL); - mbedtls_ssl_conf_authmode(&ctx->tls.mbedtls.conf, - MBEDTLS_SSL_VERIFY_REQUIRED); - - mbedtls_ssl_conf_cert_profile(&ctx->tls.mbedtls.conf, - &mbedtls_x509_crt_profile_default); - } -#endif /* MBEDTLS_X509_CRT_PARSE_C */ - - return 0; -} -#endif /* CONFIG_HTTPS */ - -static int do_sync_http_req(struct http_ctx *ctx, - enum http_method method, - const char *url, - const char *content_type, - const char *payload, - int count) -{ - struct http_request req = {}; - int ret; - - req.method = method; - req.url = url; - req.protocol = " " HTTP_PROTOCOL; - - LOG_INF("[%d] Send %s", count, url); - - ret = http_client_send_req(ctx, &req, NULL, result, sizeof(result), - NULL, APP_REQ_TIMEOUT); - if (ret < 0) { - LOG_ERR("Cannot send %s request (%d)", http_method_str(method), - ret); - goto out; - } - - if (ctx->http.rsp.data_len > sizeof(result)) { - LOG_ERR("Result buffer overflow by %zd bytes", - ctx->http.rsp.data_len - sizeof(result)); - - ret = -E2BIG; - } else { - LOG_INF("HTTP server response status: %s", - ctx->http.rsp.http_status); - - if (ctx->http.parser.http_errno) { - if (method == HTTP_OPTIONS) { - /* Ignore error if OPTIONS is not found */ - goto out; - } - - LOG_INF("HTTP parser status: %s", - http_errno_description( - ctx->http.parser.http_errno)); - ret = -EINVAL; - goto out; - } - - if (method != HTTP_HEAD) { - if (ctx->http.rsp.body_found) { - LOG_INF("HTTP body: %zd bytes, " - "expected: %zd bytes", - ctx->http.rsp.processed, - ctx->http.rsp.content_length); - } else { - LOG_ERR("Error detected during HTTP msg " - "processing"); - } - } - } - -out: - http_close(ctx); - - return ret; -} - -void response(struct http_ctx *ctx, - u8_t *data, size_t buflen, - size_t datalen, - enum http_final_call data_end, - void *user_data) -{ - struct waiter *waiter = user_data; - int ret; - - if (data_end == HTTP_DATA_MORE) { - LOG_INF("Received %zd bytes piece of data", datalen); - - /* Do something with the data here. For this example - * we just ignore the received data. - */ - waiter->total_len += datalen; - - if (ctx->http.rsp.body_start) { - /* This fragment contains the start of the body - * Note that the header length is not proper if - * the header is spanning over multiple recv - * fragments. - */ - waiter->header_len = ctx->http.rsp.body_start - - ctx->http.rsp.response_buf; - } - - return; - } - - waiter->total_len += datalen; - - LOG_INF("HTTP server response status: %s", ctx->http.rsp.http_status); - - if (ctx->http.parser.http_errno) { - if (ctx->http.req.method == HTTP_OPTIONS) { - /* Ignore error if OPTIONS is not found */ - goto out; - } - - LOG_INF("HTTP parser status: %s", - http_errno_description(ctx->http.parser.http_errno)); - ret = -EINVAL; - goto out; - } - - if (ctx->http.req.method != HTTP_HEAD && - ctx->http.req.method != HTTP_OPTIONS) { - if (ctx->http.rsp.body_found) { - LOG_INF("HTTP body: %zd bytes, expected: %zd bytes", - ctx->http.rsp.processed, - ctx->http.rsp.content_length); - } else { - LOG_ERR("Error detected during HTTP msg processing"); - } - - if (waiter->total_len != - waiter->header_len + ctx->http.rsp.content_length) { - LOG_ERR("Error while receiving data, " - "received %zd expected %zd bytes", - waiter->total_len, waiter->header_len + - ctx->http.rsp.content_length); - } - } - -out: - k_sem_give(&waiter->wait); -} - -static int do_async_http_req(struct http_ctx *ctx, - enum http_method method, - const char *url, - const char *content_type, - const char *payload, - int count) -{ - struct http_request req = {}; - struct waiter waiter; - int ret; - - req.method = method; - req.url = url; - req.protocol = " " HTTP_PROTOCOL; - - k_sem_init(&waiter.wait, 0, 1); - - waiter.total_len = 0; - - LOG_INF("[%d] Send %s", count, url); - - ret = http_client_send_req(ctx, &req, response, result, sizeof(result), - &waiter, APP_REQ_TIMEOUT); - if (ret < 0 && ret != -EINPROGRESS) { - LOG_ERR("Cannot send %s request (%d)", http_method_str(method), - ret); - goto out; - } - - if (k_sem_take(&waiter.wait, WAIT_TIME)) { - LOG_ERR("Timeout while waiting HTTP response"); - ret = -ETIMEDOUT; - http_request_cancel(ctx); - goto out; - } - - ret = 0; - -out: - http_close(ctx); - - return ret; -} - -static inline int do_sync_reqs(struct http_ctx *ctx, int count) -{ - int max_count = count; - int ret; - - /* These examples use the HTTP client API synchronously so they - * do not set the callback parameter. - */ - while (count--) { - ret = do_sync_http_req(&http_ctx, HTTP_GET, "/index.html", - NULL, NULL, max_count - count); - if (ret < 0) { - goto out; - } - - ret = do_sync_http_req(&http_ctx, HTTP_HEAD, "/", - NULL, NULL, max_count - count); - if (ret < 0) { - goto out; - } - -#if SEND_OPTIONS - ret = do_sync_http_req(&http_ctx, HTTP_OPTIONS, "/index.html", - NULL, NULL, max_count - count); - if (ret < 0) { - goto out; - } -#endif - - ret = do_sync_http_req(&http_ctx, HTTP_POST, "/post_test.php", - POST_CONTENT_TYPE, POST_PAYLOAD, - max_count - count); - if (ret < 0) { - goto out; - } - - /* Note that we cannot receive data bigger than RESULT_BUF_SIZE - * if we wait the buffer synchronously. If you want to receive - * bigger data, then you need to set the callback when sending - * the HTTP request using http_client_send_req() - */ - } - -out: - return ret; -} - -static inline int do_async_reqs(struct http_ctx *ctx, int count) -{ - int max_count = count; - int ret; - - /* These examples use the HTTP client API asynchronously so they - * do set the callback parameter. - */ - while (count--) { - ret = do_async_http_req(&http_ctx, HTTP_GET, "/index.html", - NULL, NULL, max_count - count); - if (ret < 0) { - goto out; - } - - ret = do_async_http_req(&http_ctx, HTTP_HEAD, "/", - NULL, NULL, max_count - count); - if (ret < 0) { - goto out; - } - -#if SEND_OPTIONS - ret = do_async_http_req(&http_ctx, HTTP_OPTIONS, "/index.html", - NULL, NULL, max_count - count); - if (ret < 0) { - goto out; - } -#endif - - ret = do_async_http_req(&http_ctx, HTTP_POST, "/post_test.php", - POST_CONTENT_TYPE, POST_PAYLOAD, - max_count - count); - if (ret < 0) { - goto out; - } - - ret = do_async_http_req(&http_ctx, HTTP_GET, "/big-file.html", - NULL, NULL, max_count - count); - if (ret < 0) { - goto out; - } - } - -out: - return ret; -} - -static void http_received(struct http_ctx *ctx, - struct net_pkt *pkt, - int status, - u32_t flags, - const struct sockaddr *dst, - void *user_data) -{ - if (!status) { - if (pkt) { - LOG_DBG("Received %d bytes data", - net_pkt_appdatalen(pkt)); - net_pkt_unref(pkt); - } - } else { - LOG_ERR("Receive error (%d)", status); - - if (pkt) { - net_pkt_unref(pkt); - } - } -} - -void main(void) -{ - int ret; - - ret = http_client_init(&http_ctx, SERVER_ADDR, SERVER_PORT, NULL, - K_FOREVER); - if (ret < 0) { - LOG_ERR("HTTP init failed (%d)", ret); - goto out; - } - -#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) - net_app_set_net_pkt_pool(&http_ctx.app_ctx, tx_slab, data_pool); -#endif - - http_set_cb(&http_ctx, NULL, http_received, NULL, NULL); - -#if defined(CONFIG_HTTPS) - ret = http_client_set_tls(&http_ctx, - https_result_buf, - sizeof(https_result_buf), - (u8_t *)INSTANCE_INFO, - strlen(INSTANCE_INFO), - setup_cert, - HOSTNAME, - NULL, - &ssl_pool, - https_stack, - K_THREAD_STACK_SIZEOF(https_stack)); - if (ret < 0) { - LOG_ERR("HTTPS init failed (%d)", ret); - goto out; - } -#endif - - LOG_INF("--------Sending %d sync request--------", MAX_ITERATIONS); - - ret = do_sync_reqs(&http_ctx, MAX_ITERATIONS); - if (ret < 0) { - goto out; - } - - LOG_INF("--------Sending %d async request--------", MAX_ITERATIONS); - - ret = do_async_reqs(&http_ctx, MAX_ITERATIONS); - if (ret < 0) { - goto out; - } - -out: - http_release(&http_ctx); - - LOG_INF("Done!"); -} diff --git a/samples/net/http_server/CMakeLists.txt b/samples/net/http_server/CMakeLists.txt deleted file mode 100644 index f65574527d1..00000000000 --- a/samples/net/http_server/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -cmake_minimum_required(VERSION 3.13.1) -include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) -project(http_server) - -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) - -include($ENV{ZEPHYR_BASE}/samples/net/common/common.cmake) - -# List of files that are used to generate .h file that can be included -# into .c file. -foreach(inc_file - echo-apps-cert.der - echo-apps-key.der - index.html - ) - generate_inc_file_for_target( - app - src/${inc_file} - ${ZEPHYR_BINARY_DIR}/include/generated/${inc_file}.inc - ) -endforeach() diff --git a/samples/net/http_server/README.rst b/samples/net/http_server/README.rst deleted file mode 100644 index 2573c4f4ebc..00000000000 --- a/samples/net/http_server/README.rst +++ /dev/null @@ -1,195 +0,0 @@ -.. _http-server-sample: - -HTTP Server -########### - -Overview -******** - -The HTTP Server sample application for Zephyr implements a basic TCP server -on top of the HTTP Server Library that is able to receive HTTP 1.1 requests, -parse them and write back the responses. - -The source code for this sample application can be found at: -:file:`samples/net/http_server`. - -Requirements -************ - -- Linux machine with wget and the screen terminal emulator -- Either QEMU or real device like Freedom Board (FRDM-K64F) -- For QEMU see this :ref:`networking_with_qemu` -- LAN for testing purposes (Ethernet) - - -Building and Running -******************** - -Currently, the HTTP Server application is configured to listen at port 80. -If you want to modify the http-server sample application, please check -the configuration settings in :file:`samples/net/http_server/src/main.c` file -and also in the :file:`samples/net/http_server/src/config.h` file. - -To use QEMU for testing, follow the :ref:`networking_with_qemu` guide. - -This sample code supports both static and dynamic (DHCPv4) IP addresses that -can be defined in the project configuration file: - -.. code-block:: console - - CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" - CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" - -Adding URLs -=========== - -To define a new URL or to change how a URL is processed by the HTTP server, -open the :file:`samples/net/http_server/src/main.c` file and locate the -following lines: - -.. code-block:: c - - http_server_add_default(&http_urls, default_handler); - http_server_add_url(&http_urls, "/headers", HTTP_URL_STANDARD); - http_server_add_url(&http_urls, "/index.html", HTTP_URL_STANDARD); - -The first line defines how Zephyr will deal with unknown URLs. In this case, -it will respond with a soft HTTP 404 status code, i.e. an HTTP 200 OK status -code with a 404 Not Found HTML body. - -To build this sample on your Linux host computer, open a terminal window, -locate the source code of this sample application and type: - -.. zephyr-app-commands:: - :zephyr-app: samples/net/http_server - :host-os: unix - :board: qemu_x86 - :goals: run - :compact: - - -Sample Output -============= - -Assume in this example that this HTTP server is configured to listen at -IPv4 address 192.168.1.120 and IPv6 address 2001:db8::1 port 80. -On your Linux host computer, open a terminal window and type: - -.. code-block:: console - - wget 192.168.1.120/index.html - -wget will show: - -.. code-block:: console - - --2017-01-17 00:37:44-- http://192.168.1.120/ - Connecting to 192.168.1.120:80... connected. - HTTP request sent, awaiting response... 200 OK - Length: unspecified [text/html] - Saving to: 'index.html' - -The HTML file generated by Zephyr and downloaded by wget is: - -.. code-block:: html - - - - Zephyr HTTP Server - -

It Works!

- - -The screen application will display the following information: - -.. code-block:: console - - [http-server] [DBG] http_connected: (0x00403fa0): HTTP connect attempt URL /index.html - [http-server] [DBG] http_serve_index_html: (0x00403fa0): Sending index.html (170 bytes) to client - [http-server] [DBG] http_closed: (0x00403fa0): Connection 0x004004c0 closed - -To obtain the HTTP Header Fields web page, use the following command: - -.. code-block:: console - - wget 192.168.1.120/headers -O index.html - -wget will show: - -.. code-block:: console - - --2017-01-19 22:09:55-- http://192.168.1.120/headers - Connecting to 192.168.1.120:80... connected. - HTTP request sent, awaiting response... 200 OK - Length: unspecified [text/html] - Saving to: 'index.html' - -This is the HTML file generated by Zephyr and downloaded by wget: - -.. code-block:: html - - - - Zephyr HTTP Server - - -

Zephyr HTTP server

-

HTTP Header Fields

-
    -
  • User-Agent: Wget/1.16 (linux-gnu)
  • -
  • Accept: */*
  • -
  • Host: 192.168.1.120
  • -
  • Connection: Keep-Alive
  • -
-

HTTP Method: GET

-

URL: /headers

-

Server: arm

- - - -To test the 404 Not Found soft error, use the following command: - -.. code-block:: console - - wget 192.168.1.120/not_found -O index.html - -Zephyr will generate an HTTP response with the following header: - -.. code-block:: console - - HTTP/1.1 200 OK - Content-Type: text/html - Transfer-Encoding: chunked - -and this is the HTML message that wget will save: - -.. code-block:: html - - - - Zephyr HTTP Server - -

404 Not Found

- - -HTTPS Server -============ - -The sample code also includes a HTTPS (HTTP over TLS) server example -running side by side with the HTTP server, this server runs on QEMU. -In order to compile and run the code execute: - -.. zephyr-app-commands:: - :zephyr-app: samples/net/http_server - :host-os: unix - :board: qemu_x86 - :conf: prj_tls.conf - :goals: run - :compact: - - -Known Issues and Limitations -============================ - -- Currently, this sample application only generates HTTP responses in - chunk transfer mode. diff --git a/samples/net/http_server/overlay-netusb.conf b/samples/net/http_server/overlay-netusb.conf deleted file mode 100644 index 3be02b112c8..00000000000 --- a/samples/net/http_server/overlay-netusb.conf +++ /dev/null @@ -1,26 +0,0 @@ -# USB Device settings -CONFIG_USB=y -CONFIG_USB_DEVICE_STACK=y - -# Select USB Configurations -CONFIG_USB_DEVICE_NETWORK_ECM=y - -# Logging -CONFIG_USB_DRIVER_LOG_LEVEL_INF=y -CONFIG_USB_DEVICE_LOG_LEVEL_INF=y - -# Zero Configuration -# Remove hardcoded addresses -CONFIG_NET_CONFIG_SETTINGS=n - -CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT=2 -CONFIG_NET_IPV4_AUTO=y -CONFIG_NET_HOSTNAME_ENABLE=y -CONFIG_DNS_RESOLVER=y -CONFIG_LLMNR_RESOLVER=y -CONFIG_LLMNR_RESPONDER=y - -# Reduce image size -CONFIG_NET_STATISTICS=n -CONFIG_NET_CONFIG_NEED_IPV6=n -CONFIG_NET_IPV6=n diff --git a/samples/net/http_server/prj.conf b/samples/net/http_server/prj.conf deleted file mode 100644 index 494881513ee..00000000000 --- a/samples/net/http_server/prj.conf +++ /dev/null @@ -1,43 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_NET_TCP=y -CONFIG_ENTROPY_GENERATOR=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_LOG=y -CONFIG_LOG=y -CONFIG_INIT_STACKS=y - -CONFIG_NET_PKT_RX_COUNT=32 -CONFIG_NET_PKT_TX_COUNT=32 -CONFIG_NET_BUF_RX_COUNT=32 -CONFIG_NET_BUF_TX_COUNT=32 - -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 - -CONFIG_NET_MAX_CONTEXTS=16 - -CONFIG_HTTP=y -CONFIG_HTTP_SERVER=y -# Allow two concurrent connections -CONFIG_NET_TCP_BACKLOG_SIZE=2 -CONFIG_NET_APP_SERVER_NUM_CONN=2 - -CONFIG_NET_IPV6=y -CONFIG_NET_IPV4=y -#CONFIG_NET_DHCPV4=y - -CONFIG_HTTPS=n -CONFIG_MBEDTLS=n - -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" - -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_CONFIG_NEED_IPV4=y - -CONFIG_NET_SHELL=y -CONFIG_NET_STATISTICS=y - -CONFIG_NET_MGMT=y -CONFIG_NET_MGMT_EVENT=y diff --git a/samples/net/http_server/prj_bt.conf b/samples/net/http_server/prj_bt.conf deleted file mode 100644 index 821f585aeb1..00000000000 --- a/samples/net/http_server/prj_bt.conf +++ /dev/null @@ -1,50 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_NET_TCP=y -CONFIG_ENTROPY_GENERATOR=y -CONFIG_NET_LOG=y -CONFIG_LOG=y -CONFIG_INIT_STACKS=y - -CONFIG_NET_PKT_RX_COUNT=16 -CONFIG_NET_PKT_TX_COUNT=16 -CONFIG_NET_BUF_RX_COUNT=16 -CONFIG_NET_BUF_TX_COUNT=16 - -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 - -CONFIG_STDOUT_CONSOLE=y - -CONFIG_HTTP=y -CONFIG_HTTP_SERVER=y - -CONFIG_NET_IPV6=y -CONFIG_NET_IPV4=n - -CONFIG_HTTPS=y -CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_BUILTIN=y -CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h" -CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2500 -CONFIG_MBEDTLS_ENABLE_HEAP=y -CONFIG_MBEDTLS_HEAP_SIZE=12000 - -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_BT_NODE=y - -CONFIG_NET_SHELL=y - -CONFIG_NET_MGMT=y -CONFIG_NET_MGMT_EVENT=y - -CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y -CONFIG_BT_SMP=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y -CONFIG_BT_DEVICE_NAME="Test Http_Server" -CONFIG_NET_UDP=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_L2_BT=y -CONFIG_NET_STATISTICS=y diff --git a/samples/net/http_server/prj_tls.conf b/samples/net/http_server/prj_tls.conf deleted file mode 100644 index b1151dfa6e5..00000000000 --- a/samples/net/http_server/prj_tls.conf +++ /dev/null @@ -1,48 +0,0 @@ -CONFIG_NETWORKING=y -CONFIG_NET_TCP=y -CONFIG_ENTROPY_GENERATOR=y -CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NET_LOG=y -CONFIG_LOG=y -CONFIG_INIT_STACKS=y - -CONFIG_NET_PKT_RX_COUNT=32 -CONFIG_NET_PKT_TX_COUNT=32 -CONFIG_NET_BUF_RX_COUNT=32 -CONFIG_NET_BUF_TX_COUNT=32 - -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2 -CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 - -CONFIG_NET_MAX_CONTEXTS=16 - -CONFIG_MBEDTLS_DEBUG=n -CONFIG_MBEDTLS_DEBUG_LEVEL=1 - -CONFIG_HTTP=y -CONFIG_HTTP_SERVER=y - -CONFIG_NET_IPV6=y -CONFIG_NET_IPV4=y -#CONFIG_NET_DHCPV4=y - -CONFIG_HTTPS=y -CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_BUILTIN=y -CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h" -CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2500 -CONFIG_MBEDTLS_ENABLE_HEAP=y -CONFIG_MBEDTLS_HEAP_SIZE=30000 - -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" - -CONFIG_NET_CONFIG_NEED_IPV6=y -CONFIG_NET_CONFIG_NEED_IPV4=y - -CONFIG_NET_SHELL=y -CONFIG_NET_STATISTICS=y - -CONFIG_NET_MGMT=y -CONFIG_NET_MGMT_EVENT=y diff --git a/samples/net/http_server/sample.yaml b/samples/net/http_server/sample.yaml deleted file mode 100644 index b282bb748f1..00000000000 --- a/samples/net/http_server/sample.yaml +++ /dev/null @@ -1,28 +0,0 @@ -sample: - name: HTTP Server -tests: - test: - harness: net - depends_on: netif - tags: net http - min_flash: 140 - test_bt: - harness: net - extra_args: CONF_FILE="prj_bt.conf" - platform_whitelist: qemu_x86 - tags: net http - test_usbnet_ecm: - harness: net - extra_args: OVERLAY_CONFIG="overlay-netusb.conf" - tags: net usb - depends_on: usb_device - min_ram: 64 - test_usbnet_eem: - harness: net - extra_args: OVERLAY_CONFIG="overlay-netusb.conf" - extra_configs: - - CONFIG_USB_DEVICE_NETWORK_ECM=n - - CONFIG_USB_DEVICE_NETWORK_EEM=y - tags: net usb - depends_on: usb_device - min_ram: 64 diff --git a/samples/net/http_server/src/config.h b/samples/net/http_server/src/config.h deleted file mode 100644 index a7fde5ded71..00000000000 --- a/samples/net/http_server/src/config.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _CONFIG_H_ -#define _CONFIG_H_ - -/* The startup time needs to be longish if DHCP is enabled as setting - * DHCP up takes some time. - */ -#define APP_STARTUP_TIME K_SECONDS(20) - -#ifdef CONFIG_NET_CONFIG_SETTINGS -#ifdef CONFIG_NET_IPV6 -#define ZEPHYR_ADDR CONFIG_NET_CONFIG_MY_IPV6_ADDR -#else -#define ZEPHYR_ADDR CONFIG_NET_CONFIG_MY_IPV4_ADDR -#endif -#else -#ifdef CONFIG_NET_IPV6 -#define ZEPHYR_ADDR "2001:db8::1" -#else -#define ZEPHYR_ADDR "192.0.2.1" -#endif -#endif - -#ifndef ZEPHYR_PORT -#define ZEPHYR_PORT 8080 -#endif - -#define HTTP_AUTH_URL "/auth" -#define HTTP_AUTH_TYPE "Basic" - -/* HTTP Basic Auth, see https://tools.ietf.org/html/rfc7617 */ -#define HTTP_AUTH_REALM "Zephyr" -#define HTTP_AUTH_USERNAME "zephyr" -#define HTTP_AUTH_PASSWORD "0123456789" - -#endif diff --git a/samples/net/http_server/src/echo-apps-cert.der b/samples/net/http_server/src/echo-apps-cert.der deleted file mode 100644 index bfcb335e31c..00000000000 Binary files a/samples/net/http_server/src/echo-apps-cert.der and /dev/null differ diff --git a/samples/net/http_server/src/echo-apps-key.der b/samples/net/http_server/src/echo-apps-key.der deleted file mode 100644 index 5a4d67372ea..00000000000 Binary files a/samples/net/http_server/src/echo-apps-key.der and /dev/null differ diff --git a/samples/net/http_server/src/index.html b/samples/net/http_server/src/index.html deleted file mode 100644 index d00e0c2bb56..00000000000 --- a/samples/net/http_server/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - Zephyr HTTP server sample - - - -
-

It works!

-
- - diff --git a/samples/net/http_server/src/main.c b/samples/net/http_server/src/main.c deleted file mode 100644 index 2d36d76288d..00000000000 --- a/samples/net/http_server/src/main.c +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#if defined(CONFIG_HTTPS) -#define LOG_MODULE_NAME net_https_server_sample -#else -#define LOG_MODULE_NAME net_http_server_sample -#endif - -#include -LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG); - -#include -#include - -#include - -#include - -#include "config.h" - -/* Sets the network parameters */ - -#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) -NET_PKT_TX_SLAB_DEFINE(http_srv_tx, 15); -NET_PKT_DATA_POOL_DEFINE(http_srv_data, 30); - -static struct k_mem_slab *tx_slab(void) -{ - return &http_srv_tx; -} - -static struct net_buf_pool *data_pool(void) -{ - return &http_srv_data; -} -#else -#if defined(CONFIG_NET_L2_BT) -#error "TCP connections over Bluetooth need CONFIG_NET_CONTEXT_NET_PKT_POOL "\ - "defined." -#endif /* CONFIG_NET_L2_BT */ - -#define tx_slab NULL -#define data_pool NULL -#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ - -#define RESULT_BUF_SIZE 1500 -static u8_t http_result[RESULT_BUF_SIZE]; - -#if defined(CONFIG_HTTPS) -#if !defined(CONFIG_HTTPS_STACK_SIZE) -#define CONFIG_HTTPS_STACK_SIZE 8192 -#endif /* CONFIG_HTTPS_STACK_SIZE */ - -#define APP_BANNER "Run HTTPS server" -#define INSTANCE_INFO "Zephyr HTTPS example server #1" - -/* Note that each HTTPS context needs its own stack as there will be - * a separate thread for each HTTPS context. - */ -NET_STACK_DEFINE(HTTPS, https_stack, CONFIG_NET_APP_TLS_STACK_SIZE, - CONFIG_NET_APP_TLS_STACK_SIZE); - -#define RX_FIFO_DEPTH 4 -K_MEM_POOL_DEFINE(ssl_rx_pool, 4, 64, RX_FIFO_DEPTH, 4); - -#else /* CONFIG_HTTPS */ -#define APP_BANNER "Run HTTP server" -#endif /* CONFIG_HTTPS */ - -/* - * Note that the http_server_ctx and http_server_urls are quite large so be - * careful if those are allocated from stack. - */ -static struct http_ctx http_ctx; -static struct http_server_urls http_urls; - -void panic(const char *msg) -{ - if (msg) { - LOG_ERR("%s", msg); - } - - for (;;) { - k_sleep(K_FOREVER); - } -} - -#define HTTP_STATUS_200_OK "HTTP/1.1 200 OK\r\n" \ - "Content-Type: text/html\r\n" \ - "Transfer-Encoding: chunked\r\n" - -#define HTTP_STATUS_200_OK_GZ "HTTP/1.1 200 OK\r\n" \ - "Content-Type: text/html\r\n" \ - "Transfer-Encoding: chunked\r\n" \ - "Content-Encoding: gzip\r\n" - -#define HTML_HEADER "" \ - "Zephyr HTTP Server" \ - "

" \ - "
Zephyr HTTP server

\r\n" - -#define HTML_FOOTER "\r\n" - -static int http_response(struct http_ctx *ctx, const char *header, - const char *payload, size_t payload_len, - char *str, const struct sockaddr *dst) -{ - int ret; - - ret = http_add_header(ctx, header, dst, str); - if (ret < 0) { - LOG_ERR("Cannot add HTTP header (%d)", ret); - return ret; - } - - ret = http_add_header(ctx, HTTP_CRLF, dst, str); - if (ret < 0) { - return ret; - } - - ret = http_send_chunk(ctx, payload, payload_len, dst, str); - if (ret < 0) { - LOG_ERR("Cannot send data to peer (%d)", ret); - return ret; - } - - ret = http_send_chunk(ctx, NULL, 0, dst, NULL); - if (ret < 0) { - LOG_ERR("Cannot send data to peer (%d)", ret); - return ret; - } - - return http_send_flush(ctx, str); -} - -static int http_response_soft_404(struct http_ctx *ctx, - const struct sockaddr *dst) -{ - static const char *not_found = - HTML_HEADER - "

404 Not Found

" - HTML_FOOTER; - - return http_response(ctx, HTTP_STATUS_200_OK, not_found, - strlen(not_found), "Error", dst); -} - -/* Prints the received HTTP header fields as an HTML list */ -static void print_http_headers(struct http_ctx *ctx, - char *str, int size) -{ - int offset; - int ret; - - ret = snprintf(str, size, - HTML_HEADER - "

HTTP Header Fields

\r\n
    \r\n"); - if (ret < 0 || ret >= size) { - return; - } - - offset = ret; - - for (u8_t i = 0; i < ctx->http.field_values_ctr; i++) { - struct http_field_value *kv = &ctx->http.field_values[i]; - - ret = snprintf(str + offset, size - offset, - "
  • %.*s: %.*s
  • \r\n", - kv->key_len, kv->key, - kv->value_len, kv->value); - if (ret < 0 || ret >= size) { - return; - } - - offset += ret; - } - - ret = snprintf(str + offset, size - offset, "
\r\n"); - if (ret < 0 || ret >= size) { - return; - } - - offset += ret; - - ret = snprintf(str + offset, size - offset, - "

HTTP Method: %s

\r\n", - http_method_str(ctx->http.parser.method)); - if (ret < 0 || ret >= size) { - return; - } - - offset += ret; - - ret = snprintf(str + offset, size - offset, - "

URL: %.*s

\r\n", - ctx->http.url_len, ctx->http.url); - if (ret < 0 || ret >= size) { - return; - } - - offset += ret; - - snprintf(str + offset, size - offset, - "

Server: %s

"HTML_FOOTER, CONFIG_ARCH); -} - -int http_serve_headers(struct http_ctx *ctx, - const struct sockaddr *dst) -{ -#define HTTP_MAX_BODY_STR_SIZE 1024 - static char html_body[HTTP_MAX_BODY_STR_SIZE]; - - print_http_headers(ctx, html_body, HTTP_MAX_BODY_STR_SIZE); - - return http_response(ctx, HTTP_STATUS_200_OK, html_body, - strlen(html_body), "Headers", dst); -} - -static int http_serve_index_html(struct http_ctx *ctx, - const struct sockaddr *dst) -{ - static const char index_html[] = { -#include "index.html.inc" - }; - - LOG_DBG("Sending index.html (%zd bytes) to client", - sizeof(index_html)); - - return http_response(ctx, HTTP_STATUS_200_OK, index_html, - sizeof(index_html), "Index", dst); -} - -static void http_connected(struct http_ctx *ctx, - enum http_connection_type type, - const struct sockaddr *dst, - void *user_data) -{ - char url[32]; - int len = min(sizeof(url) - 1, ctx->http.url_len); - - memcpy(url, ctx->http.url, len); - url[len] = '\0'; - - LOG_DBG("%s connect attempt URL %s", - type == HTTP_CONNECTION ? "HTTP" : "WS", url); - - if (type == HTTP_CONNECTION) { - if (strncmp(ctx->http.url, "/", - ctx->http.url_len) == 0) { - http_serve_index_html(ctx, dst); - http_close(ctx); - return; - } - - if (strncmp(ctx->http.url, "/index.html", - ctx->http.url_len) == 0) { - http_serve_index_html(ctx, dst); - http_close(ctx); - return; - } - - if (strncmp(ctx->http.url, "/headers", - ctx->http.url_len) == 0) { - http_serve_headers(ctx, dst); - http_close(ctx); - return; - } - } - - /* Give 404 error for all the other URLs we do not want to handle - * right now. - */ - http_response_soft_404(ctx, dst); - http_close(ctx); -} - -static void http_received(struct http_ctx *ctx, - struct net_pkt *pkt, - int status, - u32_t flags, - const struct sockaddr *dst, - void *user_data) -{ - if (!status) { - if (pkt) { - LOG_DBG("Received %d bytes data", - net_pkt_appdatalen(pkt)); - net_pkt_unref(pkt); - } - } else { - LOG_ERR("Receive error (%d)", status); - - if (pkt) { - net_pkt_unref(pkt); - } - } -} - -static void http_sent(struct http_ctx *ctx, - int status, - void *user_data_send, - void *user_data) -{ - LOG_DBG("%s sent", (char *)user_data_send); -} - -static void http_closed(struct http_ctx *ctx, - int status, - void *user_data) -{ - LOG_DBG("Connection %p closed", ctx); -} - -static const char *get_string(int str_len, const char *str) -{ - static char buf[64]; - int len = min(str_len, sizeof(buf) - 1); - - memcpy(buf, str, len); - buf[len] = '\0'; - - return buf; -} - -static enum http_verdict default_handler(struct http_ctx *ctx, - enum http_connection_type type, - const struct sockaddr *dst) -{ - LOG_DBG("No handler for %s URL %s", - type == HTTP_CONNECTION ? "HTTP" : "WS", - get_string(ctx->http.url_len, ctx->http.url)); - - if (type == HTTP_CONNECTION) { - http_response_soft_404(ctx, dst); - } - - return HTTP_VERDICT_DROP; -} - - -#if defined(CONFIG_HTTPS) -/* Load the certificates and private RSA key. */ - -static const char echo_apps_cert_der[] = { -#include "echo-apps-cert.der.inc" -}; - -static const char echo_apps_key_der[] = { -#include "echo-apps-key.der.inc" -}; - -static int setup_cert(struct net_app_ctx *app_ctx, - mbedtls_x509_crt *cert, - mbedtls_pk_context *pkey) -{ - int ret; - - ret = mbedtls_x509_crt_parse(cert, echo_apps_cert_der, - sizeof(echo_apps_cert_der)); - if (ret != 0) { - LOG_ERR("mbedtls_x509_crt_parse returned %d", ret); - return ret; - } - - ret = mbedtls_pk_parse_key(pkey, echo_apps_key_der, - sizeof(echo_apps_key_der), - NULL, 0); - if (ret != 0) { - LOG_ERR("mbedtls_pk_parse_key returned %d", ret); - return ret; - } - - return 0; -} -#endif /* CONFIG_HTTPS */ - -void main(void) -{ - struct sockaddr addr, *server_addr; - int ret; - - /* - * There are several options here for binding to local address. - * 1) The server address can be left empty in which case the - * library will bind to both IPv4 and IPv6 addresses and to - * port 80 which is the default. - * 2) The server address can be partially filled, meaning that - * the address can be left to 0 and port can be set if a value - * other than 80 is desired. If the protocol family in sockaddr - * is set to AF_UNSPEC, then both IPv4 and IPv6 socket is bound. - * 3) The address can be set to some real value. There is a helper - * function that can be used to fill the socket address struct. - */ -#define ADDR_OPTION 1 - -#if ADDR_OPTION == 1 - server_addr = NULL; - - ARG_UNUSED(addr); - -#elif ADDR_OPTION == 2 - /* Accept any local listening address */ - (void)memset(&addr, 0, sizeof(addr)); - - net_sin(&addr)->sin_port = htons(ZEPHYR_PORT); - - /* In this example, listen only IPv4 */ - addr.family = AF_INET; - - server_addr = &addr; - -#elif ADDR_OPTION == 3 - /* Set the bind address according to your configuration */ - (void)memset(&addr, 0, sizeof(addr)); - - /* In this example, listen only IPv6 */ - addr.family = AF_INET6; - - ret = http_server_set_local_addr(&addr, ZEPHYR_ADDR, ZEPHYR_PORT); - if (ret < 0) { - LOG_ERR("Cannot set local address (%d)", ret); - panic(NULL); - } - - server_addr = &addr; - -#else - server_addr = NULL; - - ARG_UNUSED(addr); -#endif - - http_server_add_default(&http_urls, default_handler); - http_server_add_url(&http_urls, "/headers", HTTP_URL_STANDARD); - http_server_add_url(&http_urls, "/index.html", HTTP_URL_STANDARD); - http_server_add_url(&http_urls, "/", HTTP_URL_STANDARD); - - ret = http_server_init(&http_ctx, &http_urls, server_addr, http_result, - sizeof(http_result), "Zephyr HTTP Server", - NULL); - if (ret < 0) { - LOG_ERR("Cannot initialize HTTP server (%d)", ret); - panic(NULL); - } - -#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL) - net_app_set_net_pkt_pool(&http_ctx.app_ctx, tx_slab, data_pool); -#endif - - http_set_cb(&http_ctx, http_connected, http_received, - http_sent, http_closed); - -#if defined(CONFIG_HTTPS) - ret = http_server_set_tls(&http_ctx, - APP_BANNER, - INSTANCE_INFO, - strlen(INSTANCE_INFO), - setup_cert, - NULL, - &ssl_rx_pool, - https_stack, - K_THREAD_STACK_SIZEOF(https_stack)); - if (ret < 0) { - LOG_ERR("Cannot enable TLS support (%d)", ret); - } -#endif - - /* - * If needed, the HTTP parser callbacks can be set according to - * applications own needs before enabling the server. In this example - * we use the default callbacks defined in HTTP server API. - */ - - http_server_enable(&http_ctx); -} diff --git a/subsys/net/lib/http/CMakeLists.txt b/subsys/net/lib/http/CMakeLists.txt index 7d246a0a036..43aaf4162e1 100644 --- a/subsys/net/lib/http/CMakeLists.txt +++ b/subsys/net/lib/http/CMakeLists.txt @@ -6,11 +6,3 @@ endif() zephyr_library_sources_if_kconfig(http_parser.c) zephyr_library_sources_if_kconfig(http_parser_url.c) - -zephyr_library_sources_if_kconfig(http.c) - -zephyr_library_sources_ifdef(CONFIG_HTTP_SERVER http_server.c) -zephyr_library_sources_ifdef(CONFIG_HTTP_CLIENT http_client.c) - -zephyr_link_interface_ifdef(CONFIG_MBEDTLS mbedTLS) -zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) diff --git a/subsys/net/lib/http/Kconfig b/subsys/net/lib/http/Kconfig index a40d2124252..10d3d5c9264 100644 --- a/subsys/net/lib/http/Kconfig +++ b/subsys/net/lib/http/Kconfig @@ -3,84 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 # -config HTTP - bool "HTTP support" - help - This option enables the HTTP library - -if HTTP - -config HTTP_SERVER - bool "HTTP server support" - select HTTP_PARSER - select HTTP_PARSER_URL - select NET_APP_SERVER - help - Enables HTTP server routines. - -config HTTP_CLIENT - bool "HTTP client support" - select HTTP_PARSER - select HTTP_PARSER_URL - select NET_APP_CLIENT - help - Enables HTTP client routines. - -config HTTP_HEADERS - int "HTTP header field max number of items" - depends on HTTP_SERVER - default 20 if WEBSOCKET - default 8 - help - Number of HTTP header field items that an HTTP server - application will handle. If websocket is enabled, then the - default needs to be much bigger. - -config HTTPS - bool "HTTPS support" - select NET_APP_TLS - help - Enables HTTPS support. - -config HTTP_SERVER_CONNECTIONS - int "Max number of concurrent HTTP server connections" - default NET_APP_SERVER_NUM_CONN - depends on HTTP_SERVER - help - This value determines how many simultaneous HTTP connections the - HTTP server can serve. Note that only 1 HTTPS connection can be - served at a time, so set CONFIG_NET_APP_SERVER_NUM_CONN and - CONFIG_NET_TCP_BACKLOG_SIZE to 1 in that case. - -config HTTP_SERVER_NUM_URLS - int "Max number of URLs that the HTTP server will handle" - default 8 - depends on HTTP_SERVER - help - This value determines how many URLs this HTTP server can handle. - -config HTTP_CLIENT_NETWORK_TIMEOUT - int "Default network activity timeout in seconds" - default 20 - depends on HTTP_CLIENT - help - Default network activity timeout in seconds. This setting is used - for TCP connection timeout. - -module = HTTP -module-dep = NET_LOG -module-str = Log level for HTTP -module-help = Enables routing engine debug messages. -source "subsys/net/Kconfig.template.log_config.net" - -config NET_DEBUG_HTTP_CONN - bool "Debug HTTP connections" - depends on HTTP && NET_LOG - help - Enables HTTP connection tracking. - -endif # HTTP - config HTTP_PARSER bool "HTTP Parser support" select HTTP_PARSER_URL diff --git a/subsys/net/lib/http/http.c b/subsys/net/lib/http/http.c deleted file mode 100644 index 1425a1b1ad9..00000000000 --- a/subsys/net/lib/http/http.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(net_http, CONFIG_HTTP_LOG_LEVEL); - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -int http_set_cb(struct http_ctx *ctx, - http_connect_cb_t connect_cb, - http_recv_cb_t recv_cb, - http_send_cb_t send_cb, - http_close_cb_t close_cb) -{ - if (!ctx) { - return -EINVAL; - } - - if (!ctx->is_init) { - return -ENOENT; - } - - ctx->cb.connect = connect_cb; - ctx->cb.recv = recv_cb; - ctx->cb.send = send_cb; - ctx->cb.close = close_cb; - - return 0; -} - -int http_close(struct http_ctx *ctx) -{ - if (!ctx) { - return -EINVAL; - } - - if (!ctx->is_init) { - return -ENOENT; - } - - http_send_flush(ctx, NULL); - if (ctx->pending) { - net_pkt_unref(ctx->pending); - ctx->pending = NULL; - } - -#if defined(CONFIG_HTTP_SERVER) && defined(CONFIG_NET_DEBUG_HTTP_CONN) - if (!ctx->is_client) { - http_server_conn_del(ctx); - } -#endif - -#if defined(CONFIG_HTTP_SERVER) && defined(CONFIG_WEBSOCKET) - if (ctx->websocket.pending) { - net_pkt_unref(ctx->websocket.pending); - ctx->websocket.pending = NULL; - } - - ctx->websocket.data_waiting = 0; -#endif - - return net_app_close(&ctx->app_ctx); -} - -int http_release(struct http_ctx *ctx) -{ - if (!ctx) { - return -EINVAL; - } - - if (!ctx->is_init) { - return -ENOENT; - } - - ctx->is_tls = false; - -#if defined(CONFIG_HTTP_SERVER) && defined(CONFIG_NET_DEBUG_HTTP_CONN) - if (!ctx->is_client) { - http_server_conn_del(ctx); - http_server_disable(ctx); - } -#endif - - if (ctx->pending) { - net_pkt_unref(ctx->pending); - ctx->pending = NULL; - } - - ctx->is_init = false; - - return net_app_release(&ctx->app_ctx); -} - -int http_send_msg_raw(struct http_ctx *ctx, struct net_pkt *pkt, - void *user_send_data) -{ - int ret; - - NET_DBG("[%p] Sending %zd bytes data", ctx, net_pkt_get_len(pkt)); - - ret = net_app_send_pkt(&ctx->app_ctx, pkt, NULL, 0, 0, - user_send_data); - if (!ret) { - /* We must let the system to send the packet, otherwise TCP - * might timeout before the packet is actually sent. This is - * easily seen if the application calls this functions many - * times in a row. - */ - k_yield(); - } - - return ret; -} - -static inline struct net_pkt *get_net_pkt(struct http_ctx *ctx, - const struct sockaddr *dst) -{ - if (!dst) { - return net_app_get_net_pkt(&ctx->app_ctx, AF_UNSPEC, - ctx->timeout); - } - - return net_app_get_net_pkt_with_dst(&ctx->app_ctx, dst, ctx->timeout); -} - -int http_prepare_and_send(struct http_ctx *ctx, - const char *payload, - size_t payload_len, - const struct sockaddr *dst, - void *user_send_data) -{ - size_t added; - int ret; - - do { - if (!ctx->pending) { - ctx->pending = get_net_pkt(ctx, dst); - if (!ctx->pending) { - return -ENOMEM; - } - } - - ret = net_pkt_append(ctx->pending, payload_len, payload, - ctx->timeout); - if (!ret || ret > payload_len) { - ret = -EINVAL; - goto error; - } - - added = ret; - - payload_len -= added; - if (payload_len) { - payload += added; - /* Not all data could be added, send what we have now - * and allocate new stuff to be sent. - */ - ret = http_send_flush(ctx, user_send_data); - if (ret < 0) { - goto error; - } - } - } while (payload_len); - - return 0; - -error: - if (ctx->pending) { - net_pkt_unref(ctx->pending); - ctx->pending = NULL; - } - - return ret; -} - -int http_send_flush(struct http_ctx *ctx, void *user_send_data) -{ - int ret; - - if (!ctx->pending) { - return 0; - } - - ret = http_send_msg_raw(ctx, ctx->pending, user_send_data); - if (ret < 0) { - return ret; - } - - ctx->pending = NULL; - - return ret; -} - -int http_send_chunk(struct http_ctx *ctx, const char *buf, size_t len, - const struct sockaddr *dst, void *user_send_data) -{ - char chunk_header[16]; - int ret; - - if (!buf) { - len = 0; - } - - snprintk(chunk_header, sizeof(chunk_header), "%x" HTTP_CRLF, - (unsigned int)len); - - ret = http_prepare_and_send(ctx, chunk_header, strlen(chunk_header), - dst, user_send_data); - if (ret < 0) { - return ret; - } - - if (len) { - ret = http_prepare_and_send(ctx, buf, len, dst, user_send_data); - if (ret < 0) { - return ret; - } - } - - ret = http_prepare_and_send(ctx, HTTP_CRLF, sizeof(HTTP_CRLF) - 1, dst, - user_send_data); - if (ret < 0) { - return ret; - } - - return 0; -} - -static int _http_add_header(struct http_ctx *ctx, s32_t timeout, - const char *name, const char *value, - const struct sockaddr *dst, - void *user_send_data) -{ - int ret; - - ret = http_prepare_and_send(ctx, name, strlen(name), dst, - user_send_data); - if (value && ret >= 0) { - ret = http_prepare_and_send(ctx, ": ", strlen(": "), dst, - user_send_data); - if (ret < 0) { - goto out; - } - - ret = http_prepare_and_send(ctx, value, strlen(value), dst, - user_send_data); - if (ret < 0) { - goto out; - } - - ret = http_prepare_and_send(ctx, HTTP_CRLF, strlen(HTTP_CRLF), - dst, user_send_data); - if (ret < 0) { - goto out; - } - } - -out: - return ret; -} - -int http_add_header(struct http_ctx *ctx, const char *field, - const struct sockaddr *dst, - void *user_send_data) -{ - return _http_add_header(ctx, ctx->timeout, field, NULL, dst, - user_send_data); -} - -int http_add_header_field(struct http_ctx *ctx, const char *name, - const char *value, - const struct sockaddr *dst, - void *user_send_data) -{ - return _http_add_header(ctx, ctx->timeout, name, value, dst, - user_send_data); -} diff --git a/subsys/net/lib/http/http_client.c b/subsys/net/lib/http/http_client.c deleted file mode 100644 index f4ba860d536..00000000000 --- a/subsys/net/lib/http/http_client.c +++ /dev/null @@ -1,739 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_DECLARE(net_http, CONFIG_HTTP_LOG_LEVEL); - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "../../ip/net_private.h" - -#define BUF_ALLOC_TIMEOUT 100 - -#define RC_STR(rc) (rc == 0 ? "OK" : "ERROR") - -#define HTTP_EOF "\r\n\r\n" - -#define HTTP_HOST "Host" -#define HTTP_CONTENT_TYPE "Content-Type" -#define HTTP_CONTENT_LEN "Content-Length" -#define HTTP_CONT_LEN_SIZE 6 - -/* Default network activity timeout in seconds */ -#define HTTP_NETWORK_TIMEOUT K_SECONDS(CONFIG_HTTP_CLIENT_NETWORK_TIMEOUT) - -int client_reset(struct http_ctx *ctx) -{ - http_parser_init(&ctx->http.parser, HTTP_RESPONSE); - - (void)memset(ctx->http.rsp.http_status, 0, - sizeof(ctx->http.rsp.http_status)); - - ctx->http.rsp.cl_present = 0; - ctx->http.rsp.content_length = 0; - ctx->http.rsp.processed = 0; - ctx->http.rsp.body_found = 0; - ctx->http.rsp.message_complete = 0; - ctx->http.rsp.body_start = NULL; - - (void)memset(ctx->http.rsp.response_buf, 0, - ctx->http.rsp.response_buf_len); - ctx->http.rsp.data_len = 0; - - return 0; -} - -int http_request(struct http_ctx *ctx, struct http_request *req, s32_t timeout, - void *user_data) -{ - const char *method = http_method_str(req->method); - int ret; - - if (ctx->pending) { - net_pkt_unref(ctx->pending); - ctx->pending = NULL; - } - - ret = http_add_header(ctx, method, NULL, user_data); - if (ret < 0) { - goto out; - } - - ret = http_add_header(ctx, " ", NULL, user_data); - if (ret < 0) { - goto out; - } - - ret = http_add_header(ctx, req->url, NULL, user_data); - if (ret < 0) { - goto out; - } - - ret = http_add_header(ctx, req->protocol, NULL, user_data); - if (ret < 0) { - goto out; - } - - ret = http_add_header(ctx, HTTP_CRLF, NULL, user_data); - if (ret < 0) { - goto out; - } - - if (req->host) { - ret = http_add_header_field(ctx, HTTP_HOST, req->host, - NULL, user_data); - if (ret < 0) { - goto out; - } - } - - if (req->header_fields) { - ret = http_add_header(ctx, req->header_fields, NULL, user_data); - if (ret < 0) { - goto out; - } - } - - if (req->content_type_value) { - ret = http_add_header_field(ctx, HTTP_CONTENT_TYPE, - req->content_type_value, - NULL, user_data); - if (ret < 0) { - goto out; - } - } - - if (req->payload && req->payload_size) { - char content_len_str[HTTP_CONT_LEN_SIZE]; - - ret = snprintk(content_len_str, HTTP_CONT_LEN_SIZE, - "%u", req->payload_size); - if (ret <= 0 || ret >= HTTP_CONT_LEN_SIZE) { - ret = -ENOMEM; - goto out; - } - - ret = http_add_header_field(ctx, HTTP_CONTENT_LEN, - content_len_str, - NULL, user_data); - if (ret < 0) { - goto out; - } - - ret = http_add_header(ctx, HTTP_CRLF, NULL, user_data); - if (ret < 0) { - goto out; - } - - ret = http_prepare_and_send(ctx, req->payload, - req->payload_size, - NULL, user_data); - if (ret < 0) { - goto out; - } - } else { - ret = http_add_header(ctx, HTTP_EOF, NULL, user_data); - if (ret < 0) { - goto out; - } - } - - http_send_flush(ctx, user_data); - -out: - if (ctx->pending) { - net_pkt_unref(ctx->pending); - ctx->pending = NULL; - } - - return ret; -} - -static void sprint_addr(char *buf, int len, - sa_family_t family, - struct sockaddr *addr) -{ - if (family == AF_INET6) { - net_addr_ntop(AF_INET6, &net_sin6(addr)->sin6_addr, buf, len); - } else if (family == AF_INET) { - net_addr_ntop(AF_INET, &net_sin(addr)->sin_addr, buf, len); - } else { - NET_DBG("Invalid protocol family"); - } -} - -static inline void print_info(struct http_ctx *ctx, - enum http_method method) -{ - if (CONFIG_HTTP_LOG_LEVEL >= LOG_LEVEL_INF) { - char local[NET_IPV6_ADDR_LEN]; - char remote[NET_IPV6_ADDR_LEN]; - - sprint_addr(local, NET_IPV6_ADDR_LEN, - ctx->app_ctx.default_ctx->local.sa_family, - &ctx->app_ctx.default_ctx->local); - - sprint_addr(remote, NET_IPV6_ADDR_LEN, - ctx->app_ctx.default_ctx->remote.sa_family, - &ctx->app_ctx.default_ctx->remote); - - NET_DBG("HTTP %s (%s) %s -> %s port %d", - http_method_str(method), - log_strdup(ctx->http.req.host), log_strdup(local), - log_strdup(remote), - ntohs(net_sin(&ctx->app_ctx.default_ctx->remote)-> - sin_port)); - } -} - -int http_client_send_req(struct http_ctx *ctx, - struct http_request *req, - http_response_cb_t cb, - u8_t *response_buf, - size_t response_buf_len, - void *user_data, - s32_t timeout) -{ - int ret; - - if (!response_buf || response_buf_len == 0) { - return -EINVAL; - } - - ctx->http.rsp.response_buf = response_buf; - ctx->http.rsp.response_buf_len = response_buf_len; - - client_reset(ctx); - - if (!req->host) { - req->host = ctx->server; - } - - ctx->http.req.host = req->host; - ctx->http.req.method = req->method; - ctx->http.req.user_data = user_data; - - ctx->http.rsp.cb = cb; - - ret = net_app_connect(&ctx->app_ctx, HTTP_NETWORK_TIMEOUT); - if (ret < 0) { - NET_DBG("Cannot connect to server (%d)", ret); - return ret; - } - - /* We might wait longer than timeout if the first connection - * establishment takes long time (like with HTTPS) - */ - if (k_sem_take(&ctx->http.connect_wait, HTTP_NETWORK_TIMEOUT)) { - NET_DBG("Connection timed out"); - ret = -ETIMEDOUT; - goto out; - } - - print_info(ctx, ctx->http.req.method); - - ret = http_request(ctx, req, timeout, user_data); - if (ret < 0) { - NET_DBG("Send error (%d)", ret); - goto out; - } - - if (timeout != 0 && k_sem_take(&ctx->http.req.wait, timeout)) { - ret = -ETIMEDOUT; - goto out; - } - - if (timeout == 0) { - return -EINPROGRESS; - } - - return 0; - -out: - return ret; -} - -static void print_header_field(size_t len, const char *str) -{ - if (CONFIG_HTTP_LOG_LEVEL >= LOG_LEVEL_INF) { -#define MAX_OUTPUT_LEN 128 - char output[MAX_OUTPUT_LEN]; - - /* The value of len does not count \0 so we need to increase it - * by one. - */ - if ((len + 1) > sizeof(output)) { - len = sizeof(output) - 1; - } - - snprintk(output, len + 1, "%s", str); - - NET_DBG("[%zd] %s", len, log_strdup(output)); - } -} - -static int on_url(struct http_parser *parser, const char *at, size_t length) -{ - ARG_UNUSED(parser); - - print_header_field(length, at); - - return 0; -} - -static int on_status(struct http_parser *parser, const char *at, size_t length) -{ - u16_t len; - struct http_ctx *ctx = CONTAINER_OF(parser, - struct http_ctx, - http.parser); - - len = min(length, sizeof(ctx->http.rsp.http_status) - 1); - memcpy(ctx->http.rsp.http_status, at, len); - ctx->http.rsp.http_status[len] = 0; - - NET_DBG("HTTP response status %s", - log_strdup(ctx->http.rsp.http_status)); - - return 0; -} - -static int on_header_field(struct http_parser *parser, const char *at, - size_t length) -{ - const char *content_len = HTTP_CONTENT_LEN; - struct http_ctx *ctx = CONTAINER_OF(parser, - struct http_ctx, - http.parser); - u16_t len; - - len = strlen(content_len); - if (length >= len && memcmp(at, content_len, len) == 0) { - ctx->http.rsp.cl_present = true; - } - - print_header_field(length, at); - - return 0; -} - -#define MAX_NUM_DIGITS 16 - -static int on_header_value(struct http_parser *parser, const char *at, - size_t length) -{ - char str[MAX_NUM_DIGITS]; - struct http_ctx *ctx = CONTAINER_OF(parser, - struct http_ctx, - http.parser); - - if (ctx->http.rsp.cl_present) { - if (length <= MAX_NUM_DIGITS - 1) { - long int num; - - memcpy(str, at, length); - str[length] = 0; - - num = strtol(str, NULL, 10); - if (num == LONG_MIN || num == LONG_MAX) { - return -EINVAL; - } - - ctx->http.rsp.content_length = num; - } - - ctx->http.rsp.cl_present = false; - } - - print_header_field(length, at); - - return 0; -} - -static int on_body(struct http_parser *parser, const char *at, size_t length) -{ - struct http_ctx *ctx = CONTAINER_OF(parser, - struct http_ctx, - http.parser); - - ctx->http.rsp.body_found = 1; - ctx->http.rsp.processed += length; - - NET_DBG("Processed %zd length %zd", ctx->http.rsp.processed, length); - - if (!ctx->http.rsp.body_start && - (u8_t *)at != (u8_t *)ctx->http.rsp.response_buf) { - ctx->http.rsp.body_start = (u8_t *)at; - } - - if (ctx->http.rsp.cb) { - NET_DBG("Calling callback for partitioned %zd len data", - ctx->http.rsp.data_len); - - ctx->http.rsp.cb(ctx, - ctx->http.rsp.response_buf, - ctx->http.rsp.response_buf_len, - ctx->http.rsp.data_len, - HTTP_DATA_MORE, - ctx->http.req.user_data); - - /* Re-use the result buffer and start to fill it again */ - ctx->http.rsp.data_len = 0; - ctx->http.rsp.body_start = NULL; - } - - return 0; -} - -static int on_headers_complete(struct http_parser *parser) -{ - struct http_ctx *ctx = CONTAINER_OF(parser, - struct http_ctx, - http.parser); - - if (parser->status_code >= 500 && parser->status_code < 600) { - NET_DBG("Status %d, skipping body", parser->status_code); - - return 1; - } - - if ((ctx->http.req.method == HTTP_HEAD || - ctx->http.req.method == HTTP_OPTIONS) - && ctx->http.rsp.content_length > 0) { - NET_DBG("No body expected"); - return 1; - } - - if ((ctx->http.req.method == HTTP_PUT || - ctx->http.req.method == HTTP_POST) - && ctx->http.rsp.content_length == 0) { - NET_DBG("No body expected"); - return 1; - } - - NET_DBG("Headers complete"); - - return 0; -} - -static int on_message_begin(struct http_parser *parser) -{ - if (CONFIG_HTTP_LOG_LEVEL >= LOG_LEVEL_INF) { - struct http_ctx *ctx = CONTAINER_OF(parser, - struct http_ctx, - http.parser); - - NET_DBG("-- HTTP %s response (headers) --", - http_method_str(ctx->http.req.method)); - } - - return 0; -} - -static int on_message_complete(struct http_parser *parser) -{ - struct http_ctx *ctx = CONTAINER_OF(parser, - struct http_ctx, - http.parser); - - NET_DBG("-- HTTP %s response (complete) --", - http_method_str(ctx->http.req.method)); - - if (ctx->http.rsp.cb) { - ctx->http.rsp.cb(ctx, - ctx->http.rsp.response_buf, - ctx->http.rsp.response_buf_len, - ctx->http.rsp.data_len, - HTTP_DATA_FINAL, - ctx->http.req.user_data); - } - - ctx->http.rsp.message_complete = 1; - - k_sem_give(&ctx->http.req.wait); - - return 0; -} - -static int on_chunk_header(struct http_parser *parser) -{ - ARG_UNUSED(parser); - - return 0; -} - -static int on_chunk_complete(struct http_parser *parser) -{ - ARG_UNUSED(parser); - - return 0; -} - -static void http_received(struct net_app_ctx *app_ctx, - struct net_pkt *pkt, - int status, - void *user_data) -{ - struct http_ctx *ctx = user_data; - size_t start = ctx->http.rsp.data_len; - u16_t len = 0U; - struct net_buf *frag, *prev_frag = NULL; - size_t recv_len; - size_t pkt_len; - - recv_len = net_pkt_appdatalen(pkt); - if (recv_len == 0) { - /* don't print info about zero-length app data buffers */ - goto quit; - } - - if (status) { - NET_DBG("[%p] Status %d <%s>", ctx, status, RC_STR(status)); - goto out; - } - - /* Get rid of possible IP headers in the first fragment. */ - frag = pkt->frags; - - pkt_len = net_pkt_get_len(pkt); - - if (recv_len < pkt_len) { - net_buf_pull(frag, pkt_len - recv_len); - net_pkt_set_appdata(pkt, frag->data); - } - - NET_DBG("[%p] Received %zd bytes http data", ctx, recv_len); - - while (frag) { - /* If this fragment cannot be copied to result buf, - * then parse what we have which will cause the callback to be - * called in function on_body(), and continue copying. - */ - if ((ctx->http.rsp.data_len + frag->len) > - ctx->http.rsp.response_buf_len) { - - /* If the caller has not supplied a callback, then - * we cannot really continue if the request buffer - * overflows. Set the data_len to mark how many bytes - * should be needed in the response_buf. - */ - if (!ctx->cb.recv) { - ctx->http.rsp.data_len = recv_len; - goto out; - } - - http_parser_execute(&ctx->http.parser, - &ctx->http.parser_settings, - ctx->http.rsp.response_buf + start, - len); - - ctx->http.rsp.data_len = 0; - len = 0U; - start = 0; - } - - memcpy(ctx->http.rsp.response_buf + ctx->http.rsp.data_len, - frag->data, frag->len); - - ctx->http.rsp.data_len += frag->len; - len += frag->len; - - prev_frag = frag; - frag = frag->frags; - pkt->frags = frag; - - prev_frag->frags = NULL; - net_pkt_frag_unref(prev_frag); - } - -out: - http_parser_execute(&ctx->http.parser, - &ctx->http.parser_settings, - ctx->http.rsp.response_buf + start, - len); - - net_pkt_unref(pkt); - return; - -quit: - http_parser_init(&ctx->http.parser, HTTP_RESPONSE); - ctx->http.rsp.data_len = 0; - net_pkt_unref(pkt); -} - -static void http_data_sent(struct net_app_ctx *app_ctx, - int status, - void *user_data_send, - void *user_data) -{ - struct http_ctx *ctx = user_data; - - if (!user_data_send) { - /* This is the token field in the net_context_send(). - * If this is not set, then it is TCP ACK messages - * that are generated by the stack. We just ignore those. - */ - return; - } - - if (ctx->cb.send) { - ctx->cb.send(ctx, status, user_data_send, ctx->user_data); - } -} - -static void http_connected(struct net_app_ctx *app_ctx, - int status, - void *user_data) -{ - struct http_ctx *ctx = user_data; - - if (status < 0) { - return; - } - - if (ctx->cb.connect && app_ctx->default_ctx) { - ctx->cb.connect(ctx, HTTP_CONNECTION, - &app_ctx->default_ctx->remote, - ctx->user_data); - } - - if (ctx->is_connected) { - return; - } - - ctx->is_connected = true; - - k_sem_give(&ctx->http.connect_wait); -} - -static void http_closed(struct net_app_ctx *app_ctx, - int status, - void *user_data) -{ - struct http_ctx *ctx = user_data; - - ARG_UNUSED(app_ctx); - ARG_UNUSED(status); - - NET_DBG("[%p] connection closed", ctx); - - ctx->is_connected = false; - - if (ctx->cb.close) { - ctx->cb.close(ctx, 0, ctx->user_data); - } -} - -int http_client_init(struct http_ctx *ctx, - const char *server, - u16_t server_port, - struct sockaddr *server_addr, - s32_t timeout) -{ - int ret; - - (void)memset(ctx, 0, sizeof(*ctx)); - - ret = net_app_init_tcp_client(&ctx->app_ctx, - NULL, /* use any local address */ - server_addr, - server, - server_port, - timeout, - ctx); - if (ret < 0) { - NET_DBG("Cannot init HTTP client (%d)", ret); - return ret; - } - - ret = net_app_set_cb(&ctx->app_ctx, http_connected, http_received, - http_data_sent, http_closed); - if (ret < 0) { - NET_ERR("Cannot set callbacks (%d)", ret); - return ret; - } - - ctx->http.parser_settings.on_body = on_body; - ctx->http.parser_settings.on_chunk_complete = on_chunk_complete; - ctx->http.parser_settings.on_chunk_header = on_chunk_header; - ctx->http.parser_settings.on_headers_complete = on_headers_complete; - ctx->http.parser_settings.on_header_field = on_header_field; - ctx->http.parser_settings.on_header_value = on_header_value; - ctx->http.parser_settings.on_message_begin = on_message_begin; - ctx->http.parser_settings.on_message_complete = on_message_complete; - ctx->http.parser_settings.on_status = on_status; - ctx->http.parser_settings.on_url = on_url; - - k_sem_init(&ctx->http.req.wait, 0, 1); - k_sem_init(&ctx->http.connect_wait, 0, 1); - - ctx->server = server; - ctx->is_init = true; - ctx->is_client = true; - - return 0; -} - -int http_request_cancel(struct http_ctx *ctx) -{ - if (!ctx->is_init) { - return -EINVAL; - } - - if (!ctx->is_client) { - return -EINVAL; - } - - client_reset(ctx); - - return 0; -} - -#if defined(CONFIG_HTTPS) -int http_client_set_tls(struct http_ctx *ctx, - u8_t *request_buf, - size_t request_buf_len, - u8_t *personalization_data, - size_t personalization_data_len, - net_app_ca_cert_cb_t cert_cb, - const char *cert_host, - net_app_entropy_src_cb_t entropy_src_cb, - struct k_mem_pool *pool, - k_thread_stack_t *https_stack, - size_t https_stack_size) -{ - int ret; - - ret = net_app_client_tls(&ctx->app_ctx, - request_buf, - request_buf_len, - personalization_data, - personalization_data_len, - cert_cb, - cert_host, - entropy_src_cb, - pool, - https_stack, - https_stack_size); - if (ret < 0) { - NET_DBG("Cannot init TLS (%d)", ret); - return ret; - } - - ctx->is_tls = true; - - return 0; -} -#endif /* CONFIG_HTTPS */ diff --git a/subsys/net/lib/http/http_server.c b/subsys/net/lib/http/http_server.c deleted file mode 100644 index 2e6f7223684..00000000000 --- a/subsys/net/lib/http/http_server.c +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_DECLARE(net_http, CONFIG_HTTP_LOG_LEVEL); - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(CONFIG_WEBSOCKET) -#include -#include "../websocket/websocket_internal.h" -#endif - -#define BUF_ALLOC_TIMEOUT 100 - -#define HTTP_DEFAULT_PORT 80 -#define HTTPS_DEFAULT_PORT 443 - -#define RC_STR(rc) (rc == 0 ? "OK" : "ERROR") - -#define HTTP_STATUS_400_BR "HTTP/1.1 400 Bad Request\r\n" \ - "\r\n" -#define HTTP_STATUS_500_BR "HTTP/1.1 500 Internal Server Error\r\n" \ - "\r\n" - -#if defined(CONFIG_NET_DEBUG_HTTP_CONN) -/** List of http connections */ -static sys_slist_t http_conn; - -static http_server_cb_t ctx_mon; -static void *mon_user_data; - -void http_server_conn_add(struct http_ctx *ctx) -{ - sys_slist_prepend(&http_conn, &ctx->node); - - if (ctx_mon) { - ctx_mon(ctx, mon_user_data); - } -} - -void http_server_conn_del(struct http_ctx *ctx) -{ - sys_slist_find_and_remove(&http_conn, &ctx->node); -} - -void http_server_conn_foreach(http_server_cb_t cb, void *user_data) -{ - struct http_ctx *ctx; - - SYS_SLIST_FOR_EACH_CONTAINER(&http_conn, ctx, node) { - cb(ctx, user_data); - } -} - -void http_server_conn_monitor(http_server_cb_t cb, void *user_data) -{ - ctx_mon = cb; - mon_user_data = user_data; -} -#endif /* CONFIG_NET_DEBUG_HTTP_CONN */ - -const char * const http_state_str(enum http_state state) -{ -#if CONFIG_HTTP_LOG_LEVEL >= LOG_LEVEL_DBG - switch (state) { - case HTTP_STATE_CLOSED: - return "CLOSED"; - case HTTP_STATE_WAITING_HEADER: - return "WAITING_HEADER"; - case HTTP_STATE_RECEIVING_HEADER: - return "RECEIVING HEADER"; - case HTTP_STATE_HEADER_RECEIVED: - return "HEADER_RECEIVED"; - case HTTP_STATE_OPEN: - return "OPEN"; - } -#else - ARG_UNUSED(state); -#endif - - return ""; -} - -#if CONFIG_HTTP_LOG_LEVEL >= LOG_LEVEL_DBG -static void validate_state_transition(struct http_ctx *ctx, - enum http_state current, - enum http_state new) -{ - static const u16_t valid_transitions[] = { - [HTTP_STATE_CLOSED] = 1 << HTTP_STATE_WAITING_HEADER, - [HTTP_STATE_WAITING_HEADER] = - 1 << HTTP_STATE_RECEIVING_HEADER | - 1 << HTTP_STATE_CLOSED, - [HTTP_STATE_RECEIVING_HEADER] = - 1 << HTTP_STATE_HEADER_RECEIVED | - 1 << HTTP_STATE_CLOSED | - 1 << HTTP_STATE_OPEN, - [HTTP_STATE_HEADER_RECEIVED] = - 1 << HTTP_STATE_OPEN | - 1 << HTTP_STATE_CLOSED, - [HTTP_STATE_OPEN] = 1 << HTTP_STATE_CLOSED, - }; - - if (!(valid_transitions[current] & 1 << new)) { - NET_DBG("[%p] Invalid state transition: %s (%d) => %s (%d)", - ctx, http_state_str(current), current, - http_state_str(new), new); - } -} -#endif /* CONFIG_HTTP_LOG_LEVEL */ - -void _http_change_state(struct http_ctx *ctx, - enum http_state new_state, - const char *func, int line) -{ - if (ctx->state == new_state) { - return; - } - - NET_ASSERT(new_state >= HTTP_STATE_CLOSED && - new_state <= HTTP_STATE_OPEN); - - NET_DBG("[%p] state %s (%d) => %s (%d) [%s():%d]", - ctx, http_state_str(ctx->state), ctx->state, - http_state_str(new_state), new_state, - func, line); - -#if CONFIG_HTTP_LOG_LEVEL >= LOG_LEVEL_DBG - validate_state_transition(ctx, ctx->state, new_state); -#endif - - ctx->state = new_state; -} - -static void http_data_sent(struct net_app_ctx *app_ctx, - int status, - void *user_data_send, - void *user_data) -{ - struct http_ctx *ctx = user_data; - - if (!user_data_send) { - /* This is the token field in the net_context_send(). - * If this is not set, then it is TCP ACK messages - * that are generated by the stack. We just ignore those. - */ - return; - } - - if (ctx->state == HTTP_STATE_OPEN && ctx->cb.send) { - ctx->cb.send(ctx, status, user_data_send, ctx->user_data); - } -} - -int http_send_error(struct http_ctx *ctx, int code, - u8_t *html_payload, size_t html_len, - const struct sockaddr *dst) -{ - const char *msg; - int ret; - - if (ctx->pending) { - net_pkt_unref(ctx->pending); - ctx->pending = NULL; - } - - switch (code) { - case 400: - msg = HTTP_STATUS_400_BR; - break; - default: - msg = HTTP_STATUS_500_BR; - break; - } - - ret = http_add_header(ctx, msg, dst, NULL); - if (ret < 0) { - goto quit; - } - - if (html_payload) { - ret = http_prepare_and_send(ctx, html_payload, html_len, dst, - NULL); - if (ret < 0) { - goto quit; - } - } - - ret = http_send_flush(ctx, NULL); - -quit: - if (ret < 0) { - net_pkt_unref(ctx->pending); - ctx->pending = NULL; - } - - return ret; -} - -#if CONFIG_HTTP_LOG_LEVEL >= LOG_LEVEL_INF -static char *sprint_ipaddr(char *buf, int buflen, const struct sockaddr *addr) -{ - if (addr->sa_family == AF_INET6) { -#if defined(CONFIG_NET_IPV6) - char ipaddr[NET_IPV6_ADDR_LEN]; - - net_addr_ntop(addr->sa_family, - &net_sin6(addr)->sin6_addr, - ipaddr, sizeof(ipaddr)); - snprintk(buf, buflen, "[%s]:%u", ipaddr, - ntohs(net_sin6(addr)->sin6_port)); -#endif - } else if (addr->sa_family == AF_INET) { -#if defined(CONFIG_NET_IPV4) - char ipaddr[NET_IPV4_ADDR_LEN]; - - net_addr_ntop(addr->sa_family, - &net_sin(addr)->sin_addr, - ipaddr, sizeof(ipaddr)); - snprintk(buf, buflen, "%s:%u", ipaddr, - ntohs(net_sin(addr)->sin_port)); -#endif - } else { - snprintk(buf, buflen, "", addr->sa_family); - } - - return buf; -} - -static struct net_context *get_server_ctx(struct net_app_ctx *ctx, - const struct sockaddr *dst) -{ - int i; - - if (!dst) { - return NULL; - } - - for (i = 0; i < CONFIG_NET_APP_SERVER_NUM_CONN; i++) { - struct net_context *tmp; - u16_t port, rport; - - if (!ctx->server.net_ctxs[i]) { - continue; - } - - tmp = ctx->server.net_ctxs[i]; - - if (IS_ENABLED(CONFIG_NET_IPV4) && - tmp->remote.sa_family == AF_INET && - dst->sa_family == AF_INET) { - struct in_addr *addr4 = &net_sin(dst)->sin_addr; - struct in_addr *remote4; - - remote4 = &net_sin(&tmp->remote)->sin_addr; - rport = net_sin(&tmp->remote)->sin_port; - port = net_sin(dst)->sin_port; - - if (net_ipv4_addr_cmp(addr4, remote4) && - port == rport) { - return tmp; - } - - } else if (IS_ENABLED(CONFIG_NET_IPV6) && - tmp->remote.sa_family == AF_INET6 && - dst->sa_family == AF_INET6) { - struct in6_addr *addr6 = &net_sin6(dst)->sin6_addr; - struct in6_addr *remote6; - - remote6 = &net_sin6(&tmp->remote)->sin6_addr; - rport = net_sin6(&tmp->remote)->sin6_port; - port = net_sin6(dst)->sin6_port; - - if (net_ipv6_addr_cmp(addr6, remote6) && - port == rport) { - return tmp; - } - } - } - - return NULL; -} -#endif /* CONFIG_HTTP_LOG_LEVEL */ - -static inline void new_client(struct http_ctx *ctx, - enum http_connection_type type, - struct net_app_ctx *app_ctx, - const struct sockaddr *dst) -{ -#if CONFIG_HTTP_LOG_LEVEL >= LOG_LEVEL_INF -#if defined(CONFIG_NET_IPV6) -#define PORT_LEN sizeof("[]:xxxxx") -#define ADDR_LEN NET_IPV6_ADDR_LEN -#elif defined(CONFIG_NET_IPV4) -#define PORT_LEN sizeof(":xxxxx") -#define ADDR_LEN NET_IPV4_ADDR_LEN -#endif - char buf[ADDR_LEN + PORT_LEN]; - struct net_context *net_ctx; - const char *type_str = "HTTP"; - - if (type == WS_CONNECTION) { - type_str = "WS"; - } - - net_ctx = get_server_ctx(app_ctx, dst); - if (net_ctx) { - NET_INFO("[%p] %s connection from %s (%p)", ctx, type_str, - sprint_ipaddr(buf, sizeof(buf), &net_ctx->remote), - net_ctx); - } else { - NET_INFO("[%p] %s connection", ctx, type_str); - } -#endif /* CONFIG_HTTP_LOG_LEVEL */ -} - -static void url_connected(struct http_ctx *ctx, - enum http_connection_type type, - const struct sockaddr *dst) -{ - new_client(ctx, type, &ctx->app_ctx, dst); - - if (ctx->cb.connect) { - ctx->cb.connect(ctx, type, dst, ctx->user_data); - } -} - -struct http_root_url *http_server_add_url(struct http_server_urls *my, - const char *url, u8_t flags) -{ - int i; - - for (i = 0; i < CONFIG_HTTP_SERVER_NUM_URLS; i++) { - if (my->urls[i].is_used) { - continue; - } - - my->urls[i].is_used = true; - my->urls[i].root = url; - - /* This will speed-up some future operations */ - my->urls[i].root_len = strlen(url); - my->urls[i].flags = flags; - - NET_DBG("[%d] %s URL %s", i, - flags == HTTP_URL_STANDARD ? "HTTP" : - (flags == HTTP_URL_WEBSOCKET ? "WS" : ""), - url); - - return &my->urls[i]; - } - - return NULL; -} - -int http_server_del_url(struct http_server_urls *my, const char *url) -{ - int i; - - for (i = 0; i < CONFIG_HTTP_SERVER_NUM_URLS; i++) { - if (!my->urls[i].is_used) { - continue; - } - - if (strncmp(my->urls[i].root, url, my->urls[i].root_len)) { - continue; - } - - my->urls[i].is_used = false; - my->urls[i].root = NULL; - - return 0; - } - - return -ENOENT; -} - -struct http_root_url *http_server_add_default(struct http_server_urls *my, - http_url_cb_t cb) -{ - if (my->default_url.is_used) { - return NULL; - } - - my->default_url.is_used = true; - my->default_url.root = NULL; - my->default_url.root_len = 0; - my->default_url.flags = 0; - my->default_cb = cb; - - return &my->default_url; -} - -int http_server_del_default(struct http_server_urls *my) -{ - if (!my->default_url.is_used) { - return -ENOENT; - } - - my->default_url.is_used = false; - - return 0; -} - -static int http_url_cmp(const char *url, u16_t url_len, - const char *root_url, u16_t root_url_len) -{ - if (url_len < root_url_len) { - return -EINVAL; - } - - if (memcmp(url, root_url, root_url_len) == 0) { - if (url_len == root_url_len) { - return 0; - } - - /* Here we evaluate the following conditions: - * root_url = /images, url = /images/ -> OK - * root_url = /images/, url = /images/img.png -> OK - * root_url = /images/, url = /images_and_docs -> ERROR - */ - if (url_len > root_url_len) { - /* Do not match root_url = / and url = /foobar */ - if (root_url_len > 1 && - root_url[root_url_len - 1] == '/') { - return 0; - } - - if (url[root_url_len] == '/') { - return 0; - } - } - } - - return -EINVAL; -} - -struct http_root_url *http_url_find(struct http_ctx *ctx, - enum http_url_flags flags) -{ - u16_t url_len = ctx->http.url_len; - const char *url = ctx->http.url; - struct http_root_url *root_url; - u8_t i; - int ret; - - for (i = 0U; i < CONFIG_HTTP_SERVER_NUM_URLS; i++) { - if (!ctx->http.urls) { - continue; - } - - root_url = &ctx->http.urls->urls[i]; - if (!root_url || !root_url->is_used) { - continue; - } - - ret = http_url_cmp(url, url_len, - root_url->root, root_url->root_len); - if (!ret && flags == root_url->flags) { - return root_url; - } - } - - return NULL; -} - -static int http_process_recv(struct http_ctx *ctx, - const struct sockaddr *dst) -{ - struct http_root_url *root_url; - int ret; - - root_url = http_url_find(ctx, HTTP_URL_STANDARD); - if (!root_url) { - if (!ctx->http.urls) { - NET_DBG("[%p] No URL handlers found", ctx); - ret = -ENOENT; - goto out; - } - - root_url = &ctx->http.urls->default_url; - if (!root_url || !root_url->is_used) { - NET_DBG("[%p] No default handler found", ctx); - ret = -ENOENT; - goto out; - } - - if (ctx->http.urls->default_cb) { - ret = ctx->http.urls->default_cb(ctx, - HTTP_CONNECTION, - dst); - if (ret != HTTP_VERDICT_ACCEPT) { - ret = -ECONNREFUSED; - goto out; - } - } - } - - http_change_state(ctx, HTTP_STATE_OPEN); - url_connected(ctx, HTTP_CONNECTION, dst); - - ret = 0; - -out: - return ret; -} - -static void http_closed(struct net_app_ctx *app_ctx, - int status, - void *user_data) -{ - struct http_ctx *ctx = user_data; - - ARG_UNUSED(app_ctx); - ARG_UNUSED(status); - - http_change_state(ctx, HTTP_STATE_CLOSED); - - NET_DBG("[%p] http closed", ctx); - - http_server_conn_del(ctx); - - if (ctx->cb.close) { - ctx->cb.close(ctx, 0, ctx->user_data); - } - -#if defined(CONFIG_WEBSOCKET) - if (ctx->websocket.pending) { - net_pkt_unref(ctx->websocket.pending); - ctx->websocket.pending = NULL; - } - - ctx->websocket.data_waiting = 0; -#endif - - ctx->http.field_values_ctr = 0; -} - -static void http_received(struct net_app_ctx *app_ctx, - struct net_pkt *pkt, - int status, - void *user_data) -{ - struct http_ctx *ctx = user_data; - size_t start = ctx->http.data_len; - u16_t len = 0U; - const struct sockaddr *dst = NULL; - struct net_buf *frag; - int parsed_len; - size_t recv_len; - size_t pkt_len; - - recv_len = net_pkt_appdatalen(pkt); - if (recv_len == 0) { - /* don't print info about zero-length app data buffers */ - goto quit; - } - - if (status) { - NET_DBG("[%p] Status %d <%s>", ctx, status, RC_STR(status)); - goto out; - } - - /* Get rid of possible IP headers in the first fragment. */ - frag = pkt->frags; - - pkt_len = net_pkt_get_len(pkt); - - if (recv_len < pkt_len) { - net_buf_pull(frag, pkt_len - recv_len); - net_pkt_set_appdata(pkt, frag->data); - } - - NET_DBG("[%p] Received %zd bytes http data", ctx, recv_len); - - if (net_pkt_context(pkt)) { - ctx->http.parser.addr = &net_pkt_context(pkt)->remote; - dst = &net_pkt_context(pkt)->remote; - } - - if (ctx->state == HTTP_STATE_OPEN) { - /* We have active websocket session and there is no longer - * any HTTP traffic in the connection. Give the data to - * application. - */ - goto ws_only; - } - - while (frag) { - /* If this fragment cannot be copied to result buf, - * then parse what we have which will cause the callback to be - * called in function on_body(), and continue copying. - */ - if ((ctx->http.data_len + frag->len) > - ctx->http.request_buf_len) { - - if (ctx->state == HTTP_STATE_HEADER_RECEIVED) { - goto ws_ready; - } - - /* If the caller has not supplied a callback, then - * we cannot really continue if the request buffer - * overflows. Set the data_len to mark how many bytes - * should be needed in the response_buf. - */ - if (http_process_recv(ctx, dst) < 0) { - ctx->http.data_len = recv_len; - goto out; - } - - parsed_len = - http_parser_execute(&ctx->http.parser, - &ctx->http.parser_settings, - ctx->http.request_buf + - start, - len); - if (parsed_len <= 0) { - goto fail; - } - - ctx->http.data_len = 0; - len = 0U; - start = 0; - } - - memcpy(ctx->http.request_buf + ctx->http.data_len, - frag->data, frag->len); - - ctx->http.data_len += frag->len; - len += frag->len; - frag = frag->frags; - } - -out: - parsed_len = http_parser_execute(&ctx->http.parser, - &ctx->http.parser_settings, - ctx->http.request_buf + start, - len); - if (parsed_len < 0) { -fail: - NET_DBG("[%p] Received %zd bytes, only parsed %d " - "bytes (%s %s)", - ctx, recv_len, parsed_len, - http_errno_name(ctx->http.parser.http_errno), - http_errno_description( - ctx->http.parser.http_errno)); - } - - if (ctx->http.parser.http_errno != HPE_OK) { - http_send_error(ctx, 400, NULL, 0, dst); - } else { - if (ctx->state == HTTP_STATE_HEADER_RECEIVED) { - goto ws_ready; - } - - http_process_recv(ctx, dst); - } - -quit: - http_parser_init(&ctx->http.parser, HTTP_REQUEST); - ctx->http.data_len = 0; - ctx->http.field_values_ctr = 0; - net_pkt_unref(pkt); - - return; - -ws_only: - if (ctx->cb.recv) { -#if defined(CONFIG_WEBSOCKET) - u32_t msg_len, header_len = 0U; - bool masked = true; - int ret; - - if (ctx->websocket.data_waiting == 0) { - ctx->websocket.masking_value = 0; - ctx->websocket.data_read = 0; - ctx->websocket.msg_type_flag = 0; - - if (ctx->websocket.pending) { - /* Append the pending data to current buffer */ - int orig_len; - - orig_len = net_pkt_appdatalen( - ctx->websocket.pending); - net_pkt_set_appdatalen( - ctx->websocket.pending, - orig_len + net_pkt_appdatalen(pkt)); - - net_pkt_frag_add(ctx->websocket.pending, - pkt->frags); - - pkt->frags = NULL; - net_pkt_unref(pkt); - - net_pkt_compact(ctx->websocket.pending); - } else { - ctx->websocket.pending = pkt; - } - - ret = ws_strip_header(ctx->websocket.pending, &masked, - &ctx->websocket.masking_value, - &msg_len, - &ctx->websocket.msg_type_flag, - &header_len); - if (ret < 0) { - /* Not enough bytes for a complete websocket - * header, continue reading data. - */ - NET_DBG("[%p] pending %zd bytes, waiting more", - ctx, - net_pkt_get_len(ctx->websocket.pending)); - return; - } - - if (ctx->websocket.msg_type_flag & WS_FLAG_CLOSE) { - NET_DBG("[%p] Close request from peer", ctx); - http_close(ctx); - return; - } - - if (ctx->websocket.msg_type_flag & WS_FLAG_PING) { - NET_DBG("[%p] Ping request from peer", ctx); - ws_send_msg(ctx, NULL, 0, WS_OPCODE_PONG, - false, true, dst, NULL); - ctx->websocket.data_waiting = 0; - return; - } - - /* We have now received some data. It might not yet be - * the full data that is told by msg_len but we can - * already pass this data to caller. - */ - ctx->websocket.data_waiting = msg_len; - - if (net_pkt_get_len(ctx->websocket.pending) == - header_len) { - NET_DBG("[%p] waiting more data", ctx); - - /* We do not need the websocket header - * any more, so discard it. - */ - net_pkt_unref(ctx->websocket.pending); - ctx->websocket.pending = NULL; - return; - } - - /* If we have more data pending than the header len, - * then discard the header as we do not need that. - */ - net_buf_pull(ctx->websocket.pending->frags, - header_len); - - pkt = ctx->websocket.pending; - ctx->websocket.pending = NULL; - - net_pkt_set_appdatalen(pkt, net_pkt_get_len(pkt)); - net_pkt_set_appdata(pkt, pkt->frags->data); - } - - if (net_pkt_appdatalen(pkt) > ctx->websocket.data_waiting) { - /* Now we received more data which in practice means - * that we got the next websocket header. - */ - struct net_buf *hdr, *payload; - struct net_pkt *cloned; - - payload = pkt->frags; - pkt->frags = NULL; - - cloned = net_pkt_clone(pkt, ctx->timeout); - if (!cloned) { - net_pkt_unref(pkt); - net_pkt_frag_unref(payload); - return; - } - - ret = net_pkt_split(pkt, payload, - ctx->websocket.data_waiting, - &hdr, ctx->timeout); - if (ret < 0) { - net_pkt_unref(pkt); - net_pkt_frag_unref(payload); - net_pkt_unref(cloned); - return; - } - - pkt->frags = payload; - cloned->frags = hdr; - - ctx->websocket.pending = cloned; - ctx->websocket.data_waiting = 0; - - net_pkt_set_appdatalen(pkt, net_pkt_get_len(pkt)); - net_pkt_set_appdata(pkt, pkt->frags->data); - - net_pkt_set_appdatalen(cloned, net_pkt_get_len(cloned)); - net_pkt_set_appdata(cloned, cloned->frags->data); - - NET_DBG("More data (%d bytes) received, pending it", - net_pkt_appdatalen(cloned)); - } else { - ctx->websocket.data_waiting -= net_pkt_appdatalen(pkt); - } - - if (ctx->websocket.data_waiting) { - NET_DBG("[%p] waiting still %u bytes", ctx, - ctx->websocket.data_waiting); - } else { - NET_DBG("[%p] All bytes received", ctx); - } - - NET_DBG("[%p] Pass data (%d) to application for processing", - ctx, net_pkt_appdatalen(pkt)); - - NET_DBG("[%p] Masked %s mask 0x%04x", ctx, - masked ? "yes" : "no", - ctx->websocket.masking_value); - - if (masked) { - /* Always deliver unmasked data to the application */ - ws_mask_pkt(pkt, - ctx->websocket.masking_value, - &ctx->websocket.data_read); - } - - ctx->cb.recv(ctx, pkt, 0, ctx->websocket.msg_type_flag, - dst, ctx->user_data); -#else - ctx->cb.recv(ctx, pkt, 0, 0, dst, ctx->user_data); -#endif - } - - return; - -ws_ready: - http_change_state(ctx, HTTP_STATE_OPEN); - url_connected(ctx, WS_CONNECTION, dst); - net_pkt_unref(pkt); - ctx->http.field_values_ctr = 0; -} - -#if defined(CONFIG_HTTPS) -int http_server_set_tls(struct http_ctx *ctx, - const char *server_banner, - u8_t *personalization_data, - size_t personalization_data_len, - net_app_cert_cb_t cert_cb, - net_app_entropy_src_cb_t entropy_src_cb, - struct k_mem_pool *pool, - k_thread_stack_t *stack, - size_t stack_len) -{ - int ret; - - if (!ctx->is_tls) { - /* Change the default port if user did not set it */ - if (!ctx->server_addr) { - net_sin(&ctx->local)->sin_port = - htons(HTTPS_DEFAULT_PORT); - -#if defined(CONFIG_NET_IPV6) - net_sin6(&ctx->app_ctx.ipv6.local)->sin6_port = - htons(HTTPS_DEFAULT_PORT); -#endif -#if defined(CONFIG_NET_IPV4) - net_sin(&ctx->app_ctx.ipv4.local)->sin_port = - htons(HTTPS_DEFAULT_PORT); -#endif - } - - ret = net_app_server_tls(&ctx->app_ctx, - ctx->http.request_buf, - ctx->http.request_buf_len, - server_banner, - personalization_data, - personalization_data_len, - cert_cb, - entropy_src_cb, - pool, - stack, - stack_len); - if (ret < 0) { - NET_ERR("Cannot init TLS (%d)", ret); - goto quit; - } - - ctx->is_tls = true; - return 0; - } - - return -EALREADY; - -quit: - net_app_release(&ctx->app_ctx); - return ret; -} -#endif - -static int on_header_field(struct http_parser *parser, - const char *at, size_t length) -{ - struct http_ctx *ctx = parser->data; - - if (ctx->http.field_values_ctr >= CONFIG_HTTP_HEADERS) { - return 0; - } - - http_change_state(ctx, HTTP_STATE_RECEIVING_HEADER); - - ctx->http.field_values[ctx->http.field_values_ctr].key = at; - ctx->http.field_values[ctx->http.field_values_ctr].key_len = length; - - return 0; -} - -static int on_header_value(struct http_parser *parser, - const char *at, size_t length) -{ - struct http_ctx *ctx = parser->data; - - if (ctx->http.field_values_ctr >= CONFIG_HTTP_HEADERS) { - return 0; - } - - ctx->http.field_values[ctx->http.field_values_ctr].value = at; - ctx->http.field_values[ctx->http.field_values_ctr].value_len = length; - - ctx->http.field_values_ctr++; - - return 0; -} - -static int on_url(struct http_parser *parser, const char *at, size_t length) -{ - struct http_ctx *ctx = parser->data; - - ctx->http.url = at; - ctx->http.url_len = length; - - http_change_state(ctx, HTTP_STATE_WAITING_HEADER); - - http_server_conn_add(ctx); - - return 0; -} - -static int on_headers_complete(struct http_parser *parser) -{ - ARG_UNUSED(parser); - -#if defined(CONFIG_WEBSOCKET) - return ws_headers_complete(parser); -#else - return 0; -#endif -} - -static int init_http_parser(struct http_ctx *ctx) -{ - (void)memset(ctx->http.field_values, 0, - sizeof(ctx->http.field_values)); - - ctx->http.parser_settings.on_header_field = on_header_field; - ctx->http.parser_settings.on_header_value = on_header_value; - ctx->http.parser_settings.on_url = on_url; - ctx->http.parser_settings.on_headers_complete = on_headers_complete; - - http_parser_init(&ctx->http.parser, HTTP_REQUEST); - - ctx->http.parser.data = ctx; - - return 0; -} - -static inline void new_server(struct http_ctx *ctx, - const char *server_banner, - const struct sockaddr *addr) -{ -#if CONFIG_HTTP_LOG_LEVEL >= LOG_LEVEL_INF -#if defined(CONFIG_NET_IPV6) -#define PORT_STR sizeof("[]:xxxxx") - char buf[NET_IPV6_ADDR_LEN + PORT_STR]; -#elif defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6) -#define PORT_STR sizeof(":xxxxx") - char buf[NET_IPV4_ADDR_LEN + PORT_STR]; -#endif - - if (addr) { - NET_INFO("%s %s (%p)", server_banner, - sprint_ipaddr(buf, sizeof(buf), addr), ctx); - } else { - NET_INFO("%s (%p)", server_banner, ctx); - } -#endif /* CONFIG_HTTP_LOG_LEVEL */ -} - -static void init_net(struct http_ctx *ctx, - struct sockaddr *server_addr, - u16_t port) -{ - (void)memset(&ctx->local, 0, sizeof(ctx->local)); - - if (server_addr) { - memcpy(&ctx->local, server_addr, sizeof(ctx->local)); - } else { - ctx->local.sa_family = AF_UNSPEC; - net_sin(&ctx->local)->sin_port = htons(port); - } -} - -int http_server_init(struct http_ctx *ctx, - struct http_server_urls *urls, - struct sockaddr *server_addr, - u8_t *request_buf, - size_t request_buf_len, - const char *server_banner, - void *user_data) -{ - int ret = 0; - - if (!ctx) { - return -EINVAL; - } - - if (ctx->is_init) { - return -EALREADY; - } - - if (!request_buf || request_buf_len == 0) { - NET_ERR("Request buf must be set"); - return -EINVAL; - } - - (void)memset(ctx, 0, sizeof(*ctx)); - - init_net(ctx, server_addr, HTTP_DEFAULT_PORT); - - if (server_banner) { - new_server(ctx, server_banner, server_addr); - } - - /* Timeout for network buffer allocations */ - ctx->timeout = BUF_ALLOC_TIMEOUT; - - ctx->http.request_buf = request_buf; - ctx->http.request_buf_len = request_buf_len; - ctx->http.urls = urls; - ctx->http.data_len = 0; - ctx->user_data = user_data; - ctx->server_addr = server_addr; - - ret = net_app_init_tcp_server(&ctx->app_ctx, - &ctx->local, - HTTP_DEFAULT_PORT, - ctx); - if (ret < 0) { - NET_ERR("Cannot create http server (%d)", ret); - return ret; - } - - ret = net_app_set_cb(&ctx->app_ctx, NULL, http_received, - http_data_sent, http_closed); - if (ret < 0) { - NET_ERR("Cannot set callbacks (%d)", ret); - goto quit; - } - - init_http_parser(ctx); - - ctx->is_init = true; - return 0; - -quit: - net_app_release(&ctx->app_ctx); - return ret; -} - -int http_server_enable(struct http_ctx *ctx) -{ - int ret; - - NET_ASSERT(ctx); - - net_app_server_enable(&ctx->app_ctx); - - ret = net_app_listen(&ctx->app_ctx); - if (ret < 0) { - NET_ERR("Cannot wait connection (%d)", ret); - return false; - } - - return 0; -} - -int http_server_disable(struct http_ctx *ctx) -{ - NET_ASSERT(ctx); - - net_app_server_disable(&ctx->app_ctx); - - return 0; -} diff --git a/tests/net/all/prj.conf b/tests/net/all/prj.conf index 071cf65149c..f887ad036ae 100644 --- a/tests/net/all/prj.conf +++ b/tests/net/all/prj.conf @@ -210,14 +210,6 @@ CONFIG_MQTT_LIB=y CONFIG_MQTT_KEEPALIVE=60 CONFIG_MQTT_LIB_TLS=y -# HTTP -CONFIG_HTTP=y -CONFIG_HTTP_SERVER=y -CONFIG_HTTP_CLIENT=y -CONFIG_HTTP_PARSER=y -CONFIG_HTTP_PARSER_STRICT=y -CONFIG_HTTP_LOG_LEVEL_DBG=y - # VLAN CONFIG_NET_VLAN=y diff --git a/tests/net/lib/http_header_fields/prj.conf b/tests/net/lib/http_header_fields/prj.conf index 1433360c00f..8323faf5bc1 100644 --- a/tests/net/lib/http_header_fields/prj.conf +++ b/tests/net/lib/http_header_fields/prj.conf @@ -4,7 +4,6 @@ CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_ZTEST_STACKSIZE=1024 CONFIG_HTTP_PARSER=y -CONFIG_HTTP=y CONFIG_ZTEST=y CONFIG_MAIN_STACK_SIZE=1280 # Enable strict parser by uncommenting the following line