net: http: Add HTTP server library support
This commit creates a HTTP server library. So instead of creating a complex HTTP server application for serving HTTP requests, the developer can use the HTTP server API to create HTTP server insteances. This commit also adds support for creating HTTPS servers. Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
43b37cef31
commit
a174d2eba7
21 changed files with 2339 additions and 1673 deletions
|
@ -7,13 +7,42 @@
|
||||||
#ifndef __HTTP_H__
|
#ifndef __HTTP_H__
|
||||||
#define __HTTP_H__
|
#define __HTTP_H__
|
||||||
|
|
||||||
|
#if defined(CONFIG_HTTPS)
|
||||||
|
#if defined(CONFIG_MBEDTLS)
|
||||||
|
#if !defined(CONFIG_MBEDTLS_CFG_FILE)
|
||||||
|
#include "mbedtls/config.h"
|
||||||
|
#else
|
||||||
|
#include CONFIG_MBEDTLS_CFG_FILE
|
||||||
|
#endif /* CONFIG_MBEDTLS_CFG_FILE */
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PLATFORM_C)
|
||||||
|
#include "mbedtls/platform.h"
|
||||||
|
#else
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define mbedtls_time_t time_t
|
||||||
|
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
|
||||||
|
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
|
||||||
|
#endif /* MBEDTLS_PLATFORM_C */
|
||||||
|
|
||||||
|
#include <mbedtls/ssl_cookie.h>
|
||||||
|
#include <mbedtls/entropy.h>
|
||||||
|
#include <mbedtls/ctr_drbg.h>
|
||||||
|
#include <mbedtls/net_sockets.h>
|
||||||
|
#include <mbedtls/x509.h>
|
||||||
|
#include <mbedtls/x509_crt.h>
|
||||||
|
#include <mbedtls/ssl.h>
|
||||||
|
#include <mbedtls/error.h>
|
||||||
|
#include <mbedtls/debug.h>
|
||||||
|
#endif /* CONFIG_MBEDTLS */
|
||||||
|
#endif /* CONFIG_HTTPS */
|
||||||
|
|
||||||
|
#define HTTP_CRLF "\r\n"
|
||||||
|
|
||||||
#if defined(CONFIG_HTTP_CLIENT)
|
#if defined(CONFIG_HTTP_CLIENT)
|
||||||
|
|
||||||
#include <net/http_parser.h>
|
#include <net/http_parser.h>
|
||||||
#include <net/net_context.h>
|
#include <net/net_context.h>
|
||||||
|
|
||||||
#define HTTP_CRLF "\r\n"
|
|
||||||
|
|
||||||
/* Is there more data to come */
|
/* Is there more data to come */
|
||||||
enum http_final_call {
|
enum http_final_call {
|
||||||
HTTP_DATA_MORE = 0,
|
HTTP_DATA_MORE = 0,
|
||||||
|
@ -395,20 +424,17 @@ int http_client_init(struct http_client_ctx *http_ctx,
|
||||||
* @param http_ctx HTTP context.
|
* @param http_ctx HTTP context.
|
||||||
*/
|
*/
|
||||||
void http_client_release(struct http_client_ctx *http_ctx);
|
void http_client_release(struct http_client_ctx *http_ctx);
|
||||||
#endif
|
#endif /* CONFIG_HTTP_CLIENT */
|
||||||
|
|
||||||
#if defined(CONFIG_HTTP_SERVER)
|
#if defined(CONFIG_HTTP_SERVER)
|
||||||
|
|
||||||
#include <net/net_context.h>
|
#include <net/net_context.h>
|
||||||
|
|
||||||
#if defined(CONFIG_HTTP_PARSER)
|
|
||||||
#include <net/http_parser.h>
|
#include <net/http_parser.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
/* HTTP server context state */
|
struct http_server_ctx;
|
||||||
enum HTTP_CTX_STATE {
|
|
||||||
HTTP_CTX_FREE = 0,
|
enum http_url_flags {
|
||||||
HTTP_CTX_IN_USE
|
HTTP_URL_STANDARD = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* HTTP header fields struct */
|
/* HTTP header fields struct */
|
||||||
|
@ -417,54 +443,441 @@ struct http_field_value {
|
||||||
* containing the HTTP field name
|
* containing the HTTP field name
|
||||||
*/
|
*/
|
||||||
const char *key;
|
const char *key;
|
||||||
/** Length of the field name */
|
|
||||||
u16_t key_len;
|
|
||||||
|
|
||||||
/** Value, this variable will point to the beginning of the string
|
/** Value, this variable will point to the beginning of the string
|
||||||
* containing the field value
|
* containing the field value
|
||||||
*/
|
*/
|
||||||
const char *value;
|
const char *value;
|
||||||
|
|
||||||
|
/** Length of the field name */
|
||||||
|
u16_t key_len;
|
||||||
|
|
||||||
/** Length of the field value */
|
/** Length of the field value */
|
||||||
u16_t value_len;
|
u16_t value_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef int (*http_url_cb_t)(struct http_server_ctx *ctx);
|
||||||
|
|
||||||
|
/* HTTP root URL struct, used for pattern matching */
|
||||||
|
struct http_root_url {
|
||||||
|
/** URL */
|
||||||
|
const char *root;
|
||||||
|
|
||||||
|
/** Callback that is called when this URL is received */
|
||||||
|
http_url_cb_t write_cb;
|
||||||
|
|
||||||
|
/** Length of the URL */
|
||||||
|
u16_t root_len;
|
||||||
|
|
||||||
|
/** Flags for this URL (values are from enum http_url_flags) */
|
||||||
|
u8_t flags;
|
||||||
|
|
||||||
|
/** Is this URL resource used or not */
|
||||||
|
u8_t is_used;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Collection of URLs that this server will handle */
|
||||||
|
struct http_server_urls {
|
||||||
|
/* First item is the default handler and it is always there.
|
||||||
|
*/
|
||||||
|
struct http_root_url default_url;
|
||||||
|
struct http_root_url urls[CONFIG_HTTP_SERVER_NUM_URLS];
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(CONFIG_HTTPS)
|
||||||
|
/* Internal information for managing HTTPS data */
|
||||||
|
struct https_context {
|
||||||
|
struct net_pkt *rx_pkt;
|
||||||
|
struct net_buf *frag;
|
||||||
|
struct k_sem tx_sem;
|
||||||
|
struct k_fifo rx_fifo;
|
||||||
|
int remaining;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef https_server_cert_cb_t
|
||||||
|
* @brief Callback used when the API user needs to setup the
|
||||||
|
* HTTPS certs.
|
||||||
|
*
|
||||||
|
* @param ctx HTTPS server context.
|
||||||
|
* @param cert MBEDTLS certificate
|
||||||
|
* @param pkey MBEDTLS private key
|
||||||
|
*
|
||||||
|
* @return 0 if ok, <0 if there is an error
|
||||||
|
*/
|
||||||
|
typedef int (*https_server_cert_cb_t)(struct http_server_ctx *ctx,
|
||||||
|
mbedtls_x509_crt *cert,
|
||||||
|
mbedtls_pk_context *pkey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef https_entropy_src_cb_t
|
||||||
|
* @brief Callback used when the API user needs to setup the entropy source.
|
||||||
|
* @detail This is the same as mbedtls_entropy_f_source_ptr callback.
|
||||||
|
*
|
||||||
|
* @param data Callback-specific data pointer
|
||||||
|
* @param output Data to fill
|
||||||
|
* @param len Maximum size to provide
|
||||||
|
* @param olen The actual amount of bytes put into the buffer (Can be 0)
|
||||||
|
*/
|
||||||
|
typedef int (*https_entropy_src_cb_t)(void *data, unsigned char *output,
|
||||||
|
size_t len, size_t *olen);
|
||||||
|
#endif /* CONFIG_HTTPS */
|
||||||
|
|
||||||
|
typedef int (*http_send_data_t)(struct net_pkt *pkt,
|
||||||
|
net_context_send_cb_t cb,
|
||||||
|
s32_t timeout,
|
||||||
|
void *token,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
/* The HTTP server context struct */
|
/* The HTTP server context struct */
|
||||||
struct http_server_ctx {
|
struct http_server_ctx {
|
||||||
u8_t state;
|
/** Collection of URLs that this server context will handle */
|
||||||
|
struct http_server_urls *urls;
|
||||||
|
|
||||||
/** Collection of header fields */
|
#if defined(CONFIG_NET_IPV4)
|
||||||
struct http_field_value field_values[CONFIG_HTTP_HEADER_FIELD_ITEMS];
|
/** IPv4 stack network context for listening */
|
||||||
/** Number of header field elements */
|
struct net_context *net_ipv4_ctx;
|
||||||
u16_t field_values_ctr;
|
#endif
|
||||||
|
#if defined(CONFIG_NET_IPV6)
|
||||||
|
/** IPv6 stack network context for listening */
|
||||||
|
struct net_context *net_ipv6_ctx;
|
||||||
|
#endif
|
||||||
|
|
||||||
/** HTTP Request URL */
|
/** Function that is called when data is received from network. */
|
||||||
const char *url;
|
net_context_recv_cb_t recv_cb;
|
||||||
/** URL's length */
|
|
||||||
u16_t url_len;
|
|
||||||
|
|
||||||
/**IP stack network context */
|
/** Function that is called when data is sent to network. */
|
||||||
struct net_context *net_ctx;
|
http_send_data_t send_data;
|
||||||
|
|
||||||
/** Network timeout */
|
/** Network timeout */
|
||||||
s32_t timeout;
|
s32_t timeout;
|
||||||
|
|
||||||
#if defined(CONFIG_HTTP_PARSER)
|
/** Running status of the server. If true, then the server is enabled.
|
||||||
|
* If false then it is disabled and will not serve clients.
|
||||||
|
* The server is disabled by default after initialization and will need
|
||||||
|
* to be enabled manually.
|
||||||
|
*/
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
|
/** Is this instance HTTPS or not.
|
||||||
|
*/
|
||||||
|
bool is_https;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
/** From which net_context the request came from */
|
||||||
|
struct net_context *net_ctx;
|
||||||
|
|
||||||
/** HTTP parser */
|
/** HTTP parser */
|
||||||
struct http_parser parser;
|
struct http_parser parser;
|
||||||
|
|
||||||
/** HTTP parser settings */
|
/** HTTP parser settings */
|
||||||
struct http_parser_settings parser_settings;
|
struct http_parser_settings settings;
|
||||||
#endif
|
|
||||||
|
/** Collection of header fields */
|
||||||
|
struct http_field_value
|
||||||
|
field_values[CONFIG_HTTP_HEADER_FIELD_ITEMS];
|
||||||
|
|
||||||
|
/** HTTP Request URL */
|
||||||
|
const char *url;
|
||||||
|
|
||||||
|
/** Where the request is stored, this is to be provided
|
||||||
|
* by the user.
|
||||||
|
*/
|
||||||
|
u8_t *request_buf;
|
||||||
|
|
||||||
|
/** Request buffer maximum length */
|
||||||
|
size_t request_buf_len;
|
||||||
|
|
||||||
|
/** Length of the data in the request buf. */
|
||||||
|
size_t data_len;
|
||||||
|
|
||||||
|
/** Number of header field elements */
|
||||||
|
u16_t field_values_ctr;
|
||||||
|
|
||||||
|
/** URL's length */
|
||||||
|
u16_t url_len;
|
||||||
|
} req;
|
||||||
|
|
||||||
|
#if defined(CONFIG_HTTPS)
|
||||||
|
struct {
|
||||||
|
/** HTTPS stack for mbedtls library. */
|
||||||
|
u8_t *stack;
|
||||||
|
|
||||||
|
/** HTTPS stack size. */
|
||||||
|
int stack_size;
|
||||||
|
|
||||||
|
/** HTTPS thread id */
|
||||||
|
k_tid_t tid;
|
||||||
|
|
||||||
|
/** HTTPS thread */
|
||||||
|
struct k_thread thread;
|
||||||
|
|
||||||
|
/** Memory pool for RX data */
|
||||||
|
struct k_mem_pool *pool;
|
||||||
|
|
||||||
|
/** mbedtls related configuration. */
|
||||||
|
struct {
|
||||||
|
struct https_context ssl_ctx;
|
||||||
|
https_server_cert_cb_t cert_cb;
|
||||||
|
https_entropy_src_cb_t entropy_src_cb;
|
||||||
|
mbedtls_entropy_context entropy;
|
||||||
|
mbedtls_ctr_drbg_context ctr_drbg;
|
||||||
|
mbedtls_ssl_context ssl;
|
||||||
|
mbedtls_ssl_config conf;
|
||||||
|
mbedtls_x509_crt srvcert;
|
||||||
|
mbedtls_pk_context pkey;
|
||||||
|
u8_t *personalization_data;
|
||||||
|
size_t personalization_data_len;
|
||||||
|
} mbedtls;
|
||||||
|
} https;
|
||||||
|
#endif /* CONFIG_HTTPS */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize user supplied HTTP context.
|
||||||
|
*
|
||||||
|
* @detail Caller can set the various callback fields in http_ctx and
|
||||||
|
* http_ctx.req.parser after this call if needed.
|
||||||
|
*
|
||||||
|
* @param http_ctx HTTP context.
|
||||||
|
* @param urls Array of URLs that the server instance will serve. If the
|
||||||
|
* server receives a HTTP request into one of the URLs, it will call user
|
||||||
|
* supplied callback. If no such URL is registered, a default handler will
|
||||||
|
* be called (if set by the user). If no data handler is found, the request
|
||||||
|
* is dropped.
|
||||||
|
* @param server_addr Socket address of the local network interface and TCP
|
||||||
|
* port where the data is being waited. If the socket family is set to
|
||||||
|
* AF_UNSPEC, then both IPv4 and IPv6 is started to be listened. If the
|
||||||
|
* address is set to be INADDR_ANY (for IPv4) or unspecified address (all bits
|
||||||
|
* zeros for IPv6), then the HTTP server will select proper IP address to bind
|
||||||
|
* to. If caller has not specified HTTP listening port, then port 80 is being
|
||||||
|
* listened. The parameter can be left NULL in which case a listener to port 80
|
||||||
|
* using IPv4 and IPv6 is created. Note that if IPv4 or IPv6 is disabled, then
|
||||||
|
* the corresponding disabled service listener is not created.
|
||||||
|
* @param request_buf Caller supplied buffer where the HTTP request will be
|
||||||
|
* stored
|
||||||
|
* @param request_buf_len Length of the caller suppied buffer.
|
||||||
|
* @param server_banner Print information about started service. This is only
|
||||||
|
* printed if HTTP debugging is activated. The parameter can be set to NULL if
|
||||||
|
* no extra prints are needed.
|
||||||
|
*
|
||||||
|
* @return Return 0 if ok, <0 if error.
|
||||||
|
*/
|
||||||
|
int http_server_init(struct http_server_ctx *http_ctx,
|
||||||
|
struct http_server_urls *urls,
|
||||||
|
struct sockaddr *server_addr,
|
||||||
|
u8_t *request_buf,
|
||||||
|
size_t request_buf_len,
|
||||||
|
const char *server_banner);
|
||||||
|
|
||||||
|
#if defined(CONFIG_HTTPS)
|
||||||
|
/**
|
||||||
|
* @brief Initialize user supplied HTTP context. This function must be
|
||||||
|
* used if HTTPS server is created.
|
||||||
|
*
|
||||||
|
* @detail Caller can set the various callback fields in http_ctx and
|
||||||
|
* http_ctx.req.parser after this call if needed.
|
||||||
|
*
|
||||||
|
* @param http_ctx HTTP context.
|
||||||
|
* @param urls Array of URLs that the server instance will serve. If the
|
||||||
|
* server receives a HTTP request into one of the URLs, it will call user
|
||||||
|
* supplied callback. If no such URL is registered, a default handler will
|
||||||
|
* be called (if set by the user). If no data handler is found, the request
|
||||||
|
* is dropped.
|
||||||
|
* @param server_addr Socket address of the local network interface and TCP
|
||||||
|
* port where the data is being waited. If the socket family is set to
|
||||||
|
* AF_UNSPEC, then both IPv4 and IPv6 is started to be listened. If the
|
||||||
|
* address is set to be INADDR_ANY (for IPv4) or unspecified address (all bits
|
||||||
|
* zeros for IPv6), then the HTTP server will select proper IP address to bind
|
||||||
|
* to. If caller has not specified HTTP listening port, then port 80 is being
|
||||||
|
* listened. The parameter can be left NULL in which case a listener to port 80
|
||||||
|
* using IPv4 and IPv6 is created. Note that if IPv4 or IPv6 is disabled, then
|
||||||
|
* the corresponding disabled service listener is not created.
|
||||||
|
* @param request_buf Caller supplied buffer where the HTTP request will be
|
||||||
|
* stored
|
||||||
|
* @param request_buf_len Length of the caller suppied buffer.
|
||||||
|
* @param server_banner Print information about started service. This is only
|
||||||
|
* printed if HTTP debugging is activated. The parameter can be set to NULL if
|
||||||
|
* no extra prints are needed.
|
||||||
|
* @param personalization_data Personalization data (Device specific
|
||||||
|
* identifiers) for random number generator. (Can be NULL).
|
||||||
|
* @param personalization_data_len Length of the personalization data.
|
||||||
|
* @param cert_cb User supplied callback that setups the certifacates.
|
||||||
|
* @param entropy_src_cb User supplied callback that setup the entropy. This
|
||||||
|
* can be set to NULL, in which case default entropy source is used.
|
||||||
|
* @param pool Memory pool for RX data reads.
|
||||||
|
* @param https_stack HTTPS thread stack.
|
||||||
|
* @param https_stack_len HTTP thread stack size.
|
||||||
|
*
|
||||||
|
* @return Return 0 if ok, <0 if error.
|
||||||
|
*/
|
||||||
|
int https_server_init(struct http_server_ctx *http_ctx,
|
||||||
|
struct http_server_urls *urls,
|
||||||
|
struct sockaddr *server_addr,
|
||||||
|
u8_t *request_buf,
|
||||||
|
size_t request_buf_len,
|
||||||
|
const char *server_banner,
|
||||||
|
u8_t *personalization_data,
|
||||||
|
size_t personalization_data_len,
|
||||||
|
https_server_cert_cb_t cert_cb,
|
||||||
|
https_entropy_src_cb_t entropy_src_cb,
|
||||||
|
struct k_mem_pool *pool,
|
||||||
|
u8_t *https_stack,
|
||||||
|
size_t https_stack_len);
|
||||||
|
#endif /* CONFIG_HTTPS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Release all the resources allocated for HTTP context.
|
||||||
|
*
|
||||||
|
* @param http_ctx HTTP context.
|
||||||
|
*/
|
||||||
|
void http_server_release(struct http_server_ctx *http_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable HTTP server that is related to this context.
|
||||||
|
*
|
||||||
|
* @detail The HTTP server will start to serve request after this.
|
||||||
|
*
|
||||||
|
* @param http_ctx HTTP context.
|
||||||
|
*
|
||||||
|
* @return Previous status of the server.
|
||||||
|
*/
|
||||||
|
bool http_server_enable(struct http_server_ctx *http_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable HTTP server that is related to this context.
|
||||||
|
*
|
||||||
|
* @detail The HTTP server will stop to serve request after this.
|
||||||
|
*
|
||||||
|
* @param http_ctx HTTP context.
|
||||||
|
*
|
||||||
|
* @return Previous status of the server.
|
||||||
|
*/
|
||||||
|
bool http_server_disable(struct http_server_ctx *http_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper function that can be used to fill the server (local) sockaddr
|
||||||
|
* struct.
|
||||||
|
*
|
||||||
|
* @param addr Sockaddr struct to be filled.
|
||||||
|
* @param myaddr Address that the local IP address. If left NULL, then the
|
||||||
|
* proper system address is used.
|
||||||
|
* @param port TCP port to use.
|
||||||
|
*
|
||||||
|
* @return 0 if ok, <0 if error.
|
||||||
|
*/
|
||||||
|
int http_server_set_local_addr(struct sockaddr *addr, const char *myaddr,
|
||||||
|
u16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a handler for a given URL.
|
||||||
|
*
|
||||||
|
* @detail Register a handler which is called if the server receives a
|
||||||
|
* request to a given URL.
|
||||||
|
*
|
||||||
|
* @param urls URL struct that will contain all the URLs the user wants to
|
||||||
|
* register.
|
||||||
|
* @param url URL string.
|
||||||
|
* @param flags Flags for the URL.
|
||||||
|
* @param write_cb Callback that is called when URL is requested.
|
||||||
|
*
|
||||||
|
* @return NULL if the URL is already registered, pointer to URL if
|
||||||
|
* registering was ok.
|
||||||
|
*/
|
||||||
|
struct http_root_url *http_server_add_url(struct http_server_urls *urls,
|
||||||
|
const char *url, u8_t flags,
|
||||||
|
http_url_cb_t write_cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete the handler for a given URL.
|
||||||
|
*
|
||||||
|
* @detail Unregister the previously registered URL handler.
|
||||||
|
*
|
||||||
|
* @param urls URL struct that will contain all the URLs the user has
|
||||||
|
* registered.
|
||||||
|
* @param url URL string.
|
||||||
|
*
|
||||||
|
* @return 0 if ok, <0 if error.
|
||||||
|
*/
|
||||||
|
int http_server_del_url(struct http_server_urls *urls, const char *url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add default URL handler.
|
||||||
|
*
|
||||||
|
* @detail If no URL handler is found, then call this handler. There can
|
||||||
|
* be only one default handler in the URL struct.
|
||||||
|
*
|
||||||
|
* @param urls URL struct that will contain all the URLs the user has
|
||||||
|
* registered.
|
||||||
|
* @param write_cb Callback that is called when non-registered URL is
|
||||||
|
* requested.
|
||||||
|
*
|
||||||
|
* @return NULL if default URL is already registered, pointer to default
|
||||||
|
* URL if registering was ok.
|
||||||
|
*/
|
||||||
|
struct http_root_url *http_server_add_default(struct http_server_urls *urls,
|
||||||
|
http_url_cb_t write_cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete the default URL handler.
|
||||||
|
*
|
||||||
|
* @detail Unregister the previously registered default URL handler.
|
||||||
|
*
|
||||||
|
* @param urls URL struct that will contain all the URLs the user has
|
||||||
|
* registered.
|
||||||
|
*
|
||||||
|
* @return 0 if ok, <0 if error.
|
||||||
|
*/
|
||||||
|
int http_server_del_default(struct http_server_urls *urls);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send HTTP response to client.
|
||||||
|
*
|
||||||
|
* @param ctx HTTP context.
|
||||||
|
* @param http_header HTTP headers to send.
|
||||||
|
* @param html_payload HTML payload to send.
|
||||||
|
*
|
||||||
|
* @return 0 if ok, <0 if error.
|
||||||
|
*/
|
||||||
int http_response(struct http_server_ctx *ctx, const char *http_header,
|
int http_response(struct http_server_ctx *ctx, const char *http_header,
|
||||||
const char *html_payload);
|
const char *html_payload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send HTTP 400 response to client.
|
||||||
|
*
|
||||||
|
* @detail HTTP 400 error code indicates a Bad Request
|
||||||
|
*
|
||||||
|
* @param ctx HTTP context.
|
||||||
|
* @param html_payload HTML payload to send.
|
||||||
|
*
|
||||||
|
* @return 0 if ok, <0 if error.
|
||||||
|
*/
|
||||||
int http_response_400(struct http_server_ctx *ctx, const char *html_payload);
|
int http_response_400(struct http_server_ctx *ctx, const char *html_payload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send HTTP 403 response to client.
|
||||||
|
*
|
||||||
|
* @detail HTTP 403 error code indicates a Forbidden Request
|
||||||
|
*
|
||||||
|
* @param ctx HTTP context.
|
||||||
|
* @param html_payload HTML payload to send.
|
||||||
|
*
|
||||||
|
* @return 0 if ok, <0 if error.
|
||||||
|
*/
|
||||||
int http_response_403(struct http_server_ctx *ctx, const char *html_payload);
|
int http_response_403(struct http_server_ctx *ctx, const char *html_payload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send HTTP 404 response to client.
|
||||||
|
*
|
||||||
|
* @detail HTTP 404 error code indicates a Not Found resource.
|
||||||
|
*
|
||||||
|
* @param ctx HTTP context.
|
||||||
|
* @param html_payload HTML payload to send.
|
||||||
|
*
|
||||||
|
* @return 0 if ok, <0 if error.
|
||||||
|
*/
|
||||||
int http_response_404(struct http_server_ctx *ctx, const char *html_payload);
|
int http_response_404(struct http_server_ctx *ctx, const char *html_payload);
|
||||||
|
|
||||||
#endif
|
#endif /* CONFIG_HTTP_SERVER */
|
||||||
|
|
||||||
#endif
|
#endif /* __HTTP_H__ */
|
||||||
|
|
|
@ -4,10 +4,8 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
|
|
||||||
BOARD ?= frdm_k64f
|
BOARD ?= qemu_x86
|
||||||
CONF_FILE ?= prj_$(BOARD).conf
|
CONF_FILE ?= prj_$(BOARD).conf
|
||||||
|
|
||||||
include $(ZEPHYR_BASE)/Makefile.inc
|
include $(ZEPHYR_BASE)/Makefile.inc
|
||||||
ifeq ($(BOARD), qemu_x86)
|
|
||||||
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
|
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
|
||||||
endif
|
|
||||||
|
|
|
@ -7,14 +7,13 @@ Overview
|
||||||
********
|
********
|
||||||
|
|
||||||
The HTTP Server sample application for Zephyr implements a basic TCP server
|
The HTTP Server sample application for Zephyr implements a basic TCP server
|
||||||
on top of the HTTP Parser Library that is able to receive HTTP 1.1 requests,
|
on top of the HTTP Server Library that is able to receive HTTP 1.1 requests,
|
||||||
parse them and write back the responses.
|
parse them and write back the responses.
|
||||||
|
|
||||||
This sample code generates HTTP 1.1 responses dynamically
|
This sample code generates HTTP 1.1 responses dynamically and does not serve
|
||||||
and does not serve content from a file system. The source code includes
|
content from a file system. The source code includes examples on how to write
|
||||||
examples on how to write HTTP 1.1 responses: 200 OK, 400 Bad Request,
|
HTTP 1.1 responses: 200 OK, 400 Bad Request, 403 Forbidden, 404 Not Found and
|
||||||
403 Forbidden, 404 Not Found and soft HTTP errors like 200 OK with a 404
|
soft HTTP errors like 200 OK with a 404 Not Found HTML message.
|
||||||
Not Found HTML message.
|
|
||||||
|
|
||||||
The source code for this sample application can be found at:
|
The source code for this sample application can be found at:
|
||||||
:file:`samples/net/http_server`.
|
:file:`samples/net/http_server`.
|
||||||
|
@ -23,39 +22,24 @@ Requirements
|
||||||
************
|
************
|
||||||
|
|
||||||
- Linux machine with wget and the screen terminal emulator
|
- Linux machine with wget and the screen terminal emulator
|
||||||
- Freedom Board (FRDM-K64F)
|
- Either QEMU or real device like Freedom Board (FRDM-K64F)
|
||||||
- LAN for testing purposes (Ethernet)
|
- LAN for testing purposes (Ethernet)
|
||||||
|
|
||||||
Building and Running
|
Building and Running
|
||||||
********************
|
********************
|
||||||
|
|
||||||
Currently, the HTTP Server application is configured to listen at port 80,
|
Currently, the HTTP Server application is configured to listen at port 80.
|
||||||
This value is defined in the :file:`samples/net/http_server/src/config.h`
|
If you want to modify the http-server sample application, please check
|
||||||
file:
|
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.
|
||||||
|
|
||||||
.. code-block:: c
|
This sample code supports both static and dynamic (DHCPv4) IP addresses that
|
||||||
|
can be defined in the project configuration file:
|
||||||
#define ZEPHYR_PORT 80
|
|
||||||
|
|
||||||
Open the project configuration file for your platform, for example the
|
|
||||||
:file:`prj_frdm_k64f.conf` file is the configuration file for the
|
|
||||||
:ref:`frdm_k64f` board. 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.
|
|
||||||
|
|
||||||
This sample code only supports static IP addresses that are defined in the
|
|
||||||
project configuration file:
|
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.168.1.101"
|
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
|
||||||
|
|
||||||
Adding URLs
|
Adding URLs
|
||||||
===========
|
===========
|
||||||
|
@ -66,9 +50,11 @@ following lines:
|
||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
http_url_default_handler(http_write_soft_404_not_found);
|
http_server_add_default(&http_urls, http_response_soft_404);
|
||||||
http_url_add("/headers", HTTP_URL_STANDARD, http_write_header_fields);
|
http_server_add_url(&http_urls, "/headers", HTTP_URL_STANDARD,
|
||||||
http_url_add("/index.html", HTTP_URL_STANDARD, http_write_it_works);
|
http_response_header_fields);
|
||||||
|
http_server_add_url(&http_urls, "/index.html", HTTP_URL_STANDARD,
|
||||||
|
http_response_it_works);
|
||||||
|
|
||||||
The first line defines how Zephyr will deal with unknown URLs. In this case,
|
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
|
it will respond with a soft HTTP 404 status code, i.e. an HTTP 200 OK status
|
||||||
|
@ -114,19 +100,20 @@ serial console under other operating systems.
|
||||||
Sample Output
|
Sample Output
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Assume that this HTTP server is configured to listen at 192.168.1.101 port 80.
|
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:
|
On your Linux host computer, open a terminal window and type:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
wget 192.168.1.101/index.html
|
wget 192.168.1.120/index.html
|
||||||
|
|
||||||
wget will show:
|
wget will show:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
--2017-01-17 00:37:44-- http://192.168.1.101/
|
--2017-01-17 00:37:44-- http://192.168.1.120/
|
||||||
Connecting to 192.168.1.101:80... connected.
|
Connecting to 192.168.1.120:80... connected.
|
||||||
HTTP request sent, awaiting response... 200 OK
|
HTTP request sent, awaiting response... 200 OK
|
||||||
Length: unspecified [text/html]
|
Length: unspecified [text/html]
|
||||||
Saving to: 'index.html'
|
Saving to: 'index.html'
|
||||||
|
@ -146,32 +133,38 @@ The screen application will display the following information:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
[dev/eth_mcux] [INF] eth_0_init: Enabled 100M full-duplex mode.
|
[dev/eth_mcux] [DBG] eth_0_init: MAC 00:04:9f:52:44:02
|
||||||
[dev/eth_mcux] [DBG] eth_0_init: MAC 00:04:9f:c9:29:6e
|
[sample/net] [INF] net_sample_app_init: Run HTTPS server
|
||||||
Zephyr HTTP Server
|
[sample/net] [INF] setup_dhcpv4: Running
|
||||||
Address: 192.168.1.101, port: 80
|
[dev/eth_mcux] [DBG] eth_0_init: MAC 00:04:9f:f1:80:9e
|
||||||
|
[sample/net] [INF] net_sample_app_init: Run HTTPS server
|
||||||
----------------------------------------------------
|
[sample/net] [INF] setup_dhcpv4: Running dhcpv4 client...
|
||||||
[print_client_banner:42] Connection accepted
|
[sample/net] [INF] ipv6_event_handler: IPv6 address: 2001:db8::1
|
||||||
Address: 192.168.1.10, port: 54327
|
[dev/eth_mcux] [INF] eth_mcux_phy_event: Enabled 10M half-duplex mode.
|
||||||
[http_ctx_get:268] Free ctx found, index: 0
|
[sample/net] [INF] ipv4_addr_add_handler: IPv4 address: 192.168.1.120
|
||||||
[http_write:59] net_pkt_get_tx, rc: 0 <OK>
|
[sample/net] [INF] ipv4_addr_add_handler: Lease time: 86400 seconds
|
||||||
[http_write:82] net_context_send: 0 <OK>
|
[sample/net] [INF] ipv4_addr_add_handler: Subnet: 255.255.255.0
|
||||||
[http_rx_tx:86] Connection closed by peer
|
[sample/net] [INF] ipv4_addr_add_handler: Router: 192.168.1.1
|
||||||
|
[https/server] [INF] new_server: Zephyr HTTPS Server (0x20002370)
|
||||||
|
[https/server] [DBG] https_handler: (0x2000b5b4): HTTPS handler starting
|
||||||
|
[https/server] [INF] new_server: Zephyr HTTP Server (0x20001840)
|
||||||
|
[https/server] [INF] new_client: HTTP connection from 192.168.1.107:44410 (0x20006af4)
|
||||||
|
[https/server] [DBG] http_recv: (0x2000d6b4): Received 336 bytes data
|
||||||
|
[https/server] [DBG] http_process_recv: (0x2000d6b4): Calling handler 0x00000d89 context 0x20001840
|
||||||
|
|
||||||
|
|
||||||
To obtain the HTTP Header Fields web page, use the following command:
|
To obtain the HTTP Header Fields web page, use the following command:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
wget 192.168.1.101/headers -O index.html
|
wget 192.168.1.120/headers -O index.html
|
||||||
|
|
||||||
wget will show:
|
wget will show:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
--2017-01-19 22:09:55-- http://192.168.1.101/headers
|
--2017-01-19 22:09:55-- http://192.168.1.120/headers
|
||||||
Connecting to 192.168.1.101:80... connected.
|
Connecting to 192.168.1.120:80... connected.
|
||||||
HTTP request sent, awaiting response... 200 OK
|
HTTP request sent, awaiting response... 200 OK
|
||||||
Length: unspecified [text/html]
|
Length: unspecified [text/html]
|
||||||
Saving to: 'index.html'
|
Saving to: 'index.html'
|
||||||
|
@ -190,7 +183,7 @@ This is the HTML file generated by Zephyr and downloaded by wget:
|
||||||
<ul>
|
<ul>
|
||||||
<li>User-Agent: Wget/1.16 (linux-gnu)</li>
|
<li>User-Agent: Wget/1.16 (linux-gnu)</li>
|
||||||
<li>Accept: */*</li>
|
<li>Accept: */*</li>
|
||||||
<li>Host: 192.168.1.101</li>
|
<li>Host: 192.168.1.120</li>
|
||||||
<li>Connection: Keep-Alive</li>
|
<li>Connection: Keep-Alive</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>HTTP Method: GET</h2>
|
<h2>HTTP Method: GET</h2>
|
||||||
|
@ -203,7 +196,7 @@ To test the 404 Not Found soft error, use the following command:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
wget 192.168.1.101/not_found -O index.html
|
wget 192.168.1.120/not_found -O index.html
|
||||||
|
|
||||||
Zephyr will generate an HTTP response with the following header:
|
Zephyr will generate an HTTP response with the following header:
|
||||||
|
|
||||||
|
@ -224,32 +217,11 @@ and this is the HTML message that wget will save:
|
||||||
<body><h1><center>404 Not Found</center></h1></body>
|
<body><h1><center>404 Not Found</center></h1></body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
To test the HTTP Basic Authentication functionality, use the
|
|
||||||
following command:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
wget 192.168.1.101/auth -O index.html --user=zephyr --password=0123456789
|
|
||||||
|
|
||||||
the :file:`index.html` file will contain the following information:
|
|
||||||
|
|
||||||
.. code-block:: html
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Zephyr HTTP Server</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1><center>Zephyr HTTP server</center></h1>
|
|
||||||
<h2><center>user: zephyr, password: 0123456789</center></h2>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
HTTPS Server
|
HTTPS Server
|
||||||
============
|
============
|
||||||
|
|
||||||
The sample code also includes a HTTPS (HTTP over TLS) server example
|
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.
|
running side by side with the HTTP server, this server runs on QEMU.
|
||||||
In order to compile and run the code execute:
|
In order to compile and run the code execute:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
@ -266,25 +238,23 @@ The app will show the following on the screen:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
Zephyr HTTP Server
|
[https/server] [INF] new_client: HTTPS connection from 192.168.1.107:35982 (0x20006b4c)
|
||||||
Address: 192.0.2.1, port: 80
|
[https/server] [DBG] https_handler: (0x2000b5b4): Read HTTPS request
|
||||||
Zephyr HTTPS Server
|
[https/server] [DBG] https_handler: (0x2000b5b4): Write HTTPS response
|
||||||
Address: 192.0.2.1, port: 443
|
[https/server] [DBG] http_process_recv: (0x2000b5b4): Calling handler 0x00000ce9 context 0x20002370
|
||||||
failed
|
|
||||||
! mbedtls_ssl_handshake returned -29312
|
|
||||||
|
|
||||||
Now execute the following command on a different terminal window
|
Now execute the following command on a different terminal window
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
wget https://192.0.2.1 --no-check-certificate
|
wget https://192.168.1.120 --no-check-certificate
|
||||||
|
|
||||||
This will be shown on the screen
|
This will be shown on the screen
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
Connecting to 192.0.2.1:443... connected.
|
Connecting to 192.168.1.120:443... connected.
|
||||||
WARNING: cannot verify 192.0.2.1's certificate
|
WARNING: cannot verify 192.168.1.120's certificate
|
||||||
Unable to locally verify the issuer's authority.
|
Unable to locally verify the issuer's authority.
|
||||||
HTTP request sent, awaiting response... 200 OK
|
HTTP request sent, awaiting response... 200 OK
|
||||||
Length: unspecified [text/html]
|
Length: unspecified [text/html]
|
||||||
|
@ -304,7 +274,4 @@ Known Issues and Limitations
|
||||||
|
|
||||||
- Currently, this sample application only generates HTTP responses in
|
- Currently, this sample application only generates HTTP responses in
|
||||||
chunk transfer mode.
|
chunk transfer mode.
|
||||||
- Clients must close the connection to allow the HTTP server to release
|
- Basic authentication is not yet implemented.
|
||||||
the network context and accept another connection.
|
|
||||||
- The use of mbedTLS and IPv6 takes more than the available ram for the
|
|
||||||
emulation platform, so only IPv4 works for now in QEMU.
|
|
||||||
|
|
|
@ -11,26 +11,38 @@ CONFIG_NET_PKT_TX_COUNT=16
|
||||||
CONFIG_NET_BUF_RX_COUNT=16
|
CONFIG_NET_BUF_RX_COUNT=16
|
||||||
CONFIG_NET_BUF_TX_COUNT=16
|
CONFIG_NET_BUF_TX_COUNT=16
|
||||||
|
|
||||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2
|
||||||
CONFIG_NET_IFACE_UNICAST_IPV4_ADDR_COUNT=3
|
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4
|
||||||
|
|
||||||
|
CONFIG_NET_MAX_CONTEXTS=16
|
||||||
|
|
||||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||||
|
|
||||||
CONFIG_STDOUT_CONSOLE=y
|
CONFIG_STDOUT_CONSOLE=y
|
||||||
|
|
||||||
CONFIG_HTTP_SERVER=y
|
CONFIG_SYS_LOG_SHOW_COLOR=y
|
||||||
CONFIG_HTTP_PARSER=y
|
CONFIG_SYS_LOG_NET_LEVEL=4
|
||||||
|
CONFIG_NET_DEBUG_HTTP=y
|
||||||
|
|
||||||
|
CONFIG_HTTP_SERVER=y
|
||||||
|
|
||||||
# Enable IPv6 support
|
|
||||||
CONFIG_NET_IPV6=y
|
CONFIG_NET_IPV6=y
|
||||||
# Enable IPv4 support
|
CONFIG_NET_IPV4=y
|
||||||
CONFIG_NET_IPV4=n
|
#CONFIG_NET_DHCPV4=y
|
||||||
|
|
||||||
|
CONFIG_HTTPS=y
|
||||||
|
CONFIG_MBEDTLS=y
|
||||||
|
CONFIG_MBEDTLS_BUILTIN=y
|
||||||
|
CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h"
|
||||||
|
|
||||||
CONFIG_NET_APP_SETTINGS=y
|
CONFIG_NET_APP_SETTINGS=y
|
||||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.168.1.101"
|
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
|
||||||
|
|
||||||
CONFIG_NET_MAX_CONTEXTS=16
|
CONFIG_NET_SHELL=y
|
||||||
|
|
||||||
|
CONFIG_NET_MGMT=y
|
||||||
|
CONFIG_NET_MGMT_EVENT=y
|
||||||
|
|
||||||
# ENC28J60 Ethernet Device
|
# ENC28J60 Ethernet Device
|
||||||
CONFIG_ETH_ENC28J60=y
|
CONFIG_ETH_ENC28J60=y
|
||||||
|
@ -42,4 +54,3 @@ CONFIG_ETH_ENC28J60_0_MAC5=0x36
|
||||||
|
|
||||||
# Arduino 101
|
# Arduino 101
|
||||||
CONFIG_SPI=y
|
CONFIG_SPI=y
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
CONFIG_NETWORKING=y
|
CONFIG_NETWORKING=y
|
||||||
CONFIG_NET_TCP=y
|
CONFIG_NET_TCP=y
|
||||||
CONFIG_RANDOM_GENERATOR=y
|
CONFIG_RANDOM_GENERATOR=y
|
||||||
CONFIG_NET_ARP=y
|
|
||||||
CONFIG_NET_LOG=y
|
CONFIG_NET_LOG=y
|
||||||
CONFIG_INIT_STACKS=y
|
CONFIG_INIT_STACKS=y
|
||||||
|
|
||||||
|
@ -10,24 +9,32 @@ CONFIG_NET_PKT_TX_COUNT=16
|
||||||
CONFIG_NET_BUF_RX_COUNT=16
|
CONFIG_NET_BUF_RX_COUNT=16
|
||||||
CONFIG_NET_BUF_TX_COUNT=16
|
CONFIG_NET_BUF_TX_COUNT=16
|
||||||
|
|
||||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
|
||||||
CONFIG_NET_IFACE_UNICAST_IPV4_ADDR_COUNT=3
|
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4
|
||||||
|
|
||||||
CONFIG_STDOUT_CONSOLE=y
|
CONFIG_STDOUT_CONSOLE=y
|
||||||
|
|
||||||
CONFIG_HTTP_SERVER=y
|
CONFIG_SYS_LOG_SHOW_COLOR=y
|
||||||
CONFIG_HTTP_PARSER=y
|
CONFIG_SYS_LOG_NET_LEVEL=4
|
||||||
|
CONFIG_NET_DEBUG_HTTP=y
|
||||||
|
|
||||||
|
CONFIG_HTTP_SERVER=y
|
||||||
|
|
||||||
# Enable IPv6 support
|
|
||||||
CONFIG_NET_IPV6=y
|
CONFIG_NET_IPV6=y
|
||||||
# Enable IPv4 support
|
|
||||||
CONFIG_NET_IPV4=n
|
CONFIG_NET_IPV4=n
|
||||||
|
|
||||||
|
CONFIG_HTTPS=y
|
||||||
|
CONFIG_MBEDTLS=y
|
||||||
|
CONFIG_MBEDTLS_BUILTIN=y
|
||||||
|
CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h"
|
||||||
|
|
||||||
CONFIG_NET_APP_SETTINGS=y
|
CONFIG_NET_APP_SETTINGS=y
|
||||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.168.1.101"
|
|
||||||
|
|
||||||
CONFIG_NET_MAX_CONTEXTS=16
|
CONFIG_NET_SHELL=y
|
||||||
|
|
||||||
|
CONFIG_NET_MGMT=y
|
||||||
|
CONFIG_NET_MGMT_EVENT=y
|
||||||
|
|
||||||
CONFIG_BLUETOOTH=y
|
CONFIG_BLUETOOTH=y
|
||||||
CONFIG_BLUETOOTH_DEBUG_LOG=y
|
CONFIG_BLUETOOTH_DEBUG_LOG=y
|
||||||
|
@ -40,7 +47,7 @@ CONFIG_TEST_RANDOM_GENERATOR=y
|
||||||
CONFIG_NET_L2_BLUETOOTH=y
|
CONFIG_NET_L2_BLUETOOTH=y
|
||||||
CONFIG_NET_L2_BLUETOOTH_ZEP1656=y
|
CONFIG_NET_L2_BLUETOOTH_ZEP1656=y
|
||||||
CONFIG_NET_DEBUG_L2_BLUETOOTH=y
|
CONFIG_NET_DEBUG_L2_BLUETOOTH=y
|
||||||
CONFIG_SYS_LOG_SHOW_COLOR=y
|
|
||||||
CONFIG_NET_STATISTICS=y
|
CONFIG_NET_STATISTICS=y
|
||||||
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
|
|
||||||
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2
|
# This sample is meant to be compilable in QEMU only
|
||||||
|
CONFIG_RAM_SIZE=300
|
||||||
|
|
|
@ -11,21 +11,33 @@ CONFIG_NET_PKT_TX_COUNT=16
|
||||||
CONFIG_NET_BUF_RX_COUNT=16
|
CONFIG_NET_BUF_RX_COUNT=16
|
||||||
CONFIG_NET_BUF_TX_COUNT=16
|
CONFIG_NET_BUF_TX_COUNT=16
|
||||||
|
|
||||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2
|
||||||
CONFIG_NET_IFACE_UNICAST_IPV4_ADDR_COUNT=3
|
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4
|
||||||
|
|
||||||
|
CONFIG_NET_MAX_CONTEXTS=16
|
||||||
|
|
||||||
CONFIG_STDOUT_CONSOLE=y
|
CONFIG_STDOUT_CONSOLE=y
|
||||||
|
|
||||||
CONFIG_HTTP_SERVER=y
|
CONFIG_SYS_LOG_SHOW_COLOR=y
|
||||||
CONFIG_HTTP_PARSER=y
|
CONFIG_SYS_LOG_NET_LEVEL=4
|
||||||
|
CONFIG_NET_DEBUG_HTTP=y
|
||||||
|
|
||||||
# Enable IPv6 support
|
CONFIG_HTTP_SERVER=y
|
||||||
CONFIG_NET_IPV6=n
|
|
||||||
# Enable IPv4 support
|
CONFIG_NET_IPV6=y
|
||||||
CONFIG_NET_IPV4=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_NET_APP_SETTINGS=y
|
CONFIG_NET_APP_SETTINGS=y
|
||||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.168.1.101"
|
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
|
||||||
|
|
||||||
CONFIG_NET_MAX_CONTEXTS=16
|
CONFIG_NET_SHELL=y
|
||||||
|
|
||||||
|
CONFIG_NET_MGMT=y
|
||||||
|
CONFIG_NET_MGMT_EVENT=y
|
||||||
|
|
|
@ -8,29 +8,35 @@ CONFIG_INIT_STACKS=y
|
||||||
|
|
||||||
CONFIG_NET_PKT_RX_COUNT=16
|
CONFIG_NET_PKT_RX_COUNT=16
|
||||||
CONFIG_NET_PKT_TX_COUNT=16
|
CONFIG_NET_PKT_TX_COUNT=16
|
||||||
CONFIG_NET_BUF_RX_COUNT=8
|
CONFIG_NET_BUF_RX_COUNT=16
|
||||||
CONFIG_NET_BUF_TX_COUNT=8
|
CONFIG_NET_BUF_TX_COUNT=16
|
||||||
|
|
||||||
CONFIG_NET_IPV6_RA_RDNSS=y
|
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2
|
||||||
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
|
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4
|
||||||
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2
|
|
||||||
|
|
||||||
CONFIG_STDOUT_CONSOLE=y
|
CONFIG_NET_MAX_CONTEXTS=16
|
||||||
|
|
||||||
|
CONFIG_SYS_LOG_SHOW_COLOR=y
|
||||||
|
CONFIG_SYS_LOG_NET_LEVEL=2
|
||||||
|
CONFIG_NET_DEBUG_HTTP=y
|
||||||
|
|
||||||
CONFIG_HTTP_SERVER=y
|
CONFIG_HTTP_SERVER=y
|
||||||
CONFIG_HTTP_PARSER=y
|
|
||||||
|
|
||||||
# Enable IPv6 support
|
CONFIG_NET_IPV6=y
|
||||||
CONFIG_NET_IPV6=n
|
|
||||||
# Enable IPv4 support
|
|
||||||
CONFIG_NET_IPV4=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_NET_APP_SETTINGS=y
|
CONFIG_NET_APP_SETTINGS=y
|
||||||
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
|
||||||
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
|
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
|
||||||
|
|
||||||
CONFIG_NET_MAX_CONTEXTS=16
|
CONFIG_NET_SHELL=y
|
||||||
|
CONFIG_NET_STATISTICS=y
|
||||||
|
|
||||||
#CONFIG_MBEDTLS=y
|
CONFIG_NET_MGMT=y
|
||||||
#CONFIG_MBEDTLS_BUILTIN=y
|
CONFIG_NET_MGMT_EVENT=y
|
||||||
#CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h"
|
|
||||||
|
|
|
@ -4,15 +4,6 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-y += main.o
|
include $(ZEPHYR_BASE)/samples/net/common/Makefile.common
|
||||||
obj-y += http_utils.o
|
|
||||||
obj-y += http_server.o
|
|
||||||
obj-y += http_write_utils.o
|
|
||||||
ifdef CONFIG_MBEDTLS
|
|
||||||
obj-y += https_server.o ssl_utils.o
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_NET_L2_BLUETOOTH), y)
|
obj-y += main.o
|
||||||
ccflags-y +=-I${ZEPHYR_BASE}/samples/bluetooth/
|
|
||||||
obj-y += ../../../bluetooth/gatt/ipss.o
|
|
||||||
endif
|
|
||||||
|
|
|
@ -7,6 +7,11 @@
|
||||||
#ifndef _CONFIG_H_
|
#ifndef _CONFIG_H_
|
||||||
#define _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_APP_SETTINGS
|
#ifdef CONFIG_NET_APP_SETTINGS
|
||||||
#ifdef CONFIG_NET_IPV6
|
#ifdef CONFIG_NET_IPV6
|
||||||
#define ZEPHYR_ADDR CONFIG_NET_APP_MY_IPV6_ADDR
|
#define ZEPHYR_ADDR CONFIG_NET_APP_MY_IPV6_ADDR
|
||||||
|
@ -17,25 +22,12 @@
|
||||||
#ifdef CONFIG_NET_IPV6
|
#ifdef CONFIG_NET_IPV6
|
||||||
#define ZEPHYR_ADDR "2001:db8::1"
|
#define ZEPHYR_ADDR "2001:db8::1"
|
||||||
#else
|
#else
|
||||||
#define ZEPHYR_ADDR "192.168.1.101"
|
#define ZEPHYR_ADDR "192.0.2.1"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ZEPHYR_PORT 80
|
#ifndef ZEPHYR_PORT
|
||||||
|
#define ZEPHYR_PORT 8080
|
||||||
#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"
|
|
||||||
#define HTTP_AUTH_CREDENTIALS "emVwaHlyOjAxMjM0NTY3ODk="
|
|
||||||
|
|
||||||
#define APP_SLEEP_MSECS 500
|
|
||||||
|
|
||||||
#ifdef CONFIG_MBEDTLS
|
|
||||||
#define SERVER_PORT 443
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,57 +14,10 @@
|
||||||
#include <net/net_pkt.h>
|
#include <net/net_pkt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define URL_DEFAULT_HANDLER_INDEX 0
|
|
||||||
|
|
||||||
#define HTTP_BUF_CTR HTTP_MAX_NUMBER_SERVER_CTX
|
#define HTTP_BUF_CTR HTTP_MAX_NUMBER_SERVER_CTX
|
||||||
#define HTTP_BUF_SIZE 1024
|
#define HTTP_BUF_SIZE 1024
|
||||||
|
|
||||||
NET_BUF_POOL_DEFINE(http_msg_pool, HTTP_BUF_CTR, HTTP_BUF_SIZE, 0, NULL);
|
|
||||||
|
|
||||||
void http_accept_cb(struct net_context *net_ctx, struct sockaddr *addr,
|
|
||||||
socklen_t addr_len, int status, void *data)
|
|
||||||
{
|
|
||||||
struct http_server_ctx *http_ctx = NULL;
|
|
||||||
|
|
||||||
ARG_UNUSED(addr_len);
|
|
||||||
ARG_UNUSED(data);
|
|
||||||
|
|
||||||
if (status != 0) {
|
|
||||||
net_context_put(net_ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_client_banner(addr);
|
|
||||||
|
|
||||||
http_ctx = http_ctx_get();
|
|
||||||
if (!http_ctx) {
|
|
||||||
net_context_put(net_ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
http_ctx_set(http_ctx, net_ctx);
|
|
||||||
|
|
||||||
net_context_recv(net_ctx, http_rx_tx, K_NO_WAIT, http_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief http_ctx_release Releases an HTTP context
|
|
||||||
* @return 0, future versions may return error codes
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
int http_ctx_release(struct http_server_ctx *http_ctx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief parser_init Initializes some parser-related fields at the
|
|
||||||
* http_server_ctx structure
|
|
||||||
* @param ctx HTTP server context
|
|
||||||
* @param net_ctx Network context
|
|
||||||
* @return 0 on success
|
|
||||||
* @return -EINVAL on error
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
int parser_init(struct http_server_ctx *ctx);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief parser_parse_request Parses an HTTP REQUEST
|
* @brief parser_parse_request Parses an HTTP REQUEST
|
||||||
* @param ctx HTTP server context
|
* @param ctx HTTP server context
|
||||||
|
@ -82,359 +35,17 @@ static int http_url_cmp(const char *url, u16_t url_len,
|
||||||
|
|
||||||
static void http_tx(struct http_server_ctx *http_ctx);
|
static void http_tx(struct http_server_ctx *http_ctx);
|
||||||
|
|
||||||
void http_rx_tx(struct net_context *net_ctx, struct net_pkt *rx, int status,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
struct http_server_ctx *http_ctx = NULL;
|
|
||||||
struct net_buf *data = NULL;
|
|
||||||
u16_t rcv_len;
|
|
||||||
u16_t offset;
|
|
||||||
int parsed_len;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
printf("[%s:%d] Status code: %d, <%s>\n",
|
|
||||||
__func__, __LINE__, status, RC_STR(status));
|
|
||||||
goto lb_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user_data) {
|
|
||||||
printf("[%s:%d] User data is null\n", __func__, __LINE__);
|
|
||||||
goto lb_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
http_ctx = (struct http_server_ctx *)user_data;
|
|
||||||
if (http_ctx->net_ctx != net_ctx) {
|
|
||||||
printf("[%s:%d] Wrong network context received\n",
|
|
||||||
__func__, __LINE__);
|
|
||||||
goto lb_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rx) {
|
|
||||||
printf("[%s:%d] Connection closed by peer\n",
|
|
||||||
__func__, __LINE__);
|
|
||||||
goto lb_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
rcv_len = net_pkt_appdatalen(rx);
|
|
||||||
if (rcv_len == 0) {
|
|
||||||
/* don't print info about zero-length app data buffers */
|
|
||||||
goto lb_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = net_buf_alloc(&http_msg_pool, APP_SLEEP_MSECS);
|
|
||||||
if (data == NULL) {
|
|
||||||
printf("[%s:%d] Data buffer alloc error\n", __func__, __LINE__);
|
|
||||||
goto lb_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = net_pkt_get_len(rx) - rcv_len;
|
|
||||||
rc = net_frag_linear_copy(data, rx->frags, offset, rcv_len);
|
|
||||||
if (rc != 0) {
|
|
||||||
printf("[%s:%d] Linear copy error\n", __func__, __LINE__);
|
|
||||||
goto lb_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->data[min(data->size - 1, rcv_len)] = 0;
|
|
||||||
|
|
||||||
parser_init(http_ctx);
|
|
||||||
parsed_len = parser_parse_request(http_ctx, data);
|
|
||||||
if (parsed_len <= 0) {
|
|
||||||
printf("[%s:%d] Received: %u bytes, only parsed: %d bytes\n",
|
|
||||||
__func__, __LINE__, rcv_len, parsed_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (http_ctx->parser.http_errno != HPE_OK) {
|
|
||||||
http_response_400(http_ctx, NULL);
|
|
||||||
} else {
|
|
||||||
http_tx(http_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
lb_exit:
|
|
||||||
net_pkt_frag_unref(data);
|
|
||||||
net_pkt_unref(rx);
|
|
||||||
|
|
||||||
http_ctx_release(http_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief on_header_field HTTP Parser callback for header fields
|
|
||||||
* @param parser HTTP Parser
|
|
||||||
* @param at Points to where the field begins
|
|
||||||
* @param length Field's length
|
|
||||||
* @return 0 (always)
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
int on_header_field(struct http_parser *parser, const char *at, size_t length)
|
|
||||||
{
|
|
||||||
struct http_server_ctx *ctx = (struct http_server_ctx *)parser->data;
|
|
||||||
|
|
||||||
if (ctx->field_values_ctr >= HTTP_PARSER_MAX_FIELD_VALUES) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->field_values[ctx->field_values_ctr].key = at;
|
|
||||||
ctx->field_values[ctx->field_values_ctr].key_len = length;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief on_header_value HTTP Parser callback for header values
|
|
||||||
* @param parser HTTP Parser
|
|
||||||
* @param at Points to where the value begins
|
|
||||||
* @param length Value's length
|
|
||||||
* @return 0 (always)
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
int on_header_value(struct http_parser *parser, const char *at, size_t length)
|
|
||||||
{
|
|
||||||
struct http_server_ctx *ctx = (struct http_server_ctx *)parser->data;
|
|
||||||
|
|
||||||
if (ctx->field_values_ctr >= HTTP_PARSER_MAX_FIELD_VALUES) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->field_values[ctx->field_values_ctr].value = at;
|
|
||||||
ctx->field_values[ctx->field_values_ctr].value_len = length;
|
|
||||||
|
|
||||||
ctx->field_values_ctr++;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief on_url HTTP Parser callback for URLs
|
|
||||||
* @param parser HTTP Parser
|
|
||||||
* @param at Points to where the value begins
|
|
||||||
* @param length Value's length
|
|
||||||
* @return 0 (always)
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
int on_url(struct http_parser *parser, const char *at, size_t length)
|
|
||||||
{
|
|
||||||
struct http_server_ctx *ctx = (struct http_server_ctx *)parser->data;
|
|
||||||
|
|
||||||
ctx->url = at;
|
|
||||||
ctx->url_len = length;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int parser_init(struct http_server_ctx *ctx)
|
|
||||||
{
|
|
||||||
memset(ctx->field_values, 0x00, sizeof(ctx->field_values));
|
|
||||||
|
|
||||||
ctx->parser_settings.on_header_field = on_header_field;
|
|
||||||
ctx->parser_settings.on_header_value = on_header_value;
|
|
||||||
ctx->parser_settings.on_url = on_url;
|
|
||||||
|
|
||||||
http_parser_init(&ctx->parser, HTTP_REQUEST);
|
|
||||||
|
|
||||||
/* This circular reference is useful when some parser callbacks
|
|
||||||
* want to access some internal data structures
|
|
||||||
*/
|
|
||||||
ctx->parser.data = ctx;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int parser_parse_request(struct http_server_ctx *ctx, struct net_buf *rx)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
ctx->field_values_ctr = 0;
|
|
||||||
rc = http_parser_execute(&ctx->parser, &ctx->parser_settings,
|
|
||||||
rx->data, rx->len);
|
|
||||||
if (rc < 0) {
|
|
||||||
printf("[%s:%d] http_parser_execute: %s\n\t%s\n",
|
|
||||||
__func__, __LINE__,
|
|
||||||
http_errno_name(ctx->parser.http_errno),
|
|
||||||
http_errno_description(ctx->parser.http_errno));
|
|
||||||
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto exit_routine;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit_routine:
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief server_collection This is a collection of server ctx structs
|
* @brief server_collection This is a collection of server ctx structs
|
||||||
*/
|
*/
|
||||||
static struct http_server_ctx server_collection[HTTP_MAX_NUMBER_SERVER_CTX];
|
static struct http_server_ctx server_ctx[CONFIG_HTTP_SERVER_CONNECTIONS];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief http_url_ctx Just one URL context per application
|
* @brief http_url_ctx Just one URL context per application
|
||||||
*/
|
*/
|
||||||
static struct http_url_ctx url_ctx;
|
static struct http_url_ctx url_ctx;
|
||||||
|
|
||||||
int http_ctx_init(void)
|
|
||||||
{
|
|
||||||
memset(server_collection, 0x00, sizeof(server_collection));
|
|
||||||
|
|
||||||
memset(&url_ctx, 0x00, sizeof(url_ctx));
|
|
||||||
|
|
||||||
/* 0 is reserved for the default handler */
|
|
||||||
url_ctx.urls_ctr = 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct http_server_ctx *http_ctx_get(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < HTTP_MAX_NUMBER_SERVER_CTX; i++) {
|
|
||||||
|
|
||||||
if (server_collection[i].state == HTTP_CTX_FREE) {
|
|
||||||
|
|
||||||
printf("[%s:%d] Free ctx found, index: %d\n",
|
|
||||||
__func__, __LINE__, i);
|
|
||||||
|
|
||||||
memset(server_collection + i, 0x00,
|
|
||||||
sizeof(struct http_server_ctx));
|
|
||||||
|
|
||||||
return server_collection + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_ctx_set(struct http_server_ctx *http_ctx, struct net_context *net_ctx)
|
|
||||||
{
|
|
||||||
if (http_ctx == NULL || net_ctx == NULL) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
http_ctx->state = HTTP_CTX_IN_USE;
|
|
||||||
http_ctx->net_ctx = net_ctx;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int http_ctx_release(struct http_server_ctx *http_ctx)
|
|
||||||
{
|
|
||||||
if (http_ctx == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
http_ctx->state = HTTP_CTX_FREE;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_url_default_handler(int (*write_cb)(struct http_server_ctx *))
|
|
||||||
{
|
|
||||||
if (write_cb == NULL) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
url_ctx.urls[URL_DEFAULT_HANDLER_INDEX].flags = 0x00;
|
|
||||||
url_ctx.urls[URL_DEFAULT_HANDLER_INDEX].root = NULL;
|
|
||||||
url_ctx.urls[URL_DEFAULT_HANDLER_INDEX].root_len = 0;
|
|
||||||
url_ctx.urls[URL_DEFAULT_HANDLER_INDEX].write_cb = write_cb;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_url_add(const char *url, u8_t flags,
|
|
||||||
int (*write_cb)(struct http_server_ctx *http_ctx))
|
|
||||||
{
|
|
||||||
struct http_root_url *root = NULL;
|
|
||||||
|
|
||||||
if (url_ctx.urls_ctr >= HTTP_MAX_NUMBER_URL) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
root = &url_ctx.urls[url_ctx.urls_ctr];
|
|
||||||
|
|
||||||
root->root = url;
|
|
||||||
/* this will speed-up some future operations */
|
|
||||||
root->root_len = strlen(url);
|
|
||||||
root->flags = flags;
|
|
||||||
root->write_cb = write_cb;
|
|
||||||
|
|
||||||
url_ctx.urls_ctr++;
|
|
||||||
|
|
||||||
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 evlaute 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) {
|
|
||||||
if (root_url[root_url_len - 1] == '/') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url[root_url_len] == '/') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct http_root_url *http_url_find(struct http_server_ctx *http_ctx)
|
|
||||||
{
|
|
||||||
u16_t url_len = http_ctx->url_len;
|
|
||||||
const char *url = http_ctx->url;
|
|
||||||
struct http_root_url *root_url;
|
|
||||||
u8_t i;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* at some point we must come up with something better */
|
|
||||||
for (i = 1; i < url_ctx.urls_ctr; i++) {
|
|
||||||
root_url = &url_ctx.urls[i];
|
|
||||||
|
|
||||||
rc = http_url_cmp(url, url_len,
|
|
||||||
root_url->root, root_url->root_len);
|
|
||||||
if (rc == 0) {
|
|
||||||
return root_url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void http_tx(struct http_server_ctx *http_ctx)
|
|
||||||
{
|
|
||||||
struct http_root_url *root_url;
|
|
||||||
|
|
||||||
root_url = http_url_find(http_ctx);
|
|
||||||
if (!root_url) {
|
|
||||||
root_url = &url_ctx.urls[URL_DEFAULT_HANDLER_INDEX];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (root_url->write_cb) {
|
|
||||||
root_url->write_cb(http_ctx);
|
|
||||||
} else {
|
|
||||||
printf("[%s:%d] No default handler for %.*s\n",
|
|
||||||
__func__, __LINE__,
|
|
||||||
http_ctx->url_len, http_ctx->url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_auth(struct http_server_ctx *ctx)
|
int http_auth(struct http_server_ctx *ctx)
|
||||||
{
|
{
|
||||||
const char *auth_str = "Authorization: Basic "HTTP_AUTH_CREDENTIALS;
|
const char *auth_str = "Authorization: Basic "HTTP_AUTH_CREDENTIALS;
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _HTTP_TYPES_H_
|
|
||||||
#define _HTTP_TYPES_H_
|
|
||||||
|
|
||||||
#include <net/net_context.h>
|
|
||||||
#include <net/http.h>
|
|
||||||
|
|
||||||
/* Max number of HTTP header field-value pairs */
|
|
||||||
#define HTTP_PARSER_MAX_FIELD_VALUES CONFIG_HTTP_HEADER_FIELD_ITEMS
|
|
||||||
|
|
||||||
/* Max number of HTTP server context available to this app */
|
|
||||||
#define HTTP_MAX_NUMBER_SERVER_CTX CONFIG_NET_MAX_CONTEXTS
|
|
||||||
|
|
||||||
/* Max number of URLs this server will handle */
|
|
||||||
#define HTTP_MAX_NUMBER_URL 16
|
|
||||||
|
|
||||||
enum HTTP_URL_FLAGS {
|
|
||||||
HTTP_URL_STANDARD = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief http_root_url HTTP root URL struct, used for pattern matching
|
|
||||||
*/
|
|
||||||
struct http_root_url {
|
|
||||||
const char *root;
|
|
||||||
u16_t root_len;
|
|
||||||
|
|
||||||
u8_t flags;
|
|
||||||
int (*write_cb)(struct http_server_ctx *http_ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief http_url_ctx Collection of URLs that this server will handle
|
|
||||||
*/
|
|
||||||
struct http_url_ctx {
|
|
||||||
struct http_root_url urls[HTTP_MAX_NUMBER_URL];
|
|
||||||
u8_t urls_ctr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "http_utils.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#define IP6_SIZE 16
|
|
||||||
#define IP4_SIZE 4
|
|
||||||
|
|
||||||
#define STR_IP6_ADDR 64
|
|
||||||
#define STR_IP4_ADDR 16
|
|
||||||
|
|
||||||
static
|
|
||||||
void print_ipaddr(const struct sockaddr *ip_addr)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_NET_IPV6
|
|
||||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ip_addr;
|
|
||||||
void *raw = (void *)&addr->sin6_addr;
|
|
||||||
u16_t port = addr->sin6_port;
|
|
||||||
sa_family_t family = AF_INET6;
|
|
||||||
char str[STR_IP6_ADDR];
|
|
||||||
#else
|
|
||||||
struct sockaddr_in *addr = (struct sockaddr_in *)ip_addr;
|
|
||||||
void *raw = (void *)&addr->sin_addr;
|
|
||||||
u16_t port = addr->sin_port;
|
|
||||||
sa_family_t family = AF_INET;
|
|
||||||
char str[STR_IP4_ADDR];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
net_addr_ntop(family, raw, str, sizeof(str));
|
|
||||||
printf("Address: %s, port: %d\n", str, ntohs(port));
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_client_banner(const struct sockaddr *addr)
|
|
||||||
{
|
|
||||||
printf("\n----------------------------------------------------\n");
|
|
||||||
printf("[%s:%d] Connection accepted\n", __func__, __LINE__);
|
|
||||||
print_ipaddr(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void print_server_banner(const struct sockaddr *addr)
|
|
||||||
{
|
|
||||||
printf("Zephyr HTTP Server\n");
|
|
||||||
print_ipaddr(addr);
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __HTTP_UTILS_H__
|
|
||||||
#define __HTTP_UTILS_H__
|
|
||||||
|
|
||||||
#include <net/net_ip.h>
|
|
||||||
|
|
||||||
#define RC_STR(rc) (rc == 0 ? "OK" : "ERROR")
|
|
||||||
|
|
||||||
void print_client_banner(const struct sockaddr *addr);
|
|
||||||
|
|
||||||
void print_server_banner(const struct sockaddr *addr);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -11,100 +11,11 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define HTTP_STATUS_200_OK "HTTP/1.1 200 OK\r\n" \
|
|
||||||
"Content-Type: text/html\r\n" \
|
|
||||||
"Transfer-Encoding: chunked\r\n" \
|
|
||||||
"\r\n"
|
|
||||||
|
|
||||||
#define HTTP_401_STATUS_US "HTTP/1.1 401 Unauthorized status\r\n" \
|
|
||||||
"WWW-Authenticate: Basic realm=" \
|
|
||||||
"\""HTTP_AUTH_REALM"\"\r\n\r\n"
|
|
||||||
|
|
||||||
#define HTML_HEADER "<html><head>" \
|
|
||||||
"<title>Zephyr HTTP Server</title>" \
|
|
||||||
"</head><body><h1>" \
|
|
||||||
"<center>Zephyr HTTP server</center></h1>\r\n"
|
|
||||||
|
|
||||||
#define HTML_FOOTER "</body></html>\r\n"
|
|
||||||
|
|
||||||
/* Prints the received HTTP header fields as an HTML list */
|
|
||||||
static void print_http_headers(struct http_server_ctx *ctx,
|
|
||||||
char *str, u16_t size)
|
|
||||||
{
|
|
||||||
struct http_parser *parser = &ctx->parser;
|
|
||||||
u16_t offset = 0;
|
|
||||||
|
|
||||||
offset = snprintf(str, size,
|
|
||||||
HTML_HEADER
|
|
||||||
"<h2>HTTP Header Fields</h2>\r\n<ul>\r\n");
|
|
||||||
if (offset >= size) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u8_t i = 0; i < ctx->field_values_ctr; i++) {
|
|
||||||
struct http_field_value *kv = &ctx->field_values[i];
|
|
||||||
|
|
||||||
offset += snprintf(str + offset, size - offset,
|
|
||||||
"<li>%.*s: %.*s</li>\r\n",
|
|
||||||
kv->key_len, kv->key,
|
|
||||||
kv->value_len, kv->value);
|
|
||||||
if (offset >= size) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += snprintf(str + offset, size - offset, "</ul>\r\n");
|
|
||||||
if (offset >= size) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += snprintf(str + offset, size - offset,
|
|
||||||
"<h2>HTTP Method: %s</h2>\r\n",
|
|
||||||
http_method_str(parser->method));
|
|
||||||
if (offset >= size) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += snprintf(str + offset, size - offset,
|
|
||||||
"<h2>URL: %.*s</h2>\r\n",
|
|
||||||
ctx->url_len, ctx->url);
|
|
||||||
if (offset >= size) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(str + offset, size - offset,
|
|
||||||
"<h2>Server: %s</h2>"HTML_FOOTER, CONFIG_ARCH);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define HTTP_MAX_BODY_STR_SIZE 512
|
|
||||||
static char html_body[HTTP_MAX_BODY_STR_SIZE];
|
|
||||||
|
|
||||||
int http_response_header_fields(struct http_server_ctx *ctx)
|
|
||||||
{
|
|
||||||
print_http_headers(ctx, html_body, HTTP_MAX_BODY_STR_SIZE);
|
|
||||||
|
|
||||||
return http_response(ctx, HTTP_STATUS_200_OK, html_body);
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_response_it_works(struct http_server_ctx *ctx)
|
|
||||||
{
|
|
||||||
return http_response(ctx, HTTP_STATUS_200_OK, HTML_HEADER
|
|
||||||
"<body><h2><center>It Works!</center></h2>"
|
|
||||||
HTML_FOOTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_response_401(struct http_server_ctx *ctx)
|
int http_response_401(struct http_server_ctx *ctx)
|
||||||
{
|
{
|
||||||
return http_response(ctx, HTTP_401_STATUS_US, NULL);
|
return http_response(ctx, HTTP_401_STATUS_US, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_response_soft_404(struct http_server_ctx *ctx)
|
|
||||||
{
|
|
||||||
return http_response(ctx, HTTP_STATUS_200_OK, HTML_HEADER
|
|
||||||
"<h2><center>404 Not Found</center></h2>"
|
|
||||||
HTML_FOOTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_response_auth(struct http_server_ctx *ctx)
|
int http_response_auth(struct http_server_ctx *ctx)
|
||||||
{
|
{
|
||||||
return http_response(ctx, HTTP_STATUS_200_OK,
|
return http_response(ctx, HTTP_STATUS_200_OK,
|
||||||
|
|
|
@ -1,407 +0,0 @@
|
||||||
/* Minimal TLS server.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <zephyr.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <misc/printk.h>
|
|
||||||
|
|
||||||
#if !defined(CONFIG_MBEDTLS_CFG_FILE)
|
|
||||||
#include "mbedtls/config.h"
|
|
||||||
#else
|
|
||||||
#include CONFIG_MBEDTLS_CFG_FILE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(MBEDTLS_PLATFORM_C)
|
|
||||||
#include "mbedtls/platform.h"
|
|
||||||
#else
|
|
||||||
#include <stdlib.h>
|
|
||||||
#define mbedtls_time_t time_t
|
|
||||||
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
|
|
||||||
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <net/net_context.h>
|
|
||||||
#include <net/net_if.h>
|
|
||||||
#include "config.h"
|
|
||||||
#include "ssl_utils.h"
|
|
||||||
#include "test_certs.h"
|
|
||||||
|
|
||||||
#include "mbedtls/ssl_cookie.h"
|
|
||||||
#include "mbedtls/entropy.h"
|
|
||||||
#include "mbedtls/ctr_drbg.h"
|
|
||||||
#include "mbedtls/net_sockets.h"
|
|
||||||
#include "mbedtls/x509.h"
|
|
||||||
#include "mbedtls/ssl.h"
|
|
||||||
#include "mbedtls/error.h"
|
|
||||||
#include "mbedtls/debug.h"
|
|
||||||
|
|
||||||
#if defined(MBEDTLS_DEBUG_C)
|
|
||||||
#include "mbedtls/debug.h"
|
|
||||||
#define DEBUG_THRESHOLD 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
|
|
||||||
#include "mbedtls/memory_buffer_alloc.h"
|
|
||||||
static unsigned char heap[12000];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hardcoded values for server host and port
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const char *pers = "tls_server";
|
|
||||||
|
|
||||||
#if defined(CONFIG_NET_IPV6)
|
|
||||||
static struct in6_addr server_addr;
|
|
||||||
#else
|
|
||||||
static struct in_addr server_addr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct parsed_url {
|
|
||||||
const char *url;
|
|
||||||
u16_t url_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HTTP_RESPONSE \
|
|
||||||
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \
|
|
||||||
"<h2>Zephyr TLS Test Server</h2>\r\n" \
|
|
||||||
"<p>Successful connection</p>\r\n"
|
|
||||||
|
|
||||||
#define HTTP_NOT_FOUND \
|
|
||||||
"HTTP/1.0 404 NOT FOUND\r\nContent-Type: text/html\r\n\r\n" \
|
|
||||||
"<h2>Zephyr TLS page not found </h2>\r\n" \
|
|
||||||
"<p>Successful connection</p>\r\n"
|
|
||||||
|
|
||||||
static void my_debug(void *ctx, int level,
|
|
||||||
const char *file, int line, const char *str)
|
|
||||||
{
|
|
||||||
const char *p, *basename;
|
|
||||||
|
|
||||||
ARG_UNUSED(ctx);
|
|
||||||
|
|
||||||
/* Extract basename from file */
|
|
||||||
for (p = basename = file; *p != '\0'; p++) {
|
|
||||||
if (*p == '/' || *p == '\\') {
|
|
||||||
basename = p + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int entropy_source(void *data, unsigned char *output, size_t len,
|
|
||||||
size_t *olen)
|
|
||||||
{
|
|
||||||
u32_t seed;
|
|
||||||
|
|
||||||
ARG_UNUSED(data);
|
|
||||||
|
|
||||||
seed = sys_rand32_get();
|
|
||||||
|
|
||||||
if (len > sizeof(seed)) {
|
|
||||||
len = sizeof(seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(output, &seed, len);
|
|
||||||
|
|
||||||
*olen = len;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int on_url(struct http_parser *parser, const char *at, size_t length)
|
|
||||||
{
|
|
||||||
struct parsed_url *req = (struct parsed_url *)parser->data;
|
|
||||||
|
|
||||||
req->url = at;
|
|
||||||
req->url_len = length;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned char payload[256];
|
|
||||||
|
|
||||||
void https_server(void)
|
|
||||||
{
|
|
||||||
struct ssl_context ctx;
|
|
||||||
struct parsed_url request;
|
|
||||||
int ret, len = 0;
|
|
||||||
|
|
||||||
mbedtls_entropy_context entropy;
|
|
||||||
mbedtls_ctr_drbg_context ctr_drbg;
|
|
||||||
mbedtls_ssl_context ssl;
|
|
||||||
mbedtls_ssl_config conf;
|
|
||||||
mbedtls_x509_crt srvcert;
|
|
||||||
mbedtls_pk_context pkey;
|
|
||||||
|
|
||||||
mbedtls_platform_set_printf(printk);
|
|
||||||
|
|
||||||
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
|
|
||||||
mbedtls_memory_buffer_alloc_init(heap, sizeof(heap));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(MBEDTLS_DEBUG_C)
|
|
||||||
mbedtls_debug_set_threshold(DEBUG_THRESHOLD);
|
|
||||||
mbedtls_ssl_conf_dbg(&conf, my_debug, NULL);
|
|
||||||
#endif
|
|
||||||
mbedtls_x509_crt_init(&srvcert);
|
|
||||||
mbedtls_pk_init(&pkey);
|
|
||||||
mbedtls_ssl_init(&ssl);
|
|
||||||
mbedtls_ssl_config_init(&conf);
|
|
||||||
mbedtls_entropy_init(&entropy);
|
|
||||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 1. Load the certificates and private RSA key
|
|
||||||
*/
|
|
||||||
|
|
||||||
ret = mbedtls_x509_crt_parse(&srvcert, rsa_example_cert_der,
|
|
||||||
rsa_example_cert_der_len);
|
|
||||||
if (ret != 0) {
|
|
||||||
mbedtls_printf(" failed\n !"
|
|
||||||
" mbedtls_x509_crt_parse returned %d\n\n", ret);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = mbedtls_pk_parse_key(&pkey, rsa_example_keypair_der,
|
|
||||||
rsa_example_keypair_der_len, NULL, 0);
|
|
||||||
if (ret != 0) {
|
|
||||||
mbedtls_printf(" failed\n !"
|
|
||||||
" mbedtls_pk_parse_key returned %d\n\n", ret);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 3. Seed the RNG
|
|
||||||
*/
|
|
||||||
|
|
||||||
mbedtls_entropy_add_source(&entropy, entropy_source, NULL,
|
|
||||||
MBEDTLS_ENTROPY_MAX_GATHER,
|
|
||||||
MBEDTLS_ENTROPY_SOURCE_STRONG);
|
|
||||||
|
|
||||||
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
|
||||||
(const unsigned char *)pers, strlen(pers));
|
|
||||||
if (ret != 0) {
|
|
||||||
mbedtls_printf(" failed\n !"
|
|
||||||
" mbedtls_ctr_drbg_seed returned %d\n", ret);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 4. Setup stuff
|
|
||||||
*/
|
|
||||||
ret = mbedtls_ssl_config_defaults(&conf,
|
|
||||||
MBEDTLS_SSL_IS_SERVER,
|
|
||||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
|
||||||
MBEDTLS_SSL_PRESET_DEFAULT);
|
|
||||||
if (ret != 0) {
|
|
||||||
mbedtls_printf(" failed\n !"
|
|
||||||
" mbedtls_ssl_config_defaults returned %d\n\n",
|
|
||||||
ret);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
|
||||||
mbedtls_ssl_conf_dbg(&conf, my_debug, NULL);
|
|
||||||
|
|
||||||
mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL);
|
|
||||||
ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey);
|
|
||||||
if (ret != 0) {
|
|
||||||
mbedtls_printf(" failed\n !"
|
|
||||||
" mbedtls_ssl_conf_own_cert returned %d\n\n",
|
|
||||||
ret);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = mbedtls_ssl_setup(&ssl, &conf);
|
|
||||||
if (ret != 0) {
|
|
||||||
mbedtls_printf(" failed\n !"
|
|
||||||
" mbedtls_ssl_setup returned %d\n\n", ret);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 3. Wait until a client connects
|
|
||||||
*/
|
|
||||||
ret = ssl_init(&ctx, &server_addr);
|
|
||||||
if (ret != 0) {
|
|
||||||
mbedtls_printf(" failed\n ! ssl_init returned %d\n\n", ret);
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 4. Prepare http parser
|
|
||||||
*/
|
|
||||||
http_parser_init(&ctx.parser, HTTP_REQUEST);
|
|
||||||
http_parser_settings_init(&ctx.parser_settings);
|
|
||||||
ctx.parser.data = &request;
|
|
||||||
ctx.parser_settings.on_url = on_url;
|
|
||||||
|
|
||||||
mbedtls_printf("Zephyr HTTPS Server\n");
|
|
||||||
mbedtls_printf("Address: %s, port: %d\n", ZEPHYR_ADDR, SERVER_PORT);
|
|
||||||
reset:
|
|
||||||
mbedtls_ssl_session_reset(&ssl);
|
|
||||||
mbedtls_ssl_set_bio(&ssl, &ctx, ssl_tx, ssl_rx, NULL);
|
|
||||||
/*
|
|
||||||
* 5. Handshake
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
ret = mbedtls_ssl_handshake(&ssl);
|
|
||||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
|
|
||||||
ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
|
||||||
if (ret < 0) {
|
|
||||||
mbedtls_printf(" failed\n !"
|
|
||||||
" mbedtls_ssl_handshake returned %d\n\n",
|
|
||||||
ret);
|
|
||||||
goto reset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (ret != 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 6. Read the HTTPS Request
|
|
||||||
*/
|
|
||||||
mbedtls_printf("Read HTTPS request\n");
|
|
||||||
do {
|
|
||||||
len = sizeof(payload) - 1;
|
|
||||||
memset(payload, 0, sizeof(payload));
|
|
||||||
ret = mbedtls_ssl_read(&ssl, payload, len);
|
|
||||||
|
|
||||||
if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
|
|
||||||
ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret <= 0) {
|
|
||||||
switch (ret) {
|
|
||||||
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
|
|
||||||
mbedtls_printf(" connection was"
|
|
||||||
" closed gracefully\n");
|
|
||||||
goto close;
|
|
||||||
|
|
||||||
case MBEDTLS_ERR_NET_CONN_RESET:
|
|
||||||
mbedtls_printf(" connection was"
|
|
||||||
" reset by peer\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
mbedtls_printf
|
|
||||||
(" mbedtls_ssl_read returned -0x%x\n",
|
|
||||||
-ret);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = ret;
|
|
||||||
ret = http_parser_execute(&ctx.parser, &ctx.parser_settings,
|
|
||||||
payload, len);
|
|
||||||
if (ret < 0) {
|
|
||||||
}
|
|
||||||
} while (ret < 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 7. Write the Response
|
|
||||||
*/
|
|
||||||
mbedtls_printf("Write HTTPS response\n");
|
|
||||||
|
|
||||||
if (!strncmp("/index.html", request.url, request.url_len)) {
|
|
||||||
len = snprintf((char *)payload, sizeof(payload),
|
|
||||||
HTTP_RESPONSE);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
len = snprintf((char *)payload, sizeof(payload),
|
|
||||||
HTTP_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = mbedtls_ssl_write(&ssl, payload, len);
|
|
||||||
if (ret == MBEDTLS_ERR_NET_CONN_RESET) {
|
|
||||||
mbedtls_printf(" failed\n !"
|
|
||||||
" peer closed the connection\n");
|
|
||||||
goto reset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
|
|
||||||
ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
|
||||||
if (ret < 0) {
|
|
||||||
mbedtls_printf(" failed\n !"
|
|
||||||
" mbedtls_ssl_write"
|
|
||||||
" returned %d\n", ret);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (ret <= 0);
|
|
||||||
|
|
||||||
close:
|
|
||||||
|
|
||||||
mbedtls_ssl_close_notify(&ssl);
|
|
||||||
ret = 0;
|
|
||||||
goto reset;
|
|
||||||
|
|
||||||
exit:
|
|
||||||
#ifdef MBEDTLS_ERROR_C
|
|
||||||
if (ret != 0) {
|
|
||||||
mbedtls_strerror(ret, payload, 100);
|
|
||||||
mbedtls_printf("Last error was: %d - %s\n", ret, payload);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mbedtls_ssl_free(&ssl);
|
|
||||||
mbedtls_ssl_config_free(&conf);
|
|
||||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
|
||||||
mbedtls_entropy_free(&entropy);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STACK_SIZE 8192
|
|
||||||
u8_t stack[STACK_SIZE];
|
|
||||||
struct k_thread https_thread;
|
|
||||||
|
|
||||||
static inline int init_app(void)
|
|
||||||
{
|
|
||||||
#if defined(CONFIG_NET_IPV6)
|
|
||||||
if (net_addr_pton(AF_INET6, ZEPHYR_ADDR, &server_addr) < 0) {
|
|
||||||
mbedtls_printf("Invalid IPv6 address %s", ZEPHYR_ADDR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!net_if_ipv6_addr_add(net_if_get_default(), &server_addr,
|
|
||||||
NET_ADDR_MANUAL, 0)) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (net_addr_pton(AF_INET, ZEPHYR_ADDR, &server_addr) < 0) {
|
|
||||||
mbedtls_printf("Invalid IPv4 address %s", ZEPHYR_ADDR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!net_if_ipv4_addr_add(net_if_get_default(), &server_addr,
|
|
||||||
NET_ADDR_MANUAL, 0)) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void https_server_start(void)
|
|
||||||
{
|
|
||||||
if (init_app() != 0) {
|
|
||||||
printk("Cannot initialize network\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
k_thread_create(&https_thread, stack, STACK_SIZE,
|
|
||||||
(k_thread_entry_t) https_server,
|
|
||||||
NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0);
|
|
||||||
}
|
|
|
@ -4,144 +4,305 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <zephyr.h>
|
#if 1
|
||||||
#include <net/net_context.h>
|
#if defined(CONFIG_HTTPS)
|
||||||
|
#define SYS_LOG_DOMAIN "https-server"
|
||||||
#include <misc/printk.h>
|
#else
|
||||||
|
#define SYS_LOG_DOMAIN "http-server"
|
||||||
#if defined(CONFIG_NET_L2_BLUETOOTH)
|
#endif
|
||||||
#include <bluetooth/bluetooth.h>
|
#define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG
|
||||||
#include <gatt/ipss.h>
|
#define NET_LOG_ENABLED 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "http_types.h"
|
#include <zephyr.h>
|
||||||
#include "http_server.h"
|
#include <stdio.h>
|
||||||
#include "http_utils.h"
|
|
||||||
#include "http_write_utils.h"
|
#include <net/net_context.h>
|
||||||
|
#include <net/http.h>
|
||||||
|
|
||||||
|
#include <net_sample_app.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
/* Sets the network parameters */
|
/* Sets the network parameters */
|
||||||
static
|
|
||||||
int network_setup(struct net_context **net_ctx, net_tcp_accept_cb_t accept_cb,
|
|
||||||
const char *addr, u16_t port);
|
|
||||||
|
|
||||||
#if defined(CONFIG_MBEDTLS)
|
#define RESULT_BUF_SIZE 1024
|
||||||
#include "ssl_utils.h"
|
static u8_t http_result[RESULT_BUF_SIZE];
|
||||||
#endif
|
|
||||||
|
#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_HTTPS_STACK_SIZE,
|
||||||
|
CONFIG_HTTPS_STACK_SIZE);
|
||||||
|
|
||||||
|
#define RX_FIFO_DEPTH 4
|
||||||
|
K_MEM_POOL_DEFINE(ssl_rx_pool, 4, 64, RX_FIFO_DEPTH, 4);
|
||||||
|
|
||||||
|
static struct http_server_ctx https_ctx;
|
||||||
|
|
||||||
|
static u8_t https_result[RESULT_BUF_SIZE];
|
||||||
|
|
||||||
|
#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_server_ctx http_ctx;
|
||||||
|
static struct http_server_urls http_urls;
|
||||||
|
|
||||||
|
void panic(const char *msg)
|
||||||
|
{
|
||||||
|
if (msg) {
|
||||||
|
NET_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" \
|
||||||
|
"\r\n"
|
||||||
|
|
||||||
|
#define HTML_HEADER "<html><head>" \
|
||||||
|
"<title>Zephyr HTTP Server</title>" \
|
||||||
|
"</head><body><h1>" \
|
||||||
|
"<center>Zephyr HTTP server</center></h1>\r\n"
|
||||||
|
|
||||||
|
#define HTML_FOOTER "</body></html>\r\n"
|
||||||
|
|
||||||
|
/* Prints the received HTTP header fields as an HTML list */
|
||||||
|
static void print_http_headers(struct http_server_ctx *ctx,
|
||||||
|
char *str, int size)
|
||||||
|
{
|
||||||
|
int offset;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = snprintf(str, size,
|
||||||
|
HTML_HEADER
|
||||||
|
"<h2>HTTP Header Fields</h2>\r\n<ul>\r\n");
|
||||||
|
if (ret < 0 || ret >= size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = ret;
|
||||||
|
|
||||||
|
for (u8_t i = 0; i < ctx->req.field_values_ctr; i++) {
|
||||||
|
struct http_field_value *kv = &ctx->req.field_values[i];
|
||||||
|
|
||||||
|
ret = snprintf(str + offset, size - offset,
|
||||||
|
"<li>%.*s: %.*s</li>\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, "</ul>\r\n");
|
||||||
|
if (ret < 0 || ret >= size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += ret;
|
||||||
|
|
||||||
|
ret = snprintf(str + offset, size - offset,
|
||||||
|
"<h2>HTTP Method: %s</h2>\r\n",
|
||||||
|
http_method_str(ctx->req.parser.method));
|
||||||
|
if (ret < 0 || ret >= size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += ret;
|
||||||
|
|
||||||
|
ret = snprintf(str + offset, size - offset,
|
||||||
|
"<h2>URL: %.*s</h2>\r\n",
|
||||||
|
ctx->req.url_len, ctx->req.url);
|
||||||
|
if (ret < 0 || ret >= size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += ret;
|
||||||
|
|
||||||
|
snprintf(str + offset, size - offset,
|
||||||
|
"<h2>Server: %s</h2>"HTML_FOOTER, CONFIG_ARCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_response_header_fields(struct http_server_ctx *ctx)
|
||||||
|
{
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int http_response_it_works(struct http_server_ctx *ctx)
|
||||||
|
{
|
||||||
|
return http_response(ctx, HTTP_STATUS_200_OK, HTML_HEADER
|
||||||
|
"<body><h2><center>It Works!</center></h2>"
|
||||||
|
HTML_FOOTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int http_response_soft_404(struct http_server_ctx *ctx)
|
||||||
|
{
|
||||||
|
return http_response(ctx, HTTP_STATUS_200_OK, HTML_HEADER
|
||||||
|
"<h2><center>404 Not Found</center></h2>"
|
||||||
|
HTML_FOOTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_HTTPS)
|
||||||
|
/* Load the certificates and private RSA key. */
|
||||||
|
|
||||||
|
#include "test_certs.h"
|
||||||
|
|
||||||
|
static int setup_cert(struct http_server_ctx *ctx,
|
||||||
|
mbedtls_x509_crt *cert,
|
||||||
|
mbedtls_pk_context *pkey)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = mbedtls_x509_crt_parse(cert, rsa_example_cert_der,
|
||||||
|
rsa_example_cert_der_len);
|
||||||
|
if (ret != 0) {
|
||||||
|
NET_ERR("mbedtls_x509_crt_parse returned %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mbedtls_pk_parse_key(pkey, rsa_example_keypair_der,
|
||||||
|
rsa_example_keypair_der_len, NULL, 0);
|
||||||
|
if (ret != 0) {
|
||||||
|
NET_ERR("mbedtls_pk_parse_key returned %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_HTTPS */
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_NET_L2_BLUETOOTH)
|
struct sockaddr addr, *server_addr;
|
||||||
int err;
|
u32_t flags = 0;
|
||||||
|
int ret;
|
||||||
err = bt_enable(NULL);
|
|
||||||
if (err) {
|
|
||||||
printk("Bluetooth init failed (err %d)\n", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printk("Bluetooth initialized\n");
|
|
||||||
|
|
||||||
ipss_init();
|
|
||||||
|
|
||||||
err = ipss_advertise();
|
|
||||||
if (err) {
|
|
||||||
printk("Advertising failed to start (err %d)\n", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printk("Advertising successfully started\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct net_context *net_ctx = NULL;
|
|
||||||
|
|
||||||
http_ctx_init();
|
|
||||||
|
|
||||||
http_url_default_handler(http_response_soft_404);
|
|
||||||
http_url_add(HTTP_AUTH_URL, HTTP_URL_STANDARD, http_auth);
|
|
||||||
http_url_add("/headers", HTTP_URL_STANDARD,
|
|
||||||
http_response_header_fields);
|
|
||||||
http_url_add("/index.html", HTTP_URL_STANDARD, http_response_it_works);
|
|
||||||
|
|
||||||
network_setup(&net_ctx, http_accept_cb, ZEPHYR_ADDR, ZEPHYR_PORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int network_setup(struct net_context **net_ctx, net_tcp_accept_cb_t accept_cb,
|
|
||||||
const char *addr, u16_t port)
|
|
||||||
{
|
|
||||||
struct sockaddr local_sock;
|
|
||||||
void *ptr;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
*net_ctx = NULL;
|
|
||||||
|
|
||||||
#ifdef CONFIG_NET_IPV6
|
|
||||||
net_sin6(&local_sock)->sin6_port = htons(port);
|
|
||||||
local_sock.family = AF_INET6;
|
|
||||||
ptr = &(net_sin6(&local_sock)->sin6_addr);
|
|
||||||
rc = net_addr_pton(AF_INET6, addr, ptr);
|
|
||||||
#else
|
|
||||||
net_sin(&local_sock)->sin_port = htons(port);
|
|
||||||
local_sock.family = AF_INET;
|
|
||||||
ptr = &(net_sin(&local_sock)->sin_addr);
|
|
||||||
rc = net_addr_pton(AF_INET, addr, ptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (rc) {
|
|
||||||
printk("Invalid IP address/Port: %s, %d\n", addr, port);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_NET_IPV6
|
|
||||||
ptr = net_if_ipv6_addr_add(net_if_get_default(),
|
|
||||||
&net_sin6(&local_sock)->sin6_addr,
|
|
||||||
NET_ADDR_MANUAL, 0);
|
|
||||||
#else
|
|
||||||
ptr = net_if_ipv4_addr_add(net_if_get_default(),
|
|
||||||
&net_sin(&local_sock)->sin_addr,
|
|
||||||
NET_ADDR_MANUAL, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have both IPv6 and IPv4 enabled, then set the
|
||||||
|
* startup flags so that we wait until both are ready
|
||||||
|
* before continuing.
|
||||||
|
*/
|
||||||
#if defined(CONFIG_NET_IPV6)
|
#if defined(CONFIG_NET_IPV6)
|
||||||
rc = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, net_ctx);
|
flags |= NET_SAMPLE_NEED_IPV6;
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_NET_IPV4)
|
||||||
|
flags |= NET_SAMPLE_NEED_IPV4;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret = net_sample_app_init(APP_BANNER, flags, APP_STARTUP_TIME);
|
||||||
|
if (ret < 0) {
|
||||||
|
panic("Application init failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 */
|
||||||
|
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 */
|
||||||
|
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) {
|
||||||
|
NET_ERR("Cannot set local address (%d)", ret);
|
||||||
|
panic(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
server_addr = &addr;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
rc = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, net_ctx);
|
server_addr = NULL;
|
||||||
|
|
||||||
|
ARG_UNUSED(addr);
|
||||||
#endif
|
#endif
|
||||||
if (rc != 0) {
|
|
||||||
printk("net_context_get error\n");
|
http_server_add_default(&http_urls, http_response_soft_404);
|
||||||
return rc;
|
http_server_add_url(&http_urls, "/headers", HTTP_URL_STANDARD,
|
||||||
|
http_response_header_fields);
|
||||||
|
http_server_add_url(&http_urls, "/index.html", HTTP_URL_STANDARD,
|
||||||
|
http_response_it_works);
|
||||||
|
|
||||||
|
#if defined(CONFIG_HTTPS)
|
||||||
|
ret = https_server_init(&https_ctx, &http_urls, server_addr,
|
||||||
|
https_result, sizeof(https_result),
|
||||||
|
"Zephyr HTTPS Server",
|
||||||
|
INSTANCE_INFO, strlen(INSTANCE_INFO),
|
||||||
|
setup_cert, NULL, &ssl_rx_pool,
|
||||||
|
https_stack, sizeof(https_stack));
|
||||||
|
if (ret < 0) {
|
||||||
|
NET_ERR("Cannot initialize HTTPS server (%d)", ret);
|
||||||
|
panic(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = net_context_bind(*net_ctx, (const struct sockaddr *)&local_sock,
|
http_server_enable(&https_ctx);
|
||||||
sizeof(local_sock));
|
|
||||||
if (rc != 0) {
|
|
||||||
printk("net_context_bind error\n");
|
|
||||||
goto lb_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = net_context_listen(*net_ctx, 0);
|
|
||||||
if (rc != 0) {
|
|
||||||
printk("net_context_listen error\n");
|
|
||||||
goto lb_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = net_context_accept(*net_ctx, accept_cb, 0, NULL);
|
|
||||||
if (rc != 0) {
|
|
||||||
printk("net_context_accept error\n");
|
|
||||||
goto lb_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_server_banner(&local_sock);
|
|
||||||
|
|
||||||
#if defined(CONFIG_MBEDTLS)
|
|
||||||
https_server_start();
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
|
||||||
|
|
||||||
lb_error:
|
ret = http_server_init(&http_ctx, &http_urls, server_addr, http_result,
|
||||||
net_context_put(*net_ctx);
|
sizeof(http_result), "Zephyr HTTP Server");
|
||||||
*net_ctx = NULL;
|
if (ret < 0) {
|
||||||
|
NET_ERR("Cannot initialize HTTP server (%d)", ret);
|
||||||
return rc;
|
panic(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,289 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <zephyr.h>
|
|
||||||
#include <net/net_core.h>
|
|
||||||
#include <net/net_context.h>
|
|
||||||
#include <net/net_pkt.h>
|
|
||||||
#include <net/net_if.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <misc/printk.h>
|
|
||||||
|
|
||||||
#if !defined(CONFIG_MBEDTLS_CFG_FILE)
|
|
||||||
#include "mbedtls/config.h"
|
|
||||||
#else
|
|
||||||
#include CONFIG_MBEDTLS_CFG_FILE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "mbedtls/ssl.h"
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "ssl_utils.h"
|
|
||||||
|
|
||||||
#define RX_FIFO_DEPTH 4
|
|
||||||
|
|
||||||
K_MEM_POOL_DEFINE(rx_pkts, 4, 64, RX_FIFO_DEPTH, 4);
|
|
||||||
|
|
||||||
static void ssl_received(struct net_context *context,
|
|
||||||
struct net_buf *buf, int status, void *user_data)
|
|
||||||
{
|
|
||||||
struct ssl_context *ctx = user_data;
|
|
||||||
struct rx_fifo_block *rx_data = NULL;
|
|
||||||
struct k_mem_block block;
|
|
||||||
|
|
||||||
ARG_UNUSED(context);
|
|
||||||
ARG_UNUSED(status);
|
|
||||||
|
|
||||||
if (!net_pkt_appdatalen(buf)) {
|
|
||||||
net_pkt_unref(buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
k_mem_pool_alloc(&rx_pkts, &block,
|
|
||||||
sizeof(struct rx_fifo_block), K_FOREVER);
|
|
||||||
rx_data = block.data;
|
|
||||||
rx_data->buf = buf;
|
|
||||||
|
|
||||||
/* For freeing memory later */
|
|
||||||
memcpy(&rx_data->block, &block, sizeof(struct k_mem_block));
|
|
||||||
k_fifo_put(&ctx->rx_fifo, (void *)rx_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ssl_sent(struct net_context *context,
|
|
||||||
int status, void *token, void *user_data)
|
|
||||||
{
|
|
||||||
struct ssl_context *ctx = user_data;
|
|
||||||
|
|
||||||
k_sem_give(&ctx->tx_sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ssl_tx(void *context, const unsigned char *buf, size_t size)
|
|
||||||
{
|
|
||||||
struct ssl_context *ctx = context;
|
|
||||||
struct net_context *net_ctx;
|
|
||||||
struct net_buf *send_buf;
|
|
||||||
|
|
||||||
int rc, len;
|
|
||||||
|
|
||||||
net_ctx = ctx->net_ctx;
|
|
||||||
|
|
||||||
send_buf = net_pkt_get_tx(net_ctx, K_NO_WAIT);
|
|
||||||
if (!send_buf) {
|
|
||||||
return MBEDTLS_ERR_SSL_ALLOC_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = net_pkt_append(send_buf, size, (u8_t *) buf, K_FOREVER);
|
|
||||||
|
|
||||||
rc = net_context_send(send_buf, ssl_sent, K_NO_WAIT, NULL, ctx);
|
|
||||||
|
|
||||||
if (rc < 0) {
|
|
||||||
net_pkt_unref(send_buf);
|
|
||||||
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
k_sem_take(&ctx->tx_sem, K_FOREVER);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ssl_rx(void *context, unsigned char *buf, size_t size)
|
|
||||||
{
|
|
||||||
struct ssl_context *ctx = context;
|
|
||||||
u16_t read_bytes;
|
|
||||||
struct rx_fifo_block *rx_data;
|
|
||||||
u8_t *ptr;
|
|
||||||
int pos;
|
|
||||||
int len;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
if (ctx->frag == NULL) {
|
|
||||||
rx_data = k_fifo_get(&ctx->rx_fifo, K_FOREVER);
|
|
||||||
ctx->rx_pkt = rx_data->buf;
|
|
||||||
k_mem_pool_free(&rx_data->block);
|
|
||||||
|
|
||||||
read_bytes = net_pkt_appdatalen(ctx->rx_pkt);
|
|
||||||
|
|
||||||
ctx->remaining = read_bytes;
|
|
||||||
ctx->frag = ctx->rx_pkt->frags;
|
|
||||||
ptr = net_pkt_appdata(ctx->rx_pkt);
|
|
||||||
|
|
||||||
len = ptr - ctx->frag->data;
|
|
||||||
net_buf_pull(ctx->frag, len);
|
|
||||||
} else {
|
|
||||||
read_bytes = ctx->remaining;
|
|
||||||
ptr = ctx->frag->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = ctx->frag->len;
|
|
||||||
pos = 0;
|
|
||||||
if (read_bytes > size) {
|
|
||||||
while (ctx->frag) {
|
|
||||||
read_bytes = len < (size - pos) ? len : (size - pos);
|
|
||||||
memcpy(buf + pos, ptr, read_bytes);
|
|
||||||
pos += read_bytes;
|
|
||||||
if (pos < size) {
|
|
||||||
ctx->frag = ctx->frag->frags;
|
|
||||||
ptr = ctx->frag->data;
|
|
||||||
len = ctx->frag->len;
|
|
||||||
} else {
|
|
||||||
if (read_bytes == len) {
|
|
||||||
ctx->frag = ctx->frag->frags;
|
|
||||||
} else {
|
|
||||||
net_buf_pull(ctx->frag, read_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->remaining -= size;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (ctx->frag) {
|
|
||||||
memcpy(buf + pos, ptr, len);
|
|
||||||
pos += len;
|
|
||||||
ctx->frag = ctx->frag->frags;
|
|
||||||
if (!ctx->frag) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = ctx->frag->data;
|
|
||||||
len = ctx->frag->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_pkt_unref(ctx->rx_pkt);
|
|
||||||
ctx->rx_pkt = NULL;
|
|
||||||
ctx->frag = NULL;
|
|
||||||
ctx->remaining = 0;
|
|
||||||
|
|
||||||
if (read_bytes != pos) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = read_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ssl_accepted(struct net_context *context,
|
|
||||||
struct sockaddr *addr,
|
|
||||||
socklen_t addrlen, int error, void *user_data)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct ssl_context *ctx = user_data;
|
|
||||||
|
|
||||||
ctx->net_ctx = context;
|
|
||||||
ret = net_context_recv(context, ssl_received, 0, user_data);
|
|
||||||
if (ret < 0) {
|
|
||||||
printk("Cannot receive TCP packet (family %d)",
|
|
||||||
net_context_get_family(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CONFIG_NET_IPV6)
|
|
||||||
int ssl_init(struct ssl_context *ctx, void *addr)
|
|
||||||
{
|
|
||||||
struct net_context *tcp_ctx = { 0 };
|
|
||||||
struct sockaddr_in6 my_addr = { 0 };
|
|
||||||
struct in6_addr *server_addr = addr;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
k_sem_init(&ctx->tx_sem, 0, UINT_MAX);
|
|
||||||
k_fifo_init(&ctx->rx_fifo);
|
|
||||||
|
|
||||||
my_mcast_addr.sin6_family = AF_INET6;
|
|
||||||
|
|
||||||
net_ipaddr_copy(&my_addr.sin6_addr, server_addr);
|
|
||||||
my_addr.sin6_family = AF_INET6;
|
|
||||||
my_addr.sin6_port = htons(SERVER_PORT);
|
|
||||||
|
|
||||||
rc = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &tcp_ctx);
|
|
||||||
if (rc < 0) {
|
|
||||||
printk("Cannot get network context for IPv6 TCP (%d)", rc);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = net_context_bind(tcp_ctx, (struct sockaddr *)&my_addr,
|
|
||||||
sizeof(struct sockaddr_in6));
|
|
||||||
if (rc < 0) {
|
|
||||||
printk("Cannot bind IPv6 TCP port %d (%d)", SERVER_PORT, rc);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->rx_pkt = NULL;
|
|
||||||
ctx->remaining = 0;
|
|
||||||
ctx->net_ctx = tcp_ctx;
|
|
||||||
|
|
||||||
rc = net_context_listen(ctx->net_ctx, 0);
|
|
||||||
if (rc < 0) {
|
|
||||||
printk("Cannot listen IPv6 TCP (%d)", rc);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = net_context_accept(ctx->net_ctx, ssl_accepted, 0, ctx);
|
|
||||||
if (rc < 0) {
|
|
||||||
printk("Cannot accept IPv4 (%d)", rc);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
net_context_put(tcp_ctx);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
int ssl_init(struct ssl_context *ctx, void *addr)
|
|
||||||
{
|
|
||||||
struct net_context *tcp_ctx = { 0 };
|
|
||||||
struct sockaddr_in my_addr4 = { 0 };
|
|
||||||
struct in_addr *server_addr = addr;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
k_sem_init(&ctx->tx_sem, 0, UINT_MAX);
|
|
||||||
k_fifo_init(&ctx->rx_fifo);
|
|
||||||
|
|
||||||
net_ipaddr_copy(&my_addr4.sin_addr, server_addr);
|
|
||||||
my_addr4.sin_family = AF_INET;
|
|
||||||
my_addr4.sin_port = htons(SERVER_PORT);
|
|
||||||
|
|
||||||
rc = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &tcp_ctx);
|
|
||||||
if (rc < 0) {
|
|
||||||
printk("Cannot get network context for IPv4 TCP (%d)", rc);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = net_context_bind(tcp_ctx, (struct sockaddr *)&my_addr4,
|
|
||||||
sizeof(struct sockaddr_in));
|
|
||||||
if (rc < 0) {
|
|
||||||
printk("Cannot bind IPv4 TCP port %d (%d)", SERVER_PORT, rc);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->rx_pkt = NULL;
|
|
||||||
ctx->remaining = 0;
|
|
||||||
ctx->net_ctx = tcp_ctx;
|
|
||||||
|
|
||||||
rc = net_context_listen(ctx->net_ctx, 0);
|
|
||||||
if (rc < 0) {
|
|
||||||
printk("Cannot listen IPv4 (%d)", rc);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = net_context_accept(ctx->net_ctx, ssl_accepted, 0, ctx);
|
|
||||||
if (rc < 0) {
|
|
||||||
printk("Cannot accept IPv4 (%d)", rc);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
net_context_put(tcp_ctx);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2017 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SSL_UTILS_H_
|
|
||||||
#define _SSL_UTILS_H_
|
|
||||||
|
|
||||||
#include <net/net_core.h>
|
|
||||||
#include <net/http_parser.h>
|
|
||||||
|
|
||||||
struct rx_fifo_block {
|
|
||||||
sys_snode_t snode;
|
|
||||||
struct k_mem_block block;
|
|
||||||
struct net_buf *buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ssl_context {
|
|
||||||
struct net_context *net_ctx;
|
|
||||||
struct net_buf *rx_pkt;
|
|
||||||
struct net_buf *frag;
|
|
||||||
struct k_sem tx_sem;
|
|
||||||
struct k_fifo rx_fifo;
|
|
||||||
struct http_parser_settings parser_settings;
|
|
||||||
struct http_parser parser;
|
|
||||||
|
|
||||||
int remaining;
|
|
||||||
};
|
|
||||||
|
|
||||||
int ssl_init(struct ssl_context *ctx, void *addr);
|
|
||||||
int ssl_tx(void *ctx, const unsigned char *buf, size_t size);
|
|
||||||
int ssl_rx(void *ctx, unsigned char *buf, size_t size);
|
|
||||||
|
|
||||||
void https_server_start(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,10 +1,10 @@
|
||||||
[test]
|
[test]
|
||||||
tags = net http
|
tags = net http
|
||||||
build_only = true
|
build_only = true
|
||||||
platform_whitelist = frdm_k64f qemu_x86 arduino_101
|
platform_whitelist = frdm_k64f qemu_x86
|
||||||
|
|
||||||
[test_bt]
|
[test_bt]
|
||||||
tags = net bluetooth
|
tags = net bluetooth
|
||||||
build_only = true
|
build_only = true
|
||||||
extra_args = CONF_FILE="prj_bt.conf"
|
extra_args = CONF_FILE="prj_bt.conf"
|
||||||
platform_whitelist = arduino_101
|
platform_whitelist = qemu_x86
|
||||||
|
|
|
@ -13,9 +13,25 @@ config HTTP_SERVER
|
||||||
bool "HTTP server support"
|
bool "HTTP server support"
|
||||||
default n
|
default n
|
||||||
select HTTP
|
select HTTP
|
||||||
|
select HTTP_PARSER
|
||||||
help
|
help
|
||||||
Enables HTTP server routines
|
Enables HTTP server routines
|
||||||
|
|
||||||
|
config HTTP_SERVER_CONNECTIONS
|
||||||
|
int "Max number of HTTP server connections"
|
||||||
|
default NET_MAX_CONTEXTS
|
||||||
|
depends on HTTP_SERVER
|
||||||
|
help
|
||||||
|
This value determines how many simultaneous HTTP connections the
|
||||||
|
HTTP server can serve.
|
||||||
|
|
||||||
|
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_HEADER_FIELD_ITEMS
|
config HTTP_HEADER_FIELD_ITEMS
|
||||||
int "HTTP header field max number of items"
|
int "HTTP header field max number of items"
|
||||||
depends on HTTP_SERVER
|
depends on HTTP_SERVER
|
||||||
|
@ -48,6 +64,33 @@ config HTTP_PARSER_STRICT
|
||||||
help
|
help
|
||||||
This option enables the strict parsing option
|
This option enables the strict parsing option
|
||||||
|
|
||||||
|
config HTTPS
|
||||||
|
bool "HTTPS support"
|
||||||
|
default n
|
||||||
|
depends on HTTP
|
||||||
|
depends on MBEDTLS
|
||||||
|
help
|
||||||
|
Enables HTTPS support.
|
||||||
|
|
||||||
|
config HTTPS_STACK_SIZE
|
||||||
|
int "HTTPS thread stack size"
|
||||||
|
default 8192
|
||||||
|
depends on HTTPS
|
||||||
|
help
|
||||||
|
HTTPS thread stack size. The mbedtls routines will use this stack
|
||||||
|
thus it is by default very large.
|
||||||
|
|
||||||
|
config HTTPS_HEAP_SIZE
|
||||||
|
int "HTTPS heap size for mbedtls"
|
||||||
|
default 12000
|
||||||
|
depends on HTTPS
|
||||||
|
depends on MBEDTLS
|
||||||
|
help
|
||||||
|
HTTPS heap size. The mbedtls routines will use this heap if enabled.
|
||||||
|
See ext/lib/crypto/mbedtls/include/mbedtls/config.h and
|
||||||
|
MBEDTLS_MEMORY_BUFFER_ALLOC_C option for details. This option is not
|
||||||
|
enabled by default.
|
||||||
|
|
||||||
config NET_DEBUG_HTTP
|
config NET_DEBUG_HTTP
|
||||||
bool "Debug HTTP"
|
bool "Debug HTTP"
|
||||||
default n
|
default n
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue