doc: net: Add HTTP server documentation
Add documentation page for HTTP server functionality. Rename existing HTTP documentation to HTTP client, as it only covers the client library. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
parent
811386ef3a
commit
7b55805a3e
6 changed files with 326 additions and 6 deletions
|
@ -1,6 +1,6 @@
|
|||
.. _http_interface:
|
||||
.. _http_client_interface:
|
||||
|
||||
HTTP client
|
||||
HTTP Client
|
||||
###########
|
||||
|
||||
.. contents::
|
303
doc/connectivity/networking/api/http_server.rst
Normal file
303
doc/connectivity/networking/api/http_server.rst
Normal file
|
@ -0,0 +1,303 @@
|
|||
.. _http_server_interface:
|
||||
|
||||
HTTP Server
|
||||
###########
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
Zephyr provides an HTTP server library, which allows to register HTTP services
|
||||
and HTTP resources associated with those services. The server creates a listening
|
||||
socket for every registered service, and handles incoming client connections.
|
||||
It's possible to communicate over a plain TCP socket (HTTP) or a TLS socket (HTTPS).
|
||||
Both, HTTP/1.1 (RFC 2616) and HTTP/2 (RFC 9113) protocol versions are supported.
|
||||
|
||||
The server operation is generally transparent for the application, running in a
|
||||
background thread. The application can control the server activity with
|
||||
respective API functions.
|
||||
|
||||
Certain resource types (for example dynamic resource) provide resource-specific
|
||||
application callbacks, allowing the server to interact with the application (for
|
||||
instance provide resource content, or process request payload).
|
||||
|
||||
Currently, the following resource types are supported:
|
||||
|
||||
* Static resources - content defined compile-time, cannot be modified at runtime
|
||||
(:c:enumerator:`HTTP_RESOURCE_TYPE_STATIC`).
|
||||
|
||||
* Dynamic resources - content provided at runtime by respective application
|
||||
callback (:c:enumerator:`HTTP_RESOURCE_TYPE_DYNAMIC`).
|
||||
|
||||
* Websocket resources - allowing to establish Websocket connections with the
|
||||
server (:c:enumerator:`HTTP_RESOURCE_TYPE_WEBSOCKET`).
|
||||
|
||||
Zephyr provides a sample demonstrating HTTP(s) server operation and various
|
||||
resource types usage. See :zephyr:code-sample:`sockets-http-server` for more
|
||||
information.
|
||||
|
||||
Server Setup
|
||||
************
|
||||
|
||||
A few prerequisites are needed in order to enable HTTP server functionality in
|
||||
the application.
|
||||
|
||||
First of all, the HTTP server has to be enabled in applications configuration file
|
||||
with :kconfig:option:`CONFIG_HTTP_SERVER` Kconfig option:
|
||||
|
||||
.. code-block:: cfg
|
||||
:caption: ``prj.conf``
|
||||
|
||||
CONFIG_HTTP_SERVER=y
|
||||
|
||||
All HTTP services and HTTP resources are placed in a dedicated linker section.
|
||||
The linker section for services is predefined locally, however the application
|
||||
is responsible for defining linker sections for resources associated with
|
||||
respective services. Linker section names for resources should be prefixed with
|
||||
``http_resource_desc_``, appended with the service name.
|
||||
|
||||
Linker sections for resources should be defined in a linker file. For example,
|
||||
for a service named ``my_service``, the linker section shall be defined as follows:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: ``sections-rom.ld``
|
||||
|
||||
#include <zephyr/linker/iterable_sections.h>
|
||||
|
||||
ITERABLE_SECTION_ROM(http_resource_desc_my_service, Z_LINK_ITERABLE_SUBALIGN)
|
||||
|
||||
Finally, the linker file and linker section have to be added to your application
|
||||
using CMake:
|
||||
|
||||
.. code-block:: cmake
|
||||
:caption: ``CMakeLists.txt``
|
||||
|
||||
zephyr_linker_sources(SECTIONS sections-rom.ld)
|
||||
zephyr_linker_section(NAME http_resource_desc_my_service
|
||||
KVMA RAM_REGION GROUP RODATA_REGION
|
||||
SUBALIGN Z_LINK_ITERABLE_SUBALIGN)
|
||||
|
||||
.. note::
|
||||
|
||||
You need to define a separate linker section for each HTTP service
|
||||
registered in the system.
|
||||
|
||||
Sample Usage
|
||||
************
|
||||
|
||||
Services
|
||||
========
|
||||
|
||||
The application needs to define an HTTP service (or multiple services), with
|
||||
the same name as used for the linker section with :c:macro:`HTTP_SERVICE_DEFINE`
|
||||
macro:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <zephyr/net/http/service.h>
|
||||
|
||||
static uint16_t http_service_port = 80;
|
||||
|
||||
HTTP_SERVICE_DEFINE(my_service, "0.0.0.0", &http_service_port, 1, 10, NULL);
|
||||
|
||||
Alternatively, an HTTPS service can be defined with with
|
||||
:c:macro:`HTTPS_SERVICE_DEFINE`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <zephyr/net/http/service.h>
|
||||
#include <zephyr/net/tls_credentials.h>
|
||||
|
||||
#define HTTP_SERVER_CERTIFICATE_TAG 1
|
||||
|
||||
static uint16_t https_service_port = 443;
|
||||
static const sec_tag_t sec_tag_list[] = {
|
||||
HTTP_SERVER_CERTIFICATE_TAG,
|
||||
};
|
||||
|
||||
HTTPS_SERVICE_DEFINE(my_service, "0.0.0.0", &https_service_port, 1, 10,
|
||||
NULL, sec_tag_list, sizeof(sec_tag_list));
|
||||
|
||||
.. note::
|
||||
|
||||
HTTPS services rely on TLS credentials being registered in the system.
|
||||
See :ref:`sockets_tls_credentials_subsys` for information on how to
|
||||
configure TLS credentials in the system.
|
||||
|
||||
Once HTTP(s) service is defined, resources can be registered for it with
|
||||
:c:macro:`HTTP_RESOURCE_DEFINE` macro.
|
||||
|
||||
Static resources
|
||||
================
|
||||
|
||||
Static resource content is defined build-time and is immutable. The following
|
||||
example shows how gzip compressed webpage can be defined as a static resource
|
||||
in the application:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const uint8_t index_html_gz[] = {
|
||||
#include "index.html.gz.inc"
|
||||
};
|
||||
|
||||
struct http_resource_detail_static index_html_gz_resource_detail = {
|
||||
.common = {
|
||||
.type = HTTP_RESOURCE_TYPE_STATIC,
|
||||
.bitmask_of_supported_http_methods = BIT(HTTP_GET),
|
||||
.content_encoding = "gzip",
|
||||
},
|
||||
.static_data = index_html_gz,
|
||||
.static_data_len = sizeof(index_html_gz),
|
||||
};
|
||||
|
||||
HTTP_RESOURCE_DEFINE(index_html_gz_resource, my_service, "/",
|
||||
&index_html_gz_resource_detail);
|
||||
|
||||
The resource content and content encoding is application specific. For the above
|
||||
example, a gzip compressed webpage can be generated during build, by adding the
|
||||
following code to the application's ``CMakeLists.txt`` file:
|
||||
|
||||
.. code-block:: cmake
|
||||
:caption: ``CMakeLists.txt``
|
||||
|
||||
set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/)
|
||||
set(source_file_index src/index.html)
|
||||
generate_inc_file_for_target(app ${source_file_index} ${gen_dir}/index.html.gz.inc --gzip)
|
||||
|
||||
where ``src/index.html`` is the location of the webpage to be compressed.
|
||||
|
||||
Dynamic resources
|
||||
=================
|
||||
|
||||
For dynamic resource, a resource callback is registered to exchange data between
|
||||
the server and the application. The application defines a resource buffer used
|
||||
to pass the request payload data from the server, and to provide response payload
|
||||
to the server. The following example code shows how to register a dynamic resource
|
||||
with a simple resource handler, which echoes received data back to the client:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static uint8_t recv_buffer[1024];
|
||||
|
||||
static int dyn_handler(struct http_client_ctx *client,
|
||||
enum http_data_status status, uint8_t *buffer,
|
||||
size_t len, void *user_data)
|
||||
{
|
||||
#define MAX_TEMP_PRINT_LEN 32
|
||||
static char print_str[MAX_TEMP_PRINT_LEN];
|
||||
enum http_method method = client->method;
|
||||
static size_t processed;
|
||||
|
||||
__ASSERT_NO_MSG(buffer != NULL);
|
||||
|
||||
if (status == HTTP_SERVER_DATA_ABORTED) {
|
||||
LOG_DBG("Transaction aborted after %zd bytes.", processed);
|
||||
processed = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
processed += len;
|
||||
|
||||
snprintf(print_str, sizeof(print_str), "%s received (%zd bytes)",
|
||||
http_method_str(method), len);
|
||||
LOG_HEXDUMP_DBG(buffer, len, print_str);
|
||||
|
||||
if (status == HTTP_SERVER_DATA_FINAL) {
|
||||
LOG_DBG("All data received (%zd bytes).", processed);
|
||||
processed = 0;
|
||||
}
|
||||
|
||||
/* This will echo data back to client as the buffer and recv_buffer
|
||||
* point to same area.
|
||||
*/
|
||||
return len;
|
||||
}
|
||||
|
||||
struct http_resource_detail_dynamic dyn_resource_detail = {
|
||||
.common = {
|
||||
.type = HTTP_RESOURCE_TYPE_DYNAMIC,
|
||||
.bitmask_of_supported_http_methods =
|
||||
BIT(HTTP_GET) | BIT(HTTP_POST),
|
||||
},
|
||||
.cb = dyn_handler,
|
||||
.data_buffer = recv_buffer,
|
||||
.data_buffer_len = sizeof(recv_buffer),
|
||||
.user_data = NULL,
|
||||
};
|
||||
|
||||
HTTP_RESOURCE_DEFINE(dyn_resource, my_service, "/dynamic",
|
||||
&dyn_resource_detail);
|
||||
|
||||
|
||||
The resource callback may be called multiple times for a single request, hence
|
||||
the application should be able to keep track of the received data progress.
|
||||
|
||||
The ``status`` field informs the application about the progress in passing
|
||||
request payload from the server to the application. As long as the status
|
||||
reports :c:enumerator:`HTTP_SERVER_DATA_MORE`, the application should expect
|
||||
more data to be provided in a consecutive callback calls.
|
||||
Once all request payload has been passed to the application, the server reports
|
||||
:c:enumerator:`HTTP_SERVER_DATA_FINAL` status. In case of communication errors
|
||||
during request processing (for example client closed the connection before
|
||||
complete payload has been received), the server reports
|
||||
:c:enumerator:`HTTP_SERVER_DATA_ABORTED`. Either of the two events indicate that
|
||||
the application shall reset any progress recorded for the resource, and await
|
||||
a new request to come. The server guarantees that the resource can only be
|
||||
accessed by single client at a time.
|
||||
|
||||
The resource callback returns the number of bytes to be replied in the response
|
||||
payload to the server (provided in the resource data buffer). In case there is
|
||||
no more data to be included in the response, the callback should return 0.
|
||||
|
||||
The server will call the resource callback until it provided all request data
|
||||
to the application, and the application reports there is no more data to include
|
||||
in the reply.
|
||||
|
||||
Websocket resources
|
||||
===================
|
||||
|
||||
Websocket resources register an application callback, which is is called when a
|
||||
Websocket connection upgrade takes place. The callback is provided with a socket
|
||||
descriptor corresponding to the underlying TCP/TLS connection. Once called,
|
||||
the application takes full control over the socket, i. e. is responsible to
|
||||
release it when done.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static int ws_socket;
|
||||
static uint8_t ws_recv_buffer[1024];
|
||||
|
||||
int ws_setup(int sock, void *user_data)
|
||||
{
|
||||
ws_socket = sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct http_resource_detail_websocket ws_resource_detail = {
|
||||
.common = {
|
||||
.type = HTTP_RESOURCE_TYPE_WEBSOCKET,
|
||||
/* We need HTTP/1.1 Get method for upgrading */
|
||||
.bitmask_of_supported_http_methods = BIT(HTTP_GET),
|
||||
},
|
||||
.cb = ws_setup,
|
||||
.data_buffer = ws_recv_buffer,
|
||||
.data_buffer_len = sizeof(ws_recv_buffer),
|
||||
.user_data = NULL, /* Fill this for any user specific data */
|
||||
};
|
||||
|
||||
HTTP_RESOURCE_DEFINE(ws_resource, my_service, "/", &ws_resource_detail);
|
||||
|
||||
The above minimalistic example shows how to register a Websocket resource with
|
||||
a simple callback, used only to store the socket descriptor provided. Further
|
||||
processing of the Websocket connection is application-specific, hence outside
|
||||
of scope of this guide. See :zephyr:code-sample:`sockets-http-server` for an
|
||||
example Websocket-based echo service implementation.
|
||||
|
||||
API Reference
|
||||
*************
|
||||
|
||||
.. doxygengroup:: http_service
|
||||
.. doxygengroup:: http_server
|
|
@ -10,7 +10,8 @@ Protocols
|
|||
coap
|
||||
coap_client
|
||||
coap_server
|
||||
http
|
||||
http_client
|
||||
http_server
|
||||
lwm2m
|
||||
mqtt
|
||||
mqtt_sn
|
||||
|
|
|
@ -84,6 +84,13 @@ can be disabled if not needed.
|
|||
supported in similar manner when enabled with a Kconfig option.
|
||||
:zephyr:code-sample:`lwm2m-client` sample implements the library as an example.
|
||||
|
||||
* **HTTP** Hypertext Transfer Protocol client and server are supported.
|
||||
:ref:`http_client_interface` library supports HTTP/1.1 (`RFC 2616`_).
|
||||
:ref:`http_server_interface` library supports HTTP/1.1 (`RFC 2616`_) and
|
||||
HTTP/2 (`RFC 9113`_).
|
||||
:zephyr:code-sample:`sockets-http-client` and
|
||||
:zephyr:code-sample:`sockets-http-server` samples are provided.
|
||||
|
||||
* **DNS** Domain Name Service
|
||||
(`RFC 1035 <https://tools.ietf.org/html/rfc1035>`_) client functionality
|
||||
is supported.
|
||||
|
@ -177,3 +184,9 @@ The networking stack source code tree is organized as follows:
|
|||
|
||||
.. _LwM2M specification 1.1.1:
|
||||
http://openmobilealliance.org/release/LightweightM2M/V1_1_1-20190617-A/
|
||||
|
||||
.. _RFC 2616:
|
||||
https://tools.ietf.org/html/rfc2616
|
||||
|
||||
.. _RFC 9113:
|
||||
https://tools.ietf.org/html/rfc9113
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.. zephyr:code-sample:: sockets-http-client
|
||||
:name: HTTP client
|
||||
:name: HTTP Client
|
||||
:relevant-api: bsd_sockets http_client tls_credentials secure_sockets_options
|
||||
|
||||
Implement an HTTP(S) client that issues a variety of HTTP requests.
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
Zephyr HTTP Server
|
||||
==================
|
||||
.. zephyr:code-sample:: sockets-http-server
|
||||
:name: HTTP Server
|
||||
:relevant-api: http_service http_server tls_credentials
|
||||
|
||||
Implement an HTTP(s) Server demonstrating various resource types.
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue