Skip to content

Commit

Permalink
samples: net: http_server: Add HTTP server sample application
Browse files Browse the repository at this point in the history
A simple HTTP server sample application.

Signed-off-by: Emna Rekik <[email protected]>
Signed-off-by: Jukka Rissanen <[email protected]>
Signed-off-by: Robert Lubos <[email protected]>
  • Loading branch information
jukkar authored and rlubos committed Apr 26, 2024
1 parent c13ebcc commit 394f1b2
Show file tree
Hide file tree
Showing 16 changed files with 559 additions and 0 deletions.
57 changes: 57 additions & 0 deletions samples/net/sockets/http_server/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
find_package(Python REQUIRED COMPONENTS Interpreter)

project(http_server)

if(CONFIG_NET_SOCKETS_SOCKOPT_TLS AND
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND
(CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h"))
add_custom_target(development_psk
COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------"
COMMAND ${CMAKE_COMMAND} -E echo "--- WARNING: Using dummy PSK! Only suitable for ---"
COMMAND ${CMAKE_COMMAND} -E echo "--- development. Set NET_SAMPLE_PSK_HEADER_FILE to use ---"
COMMAND ${CMAKE_COMMAND} -E echo "--- own pre-shared key. ---"
COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------"
)
add_dependencies(app development_psk)
endif()

option(INCLUDE_HTML_CONTENT "Include the HTML content" ON)

target_sources(app PRIVATE src/main.c)

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)

set(source_file_not_found src/not_found_page.html)
generate_inc_file_for_target(app ${source_file_not_found} ${gen_dir}/not_found_page.html.gz.inc --gzip)

target_link_libraries(app PRIVATE zephyr_interface zephyr)

zephyr_linker_sources(SECTIONS sections-rom.ld)
zephyr_linker_section_ifdef(CONFIG_NET_SAMPLE_HTTPS_SERVICE NAME
http_resource_desc_test_https_service
KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4)
zephyr_linker_section_ifdef(CONFIG_NET_SAMPLE_HTTP_SERVICE NAME
http_resource_desc_test_http_service
KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4)

foreach(inc_file
ca.der
server.der
server_privkey.der
https-server-cert.der
https-server-key.der
)
generate_inc_file_for_target(
app
src/${inc_file}
${gen_dir}/${inc_file}.inc
)
endforeach()
41 changes: 41 additions & 0 deletions samples/net/sockets/http_server/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Config options for http2 server sample application

# Copyright (c) 2023, Emna Rekik
# SPDX-License-Identifier: Apache-2.0

mainmenu "HTTP2 server sample application"

config NET_SAMPLE_HTTP_SERVICE
bool "Enable http service"
default y

config NET_SAMPLE_HTTP_SERVER_SERVICE_PORT
int "Port number for http service"
default 80
depends on NET_SAMPLE_HTTP_SERVICE

config NET_SAMPLE_HTTPS_SERVICE
bool "Enable https service"
depends on NET_SOCKETS_SOCKOPT_TLS || TLS_CREDENTIALS

config NET_SAMPLE_HTTPS_SERVER_SERVICE_PORT
int "Port number for https service"
default 443
depends on NET_SAMPLE_HTTPS_SERVICE

config NET_SAMPLE_PSK_HEADER_FILE
string "Header file containing PSK"
default "dummy_psk.h"
depends on MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
help
Name of a header file containing a
pre-shared key.

config NET_SAMPLE_CERTS_WITH_SC
bool "Signed certificates"
depends on NET_SOCKETS_SOCKOPT_TLS
help
Enable this flag, if you are interested to run this
application with signed certificates and keys.

source "Kconfig.zephyr"
97 changes: 97 additions & 0 deletions samples/net/sockets/http_server/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
Zephyr HTTP Server
==================

Overview
--------

This sample application demonstrates the use of the ``http_server`` library. This library provides high-level functions to simplify and abstract server implementation. The server supports the HTTP/1.1 protocol and can also be upgraded to HTTP/2.

Requirement
-----------

`QEMU Networking <https://docs.zephyrproject.org/latest/connectivity/networking/qemu_setup.html#networking-with-qemu>`_

Building and running the server
-------------------------------

To build and run the application:

.. code-block:: bash
$ west build -p auto -b <board_to_use> -t run samples/net/sockets/http_server
When the server is up, we can make requests to the server using either HTTP/1.1 or HTTP/2 protocol from the host machine.

**With HTTP/1.1:**

- Using a browser: ``http://192.0.2.1:8080/``
- Using curl: ``curl -v --compressed http://192.0.2.1:8080/``
- Using ab (Apache Bench): ``ab -n10 http://192.0.2.1:8080/``

**With HTTP/2:**

- Using nghttp client: ``nghttp -v --no-dep http://192.0.2.1:8080/``
- Using curl: ``curl --http2 -v --compressed http://192.0.2.1:8080/``
- Using h2load: ``h2load -n10 http://192.0.2.1:8080/``

Server Customization
---------------------

The server contains several parameters that can be customized based on the requirements. These are the configurable parameters:

- ``HTTP_SERVER_SERVICE_PORT``: Configures Service Port.

- ``HTTP_SERVER_MAX_CLIENTS``: Defines the maximum number of HTTP/2 clients that the server can handle simultaneously.

- ``HTTP_SERVER_MAX_STREAMS``: Specifies the maximum number of HTTP/2 streams that can be established per client.

- ``HTTP_SERVER_CLIENT_BUFFER_SIZE``: Defines the buffer size allocated for each client.

- ``HTTP_SERVER_MAX_URL_LENGTH``: Specifies the maximum length of an HTTP URL that the server can process.

To customize these options, we can run ``west build -t menuconfig``, which provides us with an interactive configuration interface. Then we could navigate from the top-level menu to: ``-> Subsystems and OS Services -> Networking -> Network Protocols``.

Performance Analysis
--------------------

CPU Usage Profiling
*******************

We can use ``perf`` to collect statistics about the CPU usage of our server with the ``stat`` command:

.. code-block:: bash
$ sudo perf stat -p <pid_of_server>
``perf stat`` will then start monitoring our server. We can let it run while sending requests to our server. Once we've collected enough data, we can stop ``perf stat``, which will print a summary of the performance statistics.

Hotspot Analysis
****************

``perf record`` and ``perf report`` can be used together to identify the functions in our code that consume the most CPU time:

.. code-block:: bash
$ sudo perf record -g -p <pid_of_server> -o perf.data
After running our server under load (For example, using ApacheBench tool), we can stop the recording and analyze the data using:

.. code-block:: bash
$ sudo perf report -i perf.data
After generating a file named ``perf.data`` which contains the profiling data, we can visualize it using ``FlameGraph`` tool. It's particularly useful for identifying the most expensive code-paths and inspect where our application is spending the most time.

To do this, we need to convert the ``perf.data`` to a format that ``FlameGraph`` can understand:

.. code-block:: bash
$ sudo perf script | ~/FlameGraph/stackcollapse-perf.pl > out.perf-folded
And, then, generate the ``FlameGraph``:

.. code-block:: bash
$ ~/FlameGraph/flamegraph.pl out.perf-folded > flamegraph.svg
We can view flamegraph.svg using a web browser.
71 changes: 71 additions & 0 deletions samples/net/sockets/http_server/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# General config
CONFIG_MAIN_STACK_SIZE=3072
CONFIG_SHELL=y
CONFIG_LOG=y
CONFIG_ENTROPY_GENERATOR=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_INIT_STACKS=y
CONFIG_POSIX_MAX_FDS=32
CONFIG_POSIX_API=y
CONFIG_FDTABLE=y
CONFIG_NET_SOCKETS_POLL_MAX=32

# Eventfd
CONFIG_EVENTFD=y

# Networking config
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
CONFIG_NET_TCP=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_CONNECTION_MANAGER=y
CONFIG_NET_SHELL=y
CONFIG_NET_LOG=y

# JSON
CONFIG_JSON_LIBRARY=y

# HTTP parser
CONFIG_HTTP_PARSER_URL=y
CONFIG_HTTP_PARSER=y
CONFIG_HTTP_SERVER=y

# Network buffers
CONFIG_NET_PKT_RX_COUNT=16
CONFIG_NET_PKT_TX_COUNT=16
CONFIG_NET_BUF_RX_COUNT=128
CONFIG_NET_BUF_TX_COUNT=128
CONFIG_NET_CONTEXT_NET_PKT_POOL=y

# IP address options
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4
CONFIG_NET_MAX_CONTEXTS=32
CONFIG_NET_MAX_CONN=32

# Network address config
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_NEED_IPV4=y
CONFIG_NET_CONFIG_NEED_IPV6=y
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"
CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2"
CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1"
CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2"

# TLS configuration
CONFIG_MBEDTLS=y
CONFIG_MBEDTLS_BUILTIN=y
CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_HEAP_SIZE=60000
CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2048
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y
CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=6
CONFIG_TLS_CREDENTIALS=y
CONFIG_TLS_MAX_CREDENTIALS_NUMBER=5

# Networking tweaks
# Required to handle large number of consecutive connections,
# e.g. when testing with ApacheBench.
CONFIG_NET_TCP_TIME_WAIT_DELAY=0
17 changes: 17 additions & 0 deletions samples/net/sockets/http_server/sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
sample:
description: HTTP Server Sample
name: http_server_sample
common:
filter: TOOLCHAIN_HAS_NEWLIB == 1
harness: net
min_ram: 192
tags:
- http
- net
- server
- socket
platform_exclude:
- native_posix
- native_posix/native/64
tests:
sample.net.sockets.http.server: {}
4 changes: 4 additions & 0 deletions samples/net/sockets/http_server/sections-rom.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include <zephyr/linker/iterable_sections.h>

ITERABLE_SECTION_ROM(http_resource_desc_test_http_service, 4)
ITERABLE_SECTION_ROM(http_resource_desc_test_https_service, 4)
Binary file added samples/net/sockets/http_server/src/ca.der
Binary file not shown.
50 changes: 50 additions & 0 deletions samples/net/sockets/http_server/src/certificate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __CERTIFICATE_H__
#define __CERTIFICATE_H__

enum tls_tag {
/** The Certificate Authority public key */
HTTP_SERVER_CA_CERTIFICATE_TAG,
/** Used for both the public and private server keys */
HTTP_SERVER_CERTIFICATE_TAG,
/** Used for both the public and private client keys */
HTTP_SERVER_CLIENT_CERTIFICATE_TAG,
PSK_TAG,
};

#if !defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC)
static const unsigned char server_certificate[] = {
#include "https-server-cert.der.inc"
};

/* This is the private key in pkcs#8 format. */
static const unsigned char private_key[] = {
#include "https-server-key.der.inc"
};

#else

static const unsigned char ca_certificate[] = {
#include "ca.der.inc"
};

static const unsigned char server_certificate[] = {
#include "server.der.inc"
};

/* This is the private key in pkcs#8 format. */
static const unsigned char private_key[] = {
#include "server_privkey.der.inc"
};
#endif

#if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
#include CONFIG_NET_SAMPLE_PSK_HEADER_FILE
#endif

#endif /* __CERTIFICATE_H__ */
14 changes: 14 additions & 0 deletions samples/net/sockets/http_server/src/dummy_psk.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2019 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __DUMMY_PSK_H__
#define __DUMMY_PSK_H__

static const unsigned char psk[] = {0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
static const char psk_id[] = "PSK_identity";

#endif /* __DUMMY_PSK_H__ */
Binary file not shown.
Binary file not shown.
10 changes: 10 additions & 0 deletions samples/net/sockets/http_server/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Zephyr HTTP Server</title>
</head>
<body>
<h1>Welcome to Zephyr HTTP Server!</h1>
<p>This is a simple HTML file.</p>
</body>
</html>
Loading

0 comments on commit 394f1b2

Please sign in to comment.