HTTP Server

Overview

The HTTP Server sample application for Zephyr implements a basic TCP server on top of the HTTP Server Library that is able to receive HTTP 1.1 requests, parse them and write back the responses.

This sample code generates HTTP 1.1 responses dynamically and does not serve content from a file system. The source code includes examples on how to write HTTP 1.1 responses: 200 OK, 400 Bad Request, 403 Forbidden, 404 Not Found and soft HTTP errors like 200 OK with a 404 Not Found HTML message.

The source code for this sample application can be found at: samples/net/http_server.

Requirements

  • Linux machine with wget and the screen terminal emulator
  • Either QEMU or real device like Freedom Board (FRDM-K64F)
  • For QEMU see this Networking with QEMU
  • LAN for testing purposes (Ethernet)

Building and Running

Currently, the HTTP Server application is configured to listen at port 80. If you want to modify the http-server sample application, please check the configuration settings in samples/net/http_server/src/main.c file and also in the samples/net/http_server/src/config.h file.

To use QEMU for testing, follow the Networking with QEMU guide.

This sample code supports both static and dynamic (DHCPv4) IP addresses that can be defined in the project configuration file:

CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"

Adding URLs

To define a new URL or to change how a URL is processed by the HTTP server, open the samples/net/http_server/src/main.c file and locate the following lines:

http_server_add_default(&http_urls, http_response_soft_404);
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);

The first line defines how Zephyr will deal with unknown URLs. In this case, it will respond with a soft HTTP 404 status code, i.e. an HTTP 200 OK status code with a 404 Not Found HTML body.

The second line must be interpreted as follows: requests to /headers, /headers/index.html and in general to /headers/xxx, will trigger the http_write_header_fields routine that prints the received HTTP Header Fields. In this case, “xxx” must be understood as any resource under the /headers/ URL.

The third line will trigger a routine that prints an HTML It Works! message when the /index.html or /index.html/xxx URLs are found.

To build this sample on your Linux host computer, open a terminal window, locate the source code of this sample application and type:

make BOARD=frdm_k64f

The FRDM K64F board is detected as a USB storage device. The board must be mounted (i.e. to /mnt) to ‘flash’ the binary:

$ cp outdir/frdm_k64f/zephyr.bin /mnt

On Linux, use the ‘dmesg’ program to find the right USB device for the FRDM serial console. Assuming that this device is ttyACM0, open a terminal window and type:

$ screen /dev/ttyACM0 115200

Once the binary is loaded into the FRDM board, press the RESET button.

Refer to the board documentation in Zephyr, NXP FRDM-K64F, for more information about this board and how to access the FRDM serial console under other operating systems.

Sample Output

Assume in this example that this HTTP server is configured to listen at IPv4 address 192.168.1.120 and IPv6 address 2001:db8::1 port 80. On your Linux host computer, open a terminal window and type:

wget 192.168.1.120/index.html

wget will show:

--2017-01-17 00:37:44--  http://192.168.1.120/
Connecting to 192.168.1.120:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: 'index.html'

The HTML file generated by Zephyr and downloaded by wget is:

<html>
<head>
<title>Zephyr HTTP Server</title>
</head>
<body><h1><center>It Works!</center></h1></body>
</html>

The screen application will display the following information:

[dev/eth_mcux] [DBG] eth_0_init: MAC 00:04:9f:52:44:02
[sample/net] [INF] net_sample_app_init: Run HTTPS server
[sample/net] [INF] setup_dhcpv4: Running
[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...
[sample/net] [INF] ipv6_event_handler: IPv6 address: 2001:db8::1
[dev/eth_mcux] [INF] eth_mcux_phy_event: Enabled 10M half-duplex mode.
[sample/net] [INF] ipv4_addr_add_handler: IPv4 address: 192.168.1.120
[sample/net] [INF] ipv4_addr_add_handler: Lease time: 86400 seconds
[sample/net] [INF] ipv4_addr_add_handler: Subnet: 255.255.255.0
[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:

wget 192.168.1.120/headers -O index.html

wget will show:

--2017-01-19 22:09:55--  http://192.168.1.120/headers
Connecting to 192.168.1.120:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: 'index.html'

This is the HTML file generated by Zephyr and downloaded by wget:

<html>
<head>
<title>Zephyr HTTP Server</title>
</head>
<body>
<h1>Zephyr HTTP server</h1>
<h2>HTTP Header Fields</h2>
<ul>
<li>User-Agent: Wget/1.16 (linux-gnu)</li>
<li>Accept: */*</li>
<li>Host: 192.168.1.120</li>
<li>Connection: Keep-Alive</li>
</ul>
<h2>HTTP Method: GET</h2>
<h2>URL: /headers</h2>
<h2>Server: arm</h2>
</body>
</html>

To test the 404 Not Found soft error, use the following command:

wget 192.168.1.120/not_found -O index.html

Zephyr will generate an HTTP response with the following header:

HTTP/1.1 200 OK
Content-Type: text/html
Transfer-Encoding: chunked

and this is the HTML message that wget will save:

<html>
<head>
<title>Zephyr HTTP Server</title>
</head>
<body><h1><center>404 Not Found</center></h1></body>
</html>

To test the HTTP Basic Authentication functionality, use the following command:

wget 192.168.1.120/auth -O index.html --user=zephyr --password=0123456789

the index.html file will contain the following information:

<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

The sample code also includes a HTTPS (HTTP over TLS) server example running side by side with the HTTP server, this server runs on QEMU. In order to compile and run the code execute:

make BOARD=qemu_x86 run

Sample Output

The app will show the following on the screen:

[https/server] [INF] new_client: HTTPS connection from 192.168.1.107:35982 (0x20006b4c)
[https/server] [DBG] https_handler: (0x2000b5b4): Read HTTPS request
[https/server] [DBG] https_handler: (0x2000b5b4): Write HTTPS response
[https/server] [DBG] http_process_recv: (0x2000b5b4): Calling handler 0x00000ce9 context 0x20002370

Now execute the following command on a different terminal window

wget https://192.168.1.120 --no-check-certificate

This will be shown on the screen

Connecting to 192.168.1.120:443... connected.
WARNING: cannot verify 192.168.1.120's certificate
Unable to locally verify the issuer's authority.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: 'index.html'

index.html                                            [ <=> ]

The inspection of the file index.html will show

<h2>Zephyr TLS Test Server</h2>
<p>Successful connection</p>

Known Issues and Limitations

  • Currently, this sample application only generates HTTP responses in chunk transfer mode.