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::
|
.. 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
|
||||||
coap_client
|
coap_client
|
||||||
coap_server
|
coap_server
|
||||||
http
|
http_client
|
||||||
|
http_server
|
||||||
lwm2m
|
lwm2m
|
||||||
mqtt
|
mqtt
|
||||||
mqtt_sn
|
mqtt_sn
|
||||||
|
|
|
@ -84,6 +84,13 @@ can be disabled if not needed.
|
||||||
supported in similar manner when enabled with a Kconfig option.
|
supported in similar manner when enabled with a Kconfig option.
|
||||||
:zephyr:code-sample:`lwm2m-client` sample implements the library as an example.
|
: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
|
* **DNS** Domain Name Service
|
||||||
(`RFC 1035 <https://tools.ietf.org/html/rfc1035>`_) client functionality
|
(`RFC 1035 <https://tools.ietf.org/html/rfc1035>`_) client functionality
|
||||||
is supported.
|
is supported.
|
||||||
|
@ -177,3 +184,9 @@ The networking stack source code tree is organized as follows:
|
||||||
|
|
||||||
.. _LwM2M specification 1.1.1:
|
.. _LwM2M specification 1.1.1:
|
||||||
http://openmobilealliance.org/release/LightweightM2M/V1_1_1-20190617-A/
|
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
|
.. zephyr:code-sample:: sockets-http-client
|
||||||
:name: HTTP client
|
:name: HTTP Client
|
||||||
:relevant-api: bsd_sockets http_client tls_credentials secure_sockets_options
|
:relevant-api: bsd_sockets http_client tls_credentials secure_sockets_options
|
||||||
|
|
||||||
Implement an HTTP(S) client that issues a variety of HTTP requests.
|
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
|
Overview
|
||||||
--------
|
--------
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue