Skip to content

Commit

Permalink
Add HTTP client examples
Browse files Browse the repository at this point in the history
Examples to demonstrate HTTP, HTTPS and TLS validation

Fixes #318
  • Loading branch information
peterharperuk committed Jan 5, 2024
1 parent 96f4abe commit 393374c
Show file tree
Hide file tree
Showing 13 changed files with 572 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ App|Description
[picow_tls_verify](pico_w/wifi/tls_client) | Demonstrates how to make a HTTPS request using TLS with certificate verification.
[picow_wifi_scan](pico_w/wifi/wifi_scan) | Scans for WiFi networks and prints the results.
[picow_udp_beacon](pico_w/wifi/udp_beacon) | A simple UDP transmitter.
[picow_http_client](pico_w/wifi/http_client) | Demonstrates how to make http and https requests
[picow_http_client_verify](pico_w/wifi/http_client) | Demonstrates how to make a https request with server authentication

#### FreeRTOS examples

Expand All @@ -142,6 +144,8 @@ App|Description
[picow_freertos_iperf_server_sys](pico_w/wifi/freertos/iperf) | Runs an "iperf" server for WiFi speed testing under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The LED is blinked in another task
[picow_freertos_ping_nosys](pico_w/wifi/freertos/ping) | Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=1 mode.
[picow_freertos_ping_sys](pico_w/wifi/freertos/ping) | Runs the lwip-contrib/apps/ping test app under FreeRTOS in NO_SYS=0 (i.e. full FreeRTOS integration) mode. The test app uses the lwIP _socket_ API in this case.
[picow_freertos_http_client_nosys](pico_w/wifi/freertos/http_client) | Demonstrates how to make a https request in NO_SYS=1 mode
[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)

### Pico W Bluetooth

Expand Down
1 change: 1 addition & 0 deletions pico_w/wifi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ else()
add_subdirectory(tcp_server)
add_subdirectory(freertos)
add_subdirectory(udp_beacon)
add_subdirectory(http_client)

if (NOT PICO_MBEDTLS_PATH)
message("Skipping tls examples as PICO_MBEDTLS_PATH is not defined")
Expand Down
1 change: 1 addition & 0 deletions pico_w/wifi/freertos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ else()

add_subdirectory(iperf)
add_subdirectory(ping)
add_subdirectory(http_client)
endif()
49 changes: 49 additions & 0 deletions pico_w/wifi/freertos/http_client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
add_executable(picow_freertos_http_client_nosys
picow_freertos_http_client.c
)
target_compile_definitions(picow_freertos_http_client_nosys PRIVATE
WIFI_SSID=\"${WIFI_SSID}\"
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
ALTCP_MBEDTLS_AUTHMODE=MBEDTLS_SSL_VERIFY_REQUIRED
)
target_include_directories(picow_freertos_http_client_nosys PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
)
target_link_libraries(picow_freertos_http_client_nosys
pico_cyw43_arch_lwip_threadsafe_background
pico_stdlib
pico_http_client
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
)
pico_add_extra_outputs(picow_freertos_http_client_nosys)

add_executable(picow_freertos_http_client_sys
picow_freertos_http_client.c
)
target_compile_definitions(picow_freertos_http_client_sys PRIVATE
WIFI_SSID=\"${WIFI_SSID}\"
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
NO_SYS=0 # don't want NO_SYS (generally this would be in your lwipopts.h)
ALTCP_MBEDTLS_AUTHMODE=MBEDTLS_SSL_VERIFY_REQUIRED
)
target_include_directories(picow_freertos_http_client_sys PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common FreeRTOSConfig
${CMAKE_CURRENT_LIST_DIR}/../.. # for our common lwipopts
)
target_link_libraries(picow_freertos_http_client_sys
pico_cyw43_arch_lwip_sys_freertos
pico_stdlib
pico_http_client
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
)
pico_add_extra_outputs(picow_freertos_http_client_sys)

# Ignore warnings from lwip code
set_source_files_properties(
${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c
PROPERTIES
COMPILE_OPTIONS "-Wno-unused-result"
)
7 changes: 7 additions & 0 deletions pico_w/wifi/freertos/http_client/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

// This example uses a common include to avoid repetition
#include "FreeRTOSConfig_examples_common.h"

#endif
36 changes: 36 additions & 0 deletions pico_w/wifi/freertos/http_client/lwipopts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H

// Generally you would define your own explicit list of lwIP options
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
//
// This example uses a common include to avoid repetition
#include "lwipopts_examples_common.h"

#if !NO_SYS
#define TCPIP_THREAD_STACKSIZE 1024
#define DEFAULT_THREAD_STACKSIZE 1024
#define DEFAULT_RAW_RECVMBOX_SIZE 8
#define TCPIP_MBOX_SIZE 8
#define LWIP_TIMEVAL_PRIVATE 0

// not necessary, can be done either way
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1

// ping_thread sets socket receive timeout, so enable this feature
#define LWIP_SO_RCVTIMEO 1
#endif

#define LWIP_ALTCP 1

// If you don't want to use TLS (just a http request) you can avoid linking to mbedtls and remove the following
#define LWIP_ALTCP_TLS 1
#define LWIP_ALTCP_TLS_MBEDTLS 1

// Note bug in lwip with LWIP_ALTCP and LWIP_DEBUG
// https://savannah.nongnu.org/bugs/index.php?62159
//#define LWIP_DEBUG 1
#undef LWIP_DEBUG
#define ALTCP_MBEDTLS_DEBUG LWIP_DBG_ON

#endif
66 changes: 66 additions & 0 deletions pico_w/wifi/freertos/http_client/mbedtls_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* Workaround for some mbedtls source files using INT_MAX without including limits.h */
#include <limits.h>

#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_ENTROPY_HARDWARE_ALT

#define MBEDTLS_SSL_OUT_CONTENT_LEN 2048

#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#define MBEDTLS_HAVE_TIME

#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
#define MBEDTLS_ECP_DP_BP256R1_ENABLED
#define MBEDTLS_ECP_DP_BP384R1_ENABLED
#define MBEDTLS_ECP_DP_BP512R1_ENABLED
#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_SHA256_SMALLER
#define MBEDTLS_SSL_SERVER_NAME_INDICATION
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_ERROR_C
#define MBEDTLS_MD_C
#define MBEDTLS_MD5_C
#define MBEDTLS_OID_C
#define MBEDTLS_PKCS5_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_AES_FEWER_TABLES

/* TLS 1.2 */
#define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_GCM_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ASN1_WRITE_C

// The following is needed to parse a certificate
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_BASE64_C
136 changes: 136 additions & 0 deletions pico_w/wifi/freertos/http_client/picow_freertos_http_client.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include "pico/cyw43_arch.h"
#include "pico/stdlib.h"
#include "pico/http_client.h"

#include "lwip/netif.h"

#include "FreeRTOS.h"
#include "task.h"

#ifndef RUN_FREERTOS_ON_CORE
#define RUN_FREERTOS_ON_CORE 0
#endif

#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 2UL )
#define BLINK_TASK_PRIORITY ( tskIDLE_PRIORITY + 4UL )

// Using this url as we know the root cert won't change for a long time
#define HOST "fw-download-alias1.raspberrypi.com"
#define URL_REQUEST "/net_install/boot.sig"

// This is the PUBLIC root certificate exported from a browser
// Note that the newlines are needed
#define TLS_ROOT_CERT_OK "-----BEGIN CERTIFICATE-----\n\
MIIC+jCCAn+gAwIBAgICEAAwCgYIKoZIzj0EAwIwgbcxCzAJBgNVBAYTAkdCMRAw\n\
DgYDVQQIDAdFbmdsYW5kMRIwEAYDVQQHDAlDYW1icmlkZ2UxHTAbBgNVBAoMFFJh\n\
c3BiZXJyeSBQSSBMaW1pdGVkMRwwGgYDVQQLDBNSYXNwYmVycnkgUEkgRUNDIENB\n\
MR0wGwYDVQQDDBRSYXNwYmVycnkgUEkgUm9vdCBDQTEmMCQGCSqGSIb3DQEJARYX\n\
c3VwcG9ydEByYXNwYmVycnlwaS5jb20wIBcNMjExMjA5MTEzMjU1WhgPMjA3MTEx\n\
MjcxMTMyNTVaMIGrMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRW5nbGFuZDEdMBsG\n\
A1UECgwUUmFzcGJlcnJ5IFBJIExpbWl0ZWQxHDAaBgNVBAsME1Jhc3BiZXJyeSBQ\n\
SSBFQ0MgQ0ExJTAjBgNVBAMMHFJhc3BiZXJyeSBQSSBJbnRlcm1lZGlhdGUgQ0Ex\n\
JjAkBgkqhkiG9w0BCQEWF3N1cHBvcnRAcmFzcGJlcnJ5cGkuY29tMHYwEAYHKoZI\n\
zj0CAQYFK4EEACIDYgAEcN9K6Cpv+od3w6yKOnec4EbyHCBzF+X2ldjorc0b2Pq0\n\
N+ZvyFHkhFZSgk2qvemsVEWIoPz+K4JSCpgPstz1fEV6WzgjYKfYI71ghELl5TeC\n\
byoPY+ee3VZwF1PTy0cco2YwZDAdBgNVHQ4EFgQUJ6YzIqFh4rhQEbmCnEbWmHEo\n\
XAUwHwYDVR0jBBgwFoAUIIAVCSiDPXut23NK39LGIyAA7NAwEgYDVR0TAQH/BAgw\n\
BgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwIDaQAwZgIxAJYM+wIM\n\
PC3wSPqJ1byJKA6D+ZyjKR1aORbiDQVEpDNWRKiQ5QapLg8wbcED0MrRKQIxAKUT\n\
v8TJkb/8jC/oBVTmczKlPMkciN+uiaZSXahgYKyYhvKTatCTZb+geSIhc0w/2w==\n\
-----END CERTIFICATE-----\n"

void blink_task(__unused void *params) {
bool on = false;
printf("blink_task starts\n");
while (true) {
#if 0 && configNUM_CORES > 1
static int last_core_id;
if (portGET_CORE_ID() != last_core_id) {
last_core_id = portGET_CORE_ID();
printf("blinking now from core %d\n", last_core_id);
}
#endif
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, on);
on = !on;
vTaskDelay(200);
}
vTaskDelete(NULL);
}

void main_task(__unused void *params) {
if (cyw43_arch_init()) {
printf("failed to initialise\n");
return;
}
TaskHandle_t blinkHandle = NULL;
xTaskCreate(blink_task, "BlinkThread", configMINIMAL_STACK_SIZE, NULL, BLINK_TASK_PRIORITY, &blinkHandle);

cyw43_arch_enable_sta_mode();
printf("Connecting to Wi-Fi...\n");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("failed to connect.\n");
exit(1);
} else {
printf("Connected.\n");
}

static const uint8_t cert_ok[] = TLS_ROOT_CERT_OK; // watch out for stack usage!
void *state = http_client_init_secure(HOST, http_client_header_print_cb, http_client_body_print_cb, NULL, cert_ok, sizeof(cert_ok));
int pass = http_client_run_sync(state, cyw43_arch_async_context(), URL_REQUEST);
http_client_deinit(state);

if (pass != 0) {
panic("test failed");
}

vTaskDelete(blinkHandle);
cyw43_arch_deinit();
panic("Test passed");
}

void vLaunch( void) {
TaskHandle_t task;
xTaskCreate(main_task, "TestMainThread", 1024, NULL, TEST_TASK_PRIORITY, &task);

#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1
// we must bind the main task to one core (well at least while the init is called)
// (note we only do this in NO_SYS mode, because cyw43_arch_freertos
// takes care of it otherwise)
vTaskCoreAffinitySet(task, 1);
#endif

/* Start the tasks and timer running. */
vTaskStartScheduler();
}

int main( void )
{
stdio_init_all();

/* Configure the hardware ready to run the demo. */
const char *rtos_name;
#if ( portSUPPORT_SMP == 1 )
rtos_name = "FreeRTOS SMP";
#else
rtos_name = "FreeRTOS";
#endif

#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 )
printf("Starting %s on both cores:\n", rtos_name);
vLaunch();
#elif ( RUN_FREERTOS_ON_CORE == 1 )
printf("Starting %s on core 1:\n", rtos_name);
multicore_launch_core1(vLaunch);
while (true);
#else
printf("Starting %s on core 0:\n", rtos_name);
vLaunch();
#endif
return 0;
}
45 changes: 45 additions & 0 deletions pico_w/wifi/http_client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
add_executable(picow_http_client
picow_http_client.c
)
target_compile_definitions(picow_http_client PRIVATE
WIFI_SSID=\"${WIFI_SSID}\"
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
)
target_include_directories(picow_http_client PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
)
target_link_libraries(picow_http_client
pico_cyw43_arch_lwip_threadsafe_background
pico_http_client
pico_stdlib
)
pico_add_extra_outputs(picow_http_client)

add_executable(picow_http_client_verify
picow_http_verify.c
)
target_compile_definitions(picow_http_client_verify PRIVATE
WIFI_SSID=\"${WIFI_SSID}\"
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
# By default verification is optional (MBEDTLS_SSL_VERIFY_OPTIONAL)
# Make it required for this test
ALTCP_MBEDTLS_AUTHMODE=MBEDTLS_SSL_VERIFY_REQUIRED
)
target_include_directories(picow_http_client_verify PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts
)
target_link_libraries(picow_http_client_verify
pico_cyw43_arch_lwip_threadsafe_background
pico_http_client
pico_stdlib
)
pico_add_extra_outputs(picow_http_client_verify)

# Ignore warnings from lwip code
set_source_files_properties(
${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c
PROPERTIES
COMPILE_OPTIONS "-Wno-unused-result"
)
Loading

0 comments on commit 393374c

Please sign in to comment.