diff --git a/examples/protocols/http2_request/README.md b/examples/protocols/http2_request/README.md index 808d595427..e7be3a83ef 100644 --- a/examples/protocols/http2_request/README.md +++ b/examples/protocols/http2_request/README.md @@ -1,6 +1,55 @@ # HTTP/2 Request Example -Established HTTP/2 connection with https://http2.golang.org -- Performs a GET on /clockstream -- Performs a PUT on /ECHO +Establish an HTTP/2 connection with https://http2.github.io +- Performs a GET on /index.html +## How to use example +Before project configuration and build, be sure to set the correct chip target using `idf.py set-target `. + +### Hardware Required + +* A development board with ESP32/ESP32-S2/ESP32-C3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.) +* A USB cable for power supply and programming + +### Configure the project + +``` +idf.py menuconfig +``` +Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(Replace PORT with the name of the serial port to use.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +``` +I (5609) example_connect: - IPv4 address: 192.168.0.103 +I (5609) example_connect: - IPv6 address: fe80:0000:0000:0000:ae67:b2ff:fe45:0194, type: ESP_IP6_ADDR_IS_LINK_LOCAL +Connecting to server +Connection done +[get-response] + +. +. +. +Body of index.html +. +. +. +. + +[get-response] Frame fully received +[get-response] Stream Closed +``` diff --git a/examples/protocols/http2_request/components/sh2lib/sh2lib.c b/examples/protocols/http2_request/components/sh2lib/sh2lib.c index 364fdec794..8f298c4bcc 100644 --- a/examples/protocols/http2_request/components/sh2lib/sh2lib.c +++ b/examples/protocols/http2_request/components/sh2lib/sh2lib.c @@ -235,27 +235,35 @@ static int do_http2_connect(struct sh2lib_handle *hd) return 0; } -int sh2lib_connect(struct sh2lib_handle *hd, const char *uri) +int sh2lib_connect(struct sh2lib_config_t *cfg, struct sh2lib_handle *hd) { memset(hd, 0, sizeof(*hd)); + + if (cfg == NULL) { + ESP_LOGE(TAG, "[sh2-connect] pointer to sh2lib configurations cannot be NULL"); + goto error; + } + const char *proto[] = {"h2", NULL}; esp_tls_cfg_t tls_cfg = { .alpn_protos = proto, + .cacert_buf = cfg->cacert_buf, + .cacert_bytes = cfg->cacert_bytes, .non_block = true, .timeout_ms = 10 * 1000, }; - if ((hd->http2_tls = esp_tls_conn_http_new(uri, &tls_cfg)) == NULL) { + if ((hd->http2_tls = esp_tls_conn_http_new(cfg->uri, &tls_cfg)) == NULL) { ESP_LOGE(TAG, "[sh2-connect] esp-tls connection failed"); goto error; } struct http_parser_url u; http_parser_url_init(&u); - http_parser_parse_url(uri, strlen(uri), 0, &u); - hd->hostname = strndup(&uri[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len); + http_parser_parse_url(cfg->uri, strlen(cfg->uri), 0, &u); + hd->hostname = strndup(&cfg->uri[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len); /* HTTP/2 Connection */ if (do_http2_connect(hd) != 0) { - ESP_LOGE(TAG, "[sh2-connect] HTTP2 Connection failed with %s", uri); + ESP_LOGE(TAG, "[sh2-connect] HTTP2 Connection failed with %s", cfg->uri); goto error; } diff --git a/examples/protocols/http2_request/components/sh2lib/sh2lib.h b/examples/protocols/http2_request/components/sh2lib/sh2lib.h index f67137695c..78733a0b0e 100644 --- a/examples/protocols/http2_request/components/sh2lib/sh2lib.h +++ b/examples/protocols/http2_request/components/sh2lib/sh2lib.h @@ -38,6 +38,15 @@ struct sh2lib_handle { struct esp_tls *http2_tls; /*!< Pointer to the TLS session handle */ }; +/** + * @brief sh2lib configuration structure + */ +struct sh2lib_config_t { + const char *uri; /*!< Pointer to the URI that should be connected to */ + const unsigned char *cacert_buf; /*!< Pointer to the buffer containing CA certificate */ + unsigned int cacert_bytes; /*!< Size of the CA certifiacte pointed by cacert_buf */ +}; + /** Flag indicating receive stream is reset */ #define DATA_RECV_RST_STREAM 1 /** Flag indicating frame is completely received */ @@ -88,14 +97,13 @@ typedef int (*sh2lib_putpost_data_cb_t)(struct sh2lib_handle *handle, char *data * * Only 'https' URIs are supported. * + * @param[in] cfg Pointer to the sh2lib configurations of the type 'struct sh2lib_config_t'. * @param[out] hd Pointer to a variable of the type 'struct sh2lib_handle'. - * @param[in] uri Pointer to the URI that should be connected to. - * * @return * - ESP_OK if the connection was successful * - ESP_FAIL if the connection fails */ -int sh2lib_connect(struct sh2lib_handle *hd, const char *uri); +int sh2lib_connect(struct sh2lib_config_t *cfg, struct sh2lib_handle *hd); /** * @brief Free a sh2lib handle diff --git a/examples/protocols/http2_request/main/CMakeLists.txt b/examples/protocols/http2_request/main/CMakeLists.txt index 40f03c8800..a450362baa 100644 --- a/examples/protocols/http2_request/main/CMakeLists.txt +++ b/examples/protocols/http2_request/main/CMakeLists.txt @@ -1,2 +1,3 @@ idf_component_register(SRCS "http2_request_example_main.c" - INCLUDE_DIRS ".") + INCLUDE_DIRS "." + EMBED_TXTFILES "http2_github_io_root_cert.pem") diff --git a/examples/protocols/http2_request/main/component.mk b/examples/protocols/http2_request/main/component.mk index e69de29bb2..bbe96a05f9 100644 --- a/examples/protocols/http2_request/main/component.mk +++ b/examples/protocols/http2_request/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +COMPONENT_EMBED_TXTFILES := http2_github_io_root_cert.pem diff --git a/examples/protocols/http2_request/main/http2_github_io_root_cert.pem b/examples/protocols/http2_request/main/http2_github_io_root_cert.pem new file mode 100644 index 0000000000..8c4c741058 --- /dev/null +++ b/examples/protocols/http2_request/main/http2_github_io_root_cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy +YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2 +4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC +Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1 +itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn +4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X +sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft +bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA +MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy +dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t +L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG +BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ +UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D +aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd +aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH +E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly +/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu +xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF +0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae +cPUeybQ= +-----END CERTIFICATE----- diff --git a/examples/protocols/http2_request/main/http2_request_example_main.c b/examples/protocols/http2_request/main/http2_request_example_main.c index 0dc6dfd124..5dce7dbbda 100644 --- a/examples/protocols/http2_request/main/http2_request_example_main.c +++ b/examples/protocols/http2_request/main/http2_request_example_main.c @@ -1,6 +1,6 @@ /* HTTP2 GET Example using nghttp2 - Contacts http2.golang.org and executes the GET/PUT requests. A thin API + Contacts http2.github.io and executes the GET request. A thin API wrapper on top of nghttp2, to properly demonstrate the interactions. This example code is in the Public Domain (or CC0 licensed, at your option.) @@ -26,12 +26,13 @@ #include "sh2lib.h" +extern const uint8_t server_root_cert_pem_start[] asm("_binary_http2_github_io_root_cert_pem_start"); +extern const uint8_t server_root_cert_pem_end[] asm("_binary_http2_github_io_root_cert_pem_end"); + /* The HTTP/2 server to connect to */ -#define HTTP2_SERVER_URI "https://http2.golang.org" +#define HTTP2_SERVER_URI "https://http2.github.io" /* A GET request that keeps streaming current time every second */ -#define HTTP2_STREAMING_GET_PATH "/clockstream" -/* A PUT request that echoes whatever we had sent to it */ -#define HTTP2_PUT_PATH "/ECHO" +#define HTTP2_STREAMING_GET_PATH "/index.html" int handle_get_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags) @@ -101,8 +102,14 @@ static void http2_task(void *args) /* HTTP2: one connection multiple requests. Do the TLS/TCP connection first */ printf("Connecting to server\n"); + struct sh2lib_config_t cfg = { + .uri = HTTP2_SERVER_URI, + .cacert_buf = server_root_cert_pem_start, + .cacert_bytes = server_root_cert_pem_end - server_root_cert_pem_start, + }; struct sh2lib_handle hd; - if (sh2lib_connect(&hd, HTTP2_SERVER_URI) != 0) { + + if (sh2lib_connect(&cfg, &hd) != 0) { printf("Failed to connect\n"); vTaskDelete(NULL); return; @@ -111,10 +118,6 @@ static void http2_task(void *args) /* HTTP GET */ sh2lib_do_get(&hd, HTTP2_STREAMING_GET_PATH, handle_get_response); - - /* HTTP PUT */ - sh2lib_do_put(&hd, HTTP2_PUT_PATH, send_put_data, handle_echo_response); - while (1) { /* Process HTTP2 send/receive */ if (sh2lib_execute(&hd) < 0) { diff --git a/examples/protocols/http2_request/sdkconfig.defaults b/examples/protocols/http2_request/sdkconfig.defaults deleted file mode 100644 index a79804293a..0000000000 --- a/examples/protocols/http2_request/sdkconfig.defaults +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_ESP_TLS_INSECURE=y -CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y