Skip to content

Commit 3fc5ce7

Browse files
Add HTTP client examples (#385)
Examples to demonstrate HTTP, HTTPS and TLS validation
1 parent b7ff2e9 commit 3fc5ce7

15 files changed

+744
-1
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ App|Description
189189
[picow_wifi_scan](pico_w/wifi/wifi_scan) | Scans for WiFi networks and prints the results.
190190
[picow_udp_beacon](pico_w/wifi/udp_beacon) | A simple UDP transmitter.
191191
[picow_httpd](pico_w/wifi/httpd) | Runs a LWIP HTTP server test app
192+
[picow_http_client](pico_w/wifi/http_client) | Demonstrates how to make http and https requests
193+
[picow_http_client_verify](pico_w/wifi/http_client) | Demonstrates how to make a https request with server authentication
192194

193195
#### FreeRTOS examples
194196

@@ -204,6 +206,7 @@ App|Description
204206
[picow_freertos_ntp_client_socket](pico_w/wifi/freertos/ntp_client_socket) | Connects to an NTP server using the LwIP Socket API with FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode.
205207
[pico_freertos_httpd_nosys](pico_w/wifi/freertos/httpd) | Runs a LWIP HTTP server test app under FreeRTOS in NO_SYS=1 mode.
206208
[pico_freertos_httpd_sys](pico_w/wifi/freertos/httpd) | Runs a LWIP HTTP server test app under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode.
209+
[picow_freertos_http_client_sys](pico_w/wifi/freertos/http_client) | Demonstrates how to make a https request in NO_SYS=0 (i.e. full FreeRTOS integration)
207210

208211
### Pico W Bluetooth
209212

pico_w/wifi/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ else()
1717
add_subdirectory_exclude_platforms(tcp_client)
1818
add_subdirectory_exclude_platforms(tcp_server)
1919
add_subdirectory_exclude_platforms(udp_beacon)
20+
add_subdirectory_exclude_platforms(http_client)
2021

2122
if (NOT PICO_MBEDTLS_PATH)
2223
message("Skipping tls examples as PICO_MBEDTLS_PATH is not defined")

pico_w/wifi/freertos/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ else()
77
add_subdirectory_exclude_platforms(iperf)
88
add_subdirectory_exclude_platforms(ntp_client_socket)
99
add_subdirectory_exclude_platforms(ping)
10-
endif()
10+
add_subdirectory_exclude_platforms(http_client)
11+
endif()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# This example is disabled as mbedtls uses too much stack, and Freertos SMP is problematic with
2+
# pico_cyw43_arch_lwip_threadsafe_background (nosys), where WiFi and LwIP activity is performed in an IRQ.
3+
# Prefer to use pico_cyw43_arch_lwip_sys_freertos instead, where WiFi and LwIP activity is performed in a thread.
4+
if (0)
5+
add_executable(picow_freertos_http_client_nosys
6+
picow_freertos_http_client.c
7+
)
8+
target_compile_definitions(picow_freertos_http_client_nosys PRIVATE
9+
WIFI_SSID=\"${WIFI_SSID}\"
10+
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
11+
ALTCP_MBEDTLS_AUTHMODE=MBEDTLS_SSL_VERIFY_REQUIRED
12+
)
13+
target_include_directories(picow_freertos_http_client_nosys PRIVATE
14+
${CMAKE_CURRENT_LIST_DIR}
15+
${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig
16+
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts and mbedtls_config
17+
)
18+
target_link_libraries(picow_freertos_http_client_nosys
19+
pico_cyw43_arch_lwip_threadsafe_background
20+
pico_stdlib
21+
example_lwip_http_util
22+
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
23+
)
24+
pico_add_extra_outputs(picow_freertos_http_client_nosys)
25+
endif()
26+
27+
add_executable(picow_freertos_http_client_sys
28+
picow_freertos_http_client.c
29+
)
30+
target_compile_definitions(picow_freertos_http_client_sys PRIVATE
31+
WIFI_SSID=\"${WIFI_SSID}\"
32+
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
33+
NO_SYS=0 # don't want NO_SYS (generally this would be in your lwipopts.h)
34+
ALTCP_MBEDTLS_AUTHMODE=MBEDTLS_SSL_VERIFY_REQUIRED
35+
CYW43_TASK_STACK_SIZE=2048
36+
)
37+
target_include_directories(picow_freertos_http_client_sys PRIVATE
38+
${CMAKE_CURRENT_LIST_DIR}
39+
${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig
40+
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
41+
)
42+
target_link_libraries(picow_freertos_http_client_sys
43+
pico_cyw43_arch_lwip_sys_freertos
44+
pico_stdlib
45+
example_lwip_http_util
46+
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
47+
)
48+
pico_add_extra_outputs(picow_freertos_http_client_sys)
49+
50+
# Ignore warnings from lwip code
51+
set_source_files_properties(
52+
${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c
53+
PROPERTIES
54+
COMPILE_OPTIONS "-Wno-unused-result"
55+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef FREERTOS_CONFIG_H
2+
#define FREERTOS_CONFIG_H
3+
4+
// This example uses a common include to avoid repetition
5+
#include "FreeRTOSConfig_examples_common.h"
6+
7+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#ifndef _LWIPOPTS_H
2+
#define _LWIPOPTS_H
3+
4+
// Generally you would define your own explicit list of lwIP options
5+
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
6+
//
7+
// This example uses a common include to avoid repetition
8+
#include "lwipopts_examples_common.h"
9+
10+
#if !NO_SYS
11+
#define TCPIP_THREAD_STACKSIZE 1024
12+
#define DEFAULT_THREAD_STACKSIZE 1024
13+
#define DEFAULT_RAW_RECVMBOX_SIZE 8
14+
#define TCPIP_MBOX_SIZE 8
15+
#define LWIP_TIMEVAL_PRIVATE 0
16+
17+
// not necessary, can be done either way
18+
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
19+
20+
// ping_thread sets socket receive timeout, so enable this feature
21+
#define LWIP_SO_RCVTIMEO 1
22+
#endif
23+
24+
#define LWIP_ALTCP 1
25+
26+
// If you don't want to use TLS (just a http request) you can avoid linking to mbedtls and remove the following
27+
#define LWIP_ALTCP_TLS 1
28+
#define LWIP_ALTCP_TLS_MBEDTLS 1
29+
30+
// Note bug in lwip with LWIP_ALTCP and LWIP_DEBUG
31+
// https://savannah.nongnu.org/bugs/index.php?62159
32+
//#define LWIP_DEBUG 1
33+
#undef LWIP_DEBUG
34+
#define ALTCP_MBEDTLS_DEBUG LWIP_DBG_ON
35+
36+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef MBEDTLS_CONFIG_TLS_CLIENT_H
2+
#define MBEDTLS_CONFIG_TLS_CLIENT_H
3+
4+
#include "mbedtls_config_examples_common.h"
5+
6+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#include "pico/cyw43_arch.h"
8+
#include "pico/stdlib.h"
9+
#include "lwip/altcp_tls.h"
10+
11+
#include "lwip/netif.h"
12+
13+
#include "FreeRTOS.h"
14+
#include "task.h"
15+
#include "example_http_client_util.h"
16+
17+
#ifndef RUN_FREERTOS_ON_CORE
18+
#define RUN_FREERTOS_ON_CORE 0
19+
#endif
20+
21+
#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 2UL )
22+
#define TEST_TASK_STACK_SIZE 1024
23+
24+
// Using this url as we know the root cert won't change for a long time
25+
#define HOST "fw-download-alias1.raspberrypi.com"
26+
#define URL_REQUEST "/net_install/boot.sig"
27+
28+
// This is the PUBLIC root certificate exported from a browser
29+
// Note that the newlines are needed
30+
#define TLS_ROOT_CERT_OK "-----BEGIN CERTIFICATE-----\n\
31+
MIIC+jCCAn+gAwIBAgICEAAwCgYIKoZIzj0EAwIwgbcxCzAJBgNVBAYTAkdCMRAw\n\
32+
DgYDVQQIDAdFbmdsYW5kMRIwEAYDVQQHDAlDYW1icmlkZ2UxHTAbBgNVBAoMFFJh\n\
33+
c3BiZXJyeSBQSSBMaW1pdGVkMRwwGgYDVQQLDBNSYXNwYmVycnkgUEkgRUNDIENB\n\
34+
MR0wGwYDVQQDDBRSYXNwYmVycnkgUEkgUm9vdCBDQTEmMCQGCSqGSIb3DQEJARYX\n\
35+
c3VwcG9ydEByYXNwYmVycnlwaS5jb20wIBcNMjExMjA5MTEzMjU1WhgPMjA3MTEx\n\
36+
MjcxMTMyNTVaMIGrMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEdMBsG\n\
37+
A1UECgwUUmFzcGJlcnJ5IFBJIExpbWl0ZWQxHDAaBgNVBAsME1Jhc3BiZXJyeSBQ\n\
38+
SSBFQ0MgQ0ExJTAjBgNVBAMMHFJhc3BiZXJyeSBQSSBJbnRlcm1lZGlhdGUgQ0Ex\n\
39+
JjAkBgkqhkiG9w0BCQEWF3N1cHBvcnRAcmFzcGJlcnJ5cGkuY29tMHYwEAYHKoZI\n\
40+
zj0CAQYFK4EEACIDYgAEcN9K6Cpv+od3w6yKOnec4EbyHCBzF+X2ldjorc0b2Pq0\n\
41+
N+ZvyFHkhFZSgk2qvemsVEWIoPz+K4JSCpgPstz1fEV6WzgjYKfYI71ghELl5TeC\n\
42+
byoPY+ee3VZwF1PTy0cco2YwZDAdBgNVHQ4EFgQUJ6YzIqFh4rhQEbmCnEbWmHEo\n\
43+
XAUwHwYDVR0jBBgwFoAUIIAVCSiDPXut23NK39LGIyAA7NAwEgYDVR0TAQH/BAgw\n\
44+
BgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwIDaQAwZgIxAJYM+wIM\n\
45+
PC3wSPqJ1byJKA6D+ZyjKR1aORbiDQVEpDNWRKiQ5QapLg8wbcED0MrRKQIxAKUT\n\
46+
v8TJkb/8jC/oBVTmczKlPMkciN+uiaZSXahgYKyYhvKTatCTZb+geSIhc0w/2w==\n\
47+
-----END CERTIFICATE-----\n"
48+
49+
void main_task(__unused void *params) {
50+
if (cyw43_arch_init()) {
51+
printf("failed to initialise\n");
52+
return;
53+
}
54+
55+
cyw43_arch_enable_sta_mode();
56+
printf("Connecting to Wi-Fi...\n");
57+
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
58+
printf("failed to connect.\n");
59+
exit(1);
60+
} else {
61+
printf("Connected.\n");
62+
}
63+
64+
static const uint8_t cert_ok[] = TLS_ROOT_CERT_OK;
65+
static EXAMPLE_HTTP_REQUEST_T req = {0};
66+
req.hostname = HOST;
67+
req.url = URL_REQUEST;
68+
req.headers_fn = http_client_header_print_fn;
69+
req.recv_fn = http_client_receive_print_fn;
70+
req.tls_config = altcp_tls_create_config_client(cert_ok, sizeof(cert_ok));
71+
72+
int pass = http_client_request_sync(cyw43_arch_async_context(), &req);
73+
altcp_tls_free_config(req.tls_config);
74+
if (pass != 0) {
75+
panic("test failed");
76+
}
77+
78+
cyw43_arch_deinit();
79+
panic("Test passed");
80+
}
81+
82+
void vLaunch( void) {
83+
TaskHandle_t task;
84+
xTaskCreate(main_task, "TestMainThread", TEST_TASK_STACK_SIZE, NULL, TEST_TASK_PRIORITY, &task);
85+
86+
#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1
87+
// we must bind the main task to one core (well at least while the init is called)
88+
// (note we only do this in NO_SYS mode, because cyw43_arch_freertos
89+
// takes care of it otherwise)
90+
vTaskCoreAffinitySet(task, 1);
91+
#endif
92+
93+
/* Start the tasks and timer running. */
94+
vTaskStartScheduler();
95+
}
96+
97+
int main( void )
98+
{
99+
stdio_init_all();
100+
101+
/* Configure the hardware ready to run the demo. */
102+
const char *rtos_name;
103+
#if ( portSUPPORT_SMP == 1 )
104+
rtos_name = "FreeRTOS SMP";
105+
#else
106+
rtos_name = "FreeRTOS";
107+
#endif
108+
109+
#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 )
110+
printf("Starting %s on both cores:\n", rtos_name);
111+
vLaunch();
112+
#elif ( RUN_FREERTOS_ON_CORE == 1 )
113+
printf("Starting %s on core 1:\n", rtos_name);
114+
multicore_launch_core1(vLaunch);
115+
while (true);
116+
#else
117+
printf("Starting %s on core 0:\n", rtos_name);
118+
vLaunch();
119+
#endif
120+
return 0;
121+
}
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
pico_add_library(example_lwip_http_util NOFLAG)
2+
target_sources(example_lwip_http_util INTERFACE
3+
${CMAKE_CURRENT_LIST_DIR}/example_http_client_util.c
4+
)
5+
pico_mirrored_target_link_libraries(example_lwip_http_util INTERFACE
6+
pico_lwip_http
7+
pico_lwip_mbedtls
8+
pico_mbedtls
9+
)
10+
target_include_directories(example_lwip_http_util INTERFACE
11+
${CMAKE_CURRENT_LIST_DIR}
12+
)
13+
14+
add_executable(picow_http_client
15+
picow_http_client.c
16+
)
17+
target_compile_definitions(picow_http_client PRIVATE
18+
WIFI_SSID=\"${WIFI_SSID}\"
19+
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
20+
)
21+
target_include_directories(picow_http_client PRIVATE
22+
${CMAKE_CURRENT_LIST_DIR}
23+
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts and mbedtls_config
24+
)
25+
target_link_libraries(picow_http_client
26+
pico_cyw43_arch_lwip_threadsafe_background
27+
example_lwip_http_util
28+
pico_stdlib
29+
)
30+
pico_add_extra_outputs(picow_http_client)
31+
32+
add_executable(picow_http_client_verify
33+
picow_http_verify.c
34+
)
35+
target_compile_definitions(picow_http_client_verify PRIVATE
36+
WIFI_SSID=\"${WIFI_SSID}\"
37+
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
38+
# By default verification is optional (MBEDTLS_SSL_VERIFY_OPTIONAL)
39+
# Make it required for this test
40+
ALTCP_MBEDTLS_AUTHMODE=MBEDTLS_SSL_VERIFY_REQUIRED
41+
)
42+
target_include_directories(picow_http_client_verify PRIVATE
43+
${CMAKE_CURRENT_LIST_DIR}
44+
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts and mbedtls_config
45+
)
46+
target_link_libraries(picow_http_client_verify
47+
pico_cyw43_arch_lwip_threadsafe_background
48+
example_lwip_http_util
49+
pico_stdlib
50+
)
51+
pico_add_extra_outputs(picow_http_client_verify)
52+
53+
# Ignore warnings from lwip code
54+
set_source_files_properties(
55+
${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c
56+
PROPERTIES
57+
COMPILE_OPTIONS "-Wno-unused-result"
58+
)

0 commit comments

Comments
 (0)