Merge branch 'feature/nghttp_sh2lib_component_manager' into 'master'

Push out nghttp and sh2lib to IDF component manager

Closes IDF-4529

See merge request espressif/esp-idf!16618
This commit is contained in:
Mahavir Jain 2022-01-11 13:45:59 +00:00
commit fba8582da4
32 changed files with 50 additions and 849 deletions

View File

@ -147,7 +147,6 @@ exclude =
components/expat/expat,
components/json/cJSON,
components/mbedtls/mbedtls,
components/nghttp/nghttp2,
components/openthread/openthread,
components/tinyusb,
components/unity/unity,

View File

@ -109,6 +109,7 @@
/components/freertos/ @esp-idf-codeowners/system
/components/hal/ @esp-idf-codeowners/peripherals
/components/heap/ @esp-idf-codeowners/system
/components/http_parser/ @esp-idf-codeowners/app-utilities
/components/idf_test/ @esp-idf-codeowners/ci
/components/ieee802154/ @esp-idf-codeowners/ieee802154
/components/json/ @esp-idf-codeowners/app-utilities
@ -118,7 +119,6 @@
/components/mdns/ @esp-idf-codeowners/network
/components/mqtt/ @esp-idf-codeowners/network
/components/newlib/ @esp-idf-codeowners/system @esp-idf-codeowners/tools
/components/nghttp/ @esp-idf-codeowners/app-utilities
/components/nvs_flash/ @esp-idf-codeowners/storage
/components/openssl/ @esp-idf-codeowners/network
/components/openthread/ @esp-idf-codeowners/ieee802154

View File

@ -169,9 +169,6 @@
- "components/lwip/lwip"
- "components/mbedtls/mbedtls"
- "components/mqtt/esp-mqtt"
- "components/nghttp/nghttp2"
- "components/nghttp/nghttp2/third-party/mruby"
- "components/nghttp/nghttp2/third-party/neverbleed"
- "components/openthread/lib"
- "components/protobuf-c/protobuf-c"
- "components/spiffs/spiffs"

4
.gitmodules vendored
View File

@ -19,10 +19,6 @@
path = components/coap/libcoap
url = ../../obgm/libcoap.git
[submodule "components/nghttp/nghttp2"]
path = components/nghttp/nghttp2
url = ../../nghttp2/nghttp2.git
[submodule "components/spiffs/spiffs"]
path = components/spiffs/spiffs
url = ../../pellepl/spiffs.git

View File

@ -13,7 +13,7 @@ idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS . esp-tls-crypto
PRIV_INCLUDE_DIRS "private_include"
REQUIRES mbedtls
PRIV_REQUIRES lwip nghttp)
PRIV_REQUIRES lwip http_parser)
if(CONFIG_ESP_TLS_USING_WOLFSSL)
idf_component_get_property(wolfssl esp-wolfssl COMPONENT_LIB)

View File

@ -4,5 +4,5 @@ idf_component_register(SRCS "esp_http_client.c"
"lib/http_utils.c"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "lib/include"
REQUIRES nghttp
REQUIRES http_parser
PRIV_REQUIRES tcp_transport)

View File

@ -7,5 +7,5 @@ idf_component_register(SRCS "src/httpd_main.c"
"src/util/ctrl_sock.c"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "src/port/esp32" "src/util"
REQUIRES nghttp # for http_parser.h
REQUIRES http_parser # for http_parser.h
PRIV_REQUIRES lwip mbedtls esp_timer)

View File

@ -8,5 +8,5 @@ endif()
idf_component_register(SRCS "esp_websocket_client.c"
INCLUDE_DIRS "include"
REQUIRES lwip esp-tls tcp_transport nghttp
REQUIRES lwip esp-tls tcp_transport http_parser
PRIV_REQUIRES esp_timer)

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "http_parser.c"
INCLUDE_DIRS .)

View File

@ -0,0 +1,23 @@
/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
*
* Additional changes are licensed under the same terms as NGINX and
* copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

View File

@ -13,7 +13,7 @@ idf_component_get_property(esp_hw_support_dir esp_hw_support COMPONENT_DIR)
idf_component_get_property(esp_event_dir esp_event COMPONENT_DIR)
idf_component_get_property(log_dir log COMPONENT_DIR)
idf_component_get_property(freertos_dir freertos COMPONENT_DIR)
idf_component_get_property(nghttp_dir nghttp COMPONENT_DIR)
idf_component_get_property(http_parser_dir http_parser COMPONENT_DIR)
idf_component_get_property(esp_wifi_dir esp_wifi COMPONENT_DIR)
idf_component_get_property(esp_hw_support_dir esp_hw_support COMPONENT_DIR)
idf_component_get_property(esp_tls_dir esp-tls COMPONENT_DIR)
@ -61,7 +61,7 @@ idf_component_get_property(mbedtls_dir mbedtls COMPONENT_DIR)
${freertos_dir}/FreeRTOS-Kernel/include/freertos/task.h
${freertos_dir}/FreeRTOS-Kernel/include/freertos/event_groups.h
${log_dir}/include/esp_log.h
${nghttp_dir}/port/include/http_parser.h
${http_parser_dir}/http_parser.h
)
set(srcs
@ -113,7 +113,7 @@ idf_component_get_property(mbedtls_dir mbedtls COMPONENT_DIR)
${log_dir}/include
${esp_rom_dir}/include
${mbedtls_dir}/port/include
${nghttp_dir}/port/include
${http_parser_dir}
${mbedtls_dir}/mbedtls/include
${freertos_dir}/FreeRTOS-Kernel/include/freertos
esp-mqtt/lib/include
@ -131,7 +131,7 @@ idf_component_get_property(mbedtls_dir mbedtls COMPONENT_DIR)
target_link_libraries(${COMPONENT_LIB} PUBLIC mocks)
else()
idf_component_get_property(nghttp_lib nghttp COMPONENT_LIB)
idf_component_get_property(http_parser_lib http_parser COMPONENT_LIB)
idf_component_get_property(tcp_transport_lib tcp_transport COMPONENT_LIB)
target_link_libraries(${COMPONENT_LIB} PUBLIC ${nghttp_lib} ${tcp_transport_lib})
target_link_libraries(${COMPONENT_LIB} PUBLIC ${http_parser_lib} ${tcp_transport_lib})
endif()

View File

@ -1,30 +0,0 @@
set(srcs
"nghttp2/lib/nghttp2_buf.c"
"nghttp2/lib/nghttp2_callbacks.c"
"nghttp2/lib/nghttp2_debug.c"
"nghttp2/lib/nghttp2_frame.c"
"nghttp2/lib/nghttp2_hd.c"
"nghttp2/lib/nghttp2_hd_huffman.c"
"nghttp2/lib/nghttp2_hd_huffman_data.c"
"nghttp2/lib/nghttp2_helper.c"
"nghttp2/lib/nghttp2_http.c"
"nghttp2/lib/nghttp2_map.c"
"nghttp2/lib/nghttp2_mem.c"
"nghttp2/lib/nghttp2_npn.c"
"nghttp2/lib/nghttp2_option.c"
"nghttp2/lib/nghttp2_outbound_item.c"
"nghttp2/lib/nghttp2_pq.c"
"nghttp2/lib/nghttp2_priority_spec.c"
"nghttp2/lib/nghttp2_queue.c"
"nghttp2/lib/nghttp2_rcbuf.c"
"nghttp2/lib/nghttp2_session.c"
"nghttp2/lib/nghttp2_stream.c"
"nghttp2/lib/nghttp2_submit.c"
"nghttp2/lib/nghttp2_version.c"
"port/http_parser.c")
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS port/include nghttp2/lib/includes
PRIV_INCLUDE_DIRS private_include)
target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DHAVE_CONFIG_H")

View File

@ -1,23 +0,0 @@
The MIT License
Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1 +0,0 @@
See COPYING

View File

@ -1 +0,0 @@
See README.rst

View File

@ -1,44 +0,0 @@
The nghttp Instruction
=============================
This is an implementation of the Hypertext Transfer Protocol version 2 in C.
The framing layer of HTTP/2 is implemented as a reusable C library.
An HPACK encoder and decoder are available as a public API.
- The nghttp support many different processor, but for the most part you only need the following functions:
**nghttp2_session_callbacks_new**: Initializes \*callbacks_ptr with NULL values
**nghttp2_session_client_new**: Initializes \*session_ptr for client use
**nghttp2_session_callbacks_del**: Frees any resources allocated for callbacks
**nghttp2_submit_settings**: Stores local settings and submits SETTINGS frame
**nghttp2_submit_request**: Submits HEADERS frame and optionally one or more DATA frames
**nghttp2_session_want_read**: Returns nonzero value if session wants to receive data from the remote peer
**nghttp2_session_want_write**: Returns nonzero value if session wants to send data to the remote peer
**nghttp2_session_recv**: Receives frames from the remote peer
**nghttp2_session_send**: Sends pending frames to the remote peer
**nghttp2_session_del**: Frees any resources allocated for session
If you are following TLS related RFC, you know that NPN is not the standardized way to negotiate HTTP/2. NPN itself is not even published as RFC.
The standard way to negotiate HTTP/2 is ALPN, Application-Layer Protocol Negotiation Extension, defined in RFC 7301.
- The following endpoints are available to try out the nghttp2 implementation:
https://nghttp2.org/ (TLS + ALPN/NPN)
This endpoint supports h2, h2-16, h2-14, spdy/3.1 and http/1.1 via ALPN/NPN and requires TLSv1.2 for HTTP/2 connection.
More information about nghttp library can be found at https://nghttp2.org
An introductory article on protocol is available on RFC 7540 HTTP/2 and RFC 7541 HPACK - Header Compression for HTTP/2

@ -1 +0,0 @@
Subproject commit 8f7b008b158e12de0e58247afd170f127dbb6456

View File

@ -1,42 +0,0 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2VER_H
#define NGHTTP2VER_H
/**
* @macro
* Version number of the nghttp2 library release
*/
#define NGHTTP2_VERSION "v1.22.0"
/**
* @macro
* Numerical representation of the version number of the nghttp2 library
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
#define NGHTTP2_VERSION_NUM 0x012200
#endif /* NGHTTP2VER_H */

View File

@ -1,36 +0,0 @@
#ifndef __HAVE_CONFIG_H_
#define __HAVE_CONFIG_H_
#define _U_
#define SIZEOF_INT_P 2
//#define DEBUGBUILD
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#if (!defined(nghttp_unlikely))
#define nghttp_unlikely(Expression) !!(Expression)
#endif
#define nghttp_ASSERT(Expression) do{if (!(Expression)) printf("%d\n", __LINE__);}while(0)
#define CU_ASSERT(a) nghttp_ASSERT(a)
#define CU_ASSERT_FATAL(a) nghttp_ASSERT(a)
#if 1
#define NGHTTP2_DEBUG_INFO() printf("%s %d\n", __FILE__, __LINE__)
#else
#define NGHTTP2_DEBUG_INFO()
#endif
#define NGHTTP_PLATFORM_HTONS(_n) ((uint16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff)))
#define NGHTTP_PLATFORM_HTONL(_n) ((uint32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) ))
#define htons(x) NGHTTP_PLATFORM_HTONS(x)
#define ntohs(x) NGHTTP_PLATFORM_HTONS(x)
#define htonl(x) NGHTTP_PLATFORM_HTONL(x)
#define ntohl(x) NGHTTP_PLATFORM_HTONL(x)
#endif

View File

@ -43,8 +43,6 @@ These third party libraries can be included into the application (firmware) prod
* `micro-ecc`_ library, Copyright (c) 2014 Kenneth MacKay, is licensed under 2-clause BSD license.
* `nghttp2`_ library, Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa, Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors, is licensed under MIT license as described in :component_file:`COPYING file <nghttp/nghttp2/COPYING>`.
* `Mbed TLS`_ library, Copyright (C) 2006-2018 ARM Limited, is licensed under Apache License 2.0 as described in :component_file:`LICENSE file <mbedtls/mbedtls/LICENSE>`.
* `SPIFFS`_ library, Copyright (c) 2013-2017 Peter Andersson, is licensed under MIT license as described in :component_file:`LICENSE file <spiffs/spiffs/LICENSE>`.
@ -71,6 +69,8 @@ These third party libraries can be included into the application (firmware) prod
* `freemodbus`_ Copyright (c) 2006-2013 Christian Walter, Armink and licensed under the BSD license.
* :component:`HTTP Parser <http_parser>` Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev. Additional changes are licensed under the same terms as NGINX and Joyent, Inc. and other Node contributors. For details please check :component_file:`LICENSE file<http_parser/LICENSE.txt>`.
Build Tools
-----------
@ -166,7 +166,6 @@ Copyright (C) 2011, ChaN, all right reserved.
.. _cJSON: https://github.com/DaveGamble/cJSON
.. _libexpat: https://github.com/libexpat/libexpat
.. _micro-ecc: https://github.com/kmackay/micro-ecc
.. _nghttp2: https://github.com/nghttp2/nghttp2
.. _OpenBSD SD/MMC driver: https://github.com/openbsd/src/blob/f303646/sys/dev/sdmmc/sdmmc.c
.. _Mbed TLS: https://github.com/ARMmbed/mbedtls
.. _spiffs: https://github.com/pellepl/spiffs

View File

@ -7,6 +7,11 @@ Following components are removed from ESP-IDF and moved to `IDF Component Regist
* `cbor <https://components.espressif.com/component/espressif/cbor>`_
* `jsmn <https://components.espressif.com/component/espressif/jsmn>`_
* `esp_modem <https://components.espressif.com/component/espressif/esp_modem>`_
* `nghttp <https://components.espressif.com/component/espressif/nghttp>`_
.. note:: Please note that http parser functionality which was previously part of ``nghttp`` component is now part of :component:`http_parser <http_parser>` component.
* `sh2lib <https://components.espressif.com/component/espressif/sh2lib>`_
These components can be installed using ``idf.py add-dependency`` command.

View File

@ -1,4 +0,0 @@
idf_component_register(SRCS "sh2lib.c"
INCLUDE_DIRS .
REQUIRES nghttp
PRIV_REQUIRES lwip esp-tls)

View File

@ -1,369 +0,0 @@
/*
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <netdb.h>
#include <esp_log.h>
#include <http_parser.h>
#include "sh2lib.h"
static const char *TAG = "sh2lib";
#define DBG_FRAME_SEND 1
/*
* The implementation of nghttp2_send_callback type. Here we write
* |data| with size |length| to the network and return the number of
* bytes actually written. See the documentation of
* nghttp2_send_callback for the details.
*/
static ssize_t callback_send_inner(struct sh2lib_handle *hd, const uint8_t *data,
size_t length)
{
int rv = esp_tls_conn_write(hd->http2_tls, data, length);
if (rv <= 0) {
if (rv == ESP_TLS_ERR_SSL_WANT_READ || rv == ESP_TLS_ERR_SSL_WANT_WRITE) {
rv = NGHTTP2_ERR_WOULDBLOCK;
} else {
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
return rv;
}
static ssize_t callback_send(nghttp2_session *session, const uint8_t *data,
size_t length, int flags, void *user_data)
{
int rv = 0;
struct sh2lib_handle *hd = user_data;
int copy_offset = 0;
int pending_data = length;
/* Send data in 1000 byte chunks */
while (copy_offset != length) {
int chunk_len = pending_data > 1000 ? 1000 : pending_data;
int subrv = callback_send_inner(hd, data + copy_offset, chunk_len);
if (subrv <= 0) {
if (copy_offset == 0) {
/* If no data is transferred, send the error code */
rv = subrv;
}
break;
}
copy_offset += subrv;
pending_data -= subrv;
rv += subrv;
}
return rv;
}
/*
* The implementation of nghttp2_recv_callback type. Here we read data
* from the network and write them in |buf|. The capacity of |buf| is
* |length| bytes. Returns the number of bytes stored in |buf|. See
* the documentation of nghttp2_recv_callback for the details.
*/
static ssize_t callback_recv(nghttp2_session *session, uint8_t *buf,
size_t length, int flags, void *user_data)
{
struct sh2lib_handle *hd = user_data;
int rv;
rv = esp_tls_conn_read(hd->http2_tls, (char *)buf, (int)length);
if (rv < 0) {
if (rv == ESP_TLS_ERR_SSL_WANT_READ || rv == ESP_TLS_ERR_SSL_WANT_WRITE) {
rv = NGHTTP2_ERR_WOULDBLOCK;
} else {
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
}
} else if (rv == 0) {
rv = NGHTTP2_ERR_EOF;
}
return rv;
}
const char *sh2lib_frame_type_str(int type)
{
switch (type) {
case NGHTTP2_HEADERS:
return "HEADERS";
break;
case NGHTTP2_RST_STREAM:
return "RST_STREAM";
break;
case NGHTTP2_GOAWAY:
return "GOAWAY";
break;
case NGHTTP2_DATA:
return "DATA";
break;
case NGHTTP2_SETTINGS:
return "SETTINGS";
break;
case NGHTTP2_PUSH_PROMISE:
return "PUSH_PROMISE";
break;
case NGHTTP2_PING:
return "PING";
break;
default:
return "other";
break;
}
}
static int callback_on_frame_send(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
ESP_LOGD(TAG, "[frame-send] frame type %s", sh2lib_frame_type_str(frame->hd.type));
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if (nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
ESP_LOGD(TAG, "[frame-send] C ----------------------------> S (HEADERS)");
#if DBG_FRAME_SEND
ESP_LOGD(TAG, "[frame-send] headers nv-len = %d", frame->headers.nvlen);
const nghttp2_nv *nva = frame->headers.nva;
size_t i;
for (i = 0; i < frame->headers.nvlen; ++i) {
ESP_LOGD(TAG, "[frame-send] %s : %s", nva[i].name, nva[i].value);
}
#endif
}
break;
}
return 0;
}
static int callback_on_frame_recv(nghttp2_session *session,
const nghttp2_frame *frame, void *user_data)
{
ESP_LOGD(TAG, "[frame-recv][sid: %d] frame type %s", frame->hd.stream_id, sh2lib_frame_type_str(frame->hd.type));
if (frame->hd.type != NGHTTP2_DATA) {
return 0;
}
/* Subsequent processing only for data frame */
sh2lib_frame_data_recv_cb_t data_recv_cb = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (data_recv_cb) {
struct sh2lib_handle *h2 = user_data;
(*data_recv_cb)(h2, NULL, 0, DATA_RECV_FRAME_COMPLETE);
}
return 0;
}
static int callback_on_stream_close(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *user_data)
{
ESP_LOGD(TAG, "[stream-close][sid %d]", stream_id);
sh2lib_frame_data_recv_cb_t data_recv_cb = nghttp2_session_get_stream_user_data(session, stream_id);
if (data_recv_cb) {
struct sh2lib_handle *h2 = user_data;
(*data_recv_cb)(h2, NULL, 0, DATA_RECV_RST_STREAM);
}
return 0;
}
static int callback_on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
int32_t stream_id, const uint8_t *data,
size_t len, void *user_data)
{
sh2lib_frame_data_recv_cb_t data_recv_cb;
ESP_LOGD(TAG, "[data-chunk][sid:%d]", stream_id);
data_recv_cb = nghttp2_session_get_stream_user_data(session, stream_id);
if (data_recv_cb) {
ESP_LOGD(TAG, "[data-chunk] C <---------------------------- S (DATA chunk)"
"%lu bytes",
(unsigned long int)len);
struct sh2lib_handle *h2 = user_data;
(*data_recv_cb)(h2, (char *)data, len, 0);
/* TODO: What to do with the return value: look for pause/abort */
}
return 0;
}
static int callback_on_header(nghttp2_session *session, const nghttp2_frame *frame,
const uint8_t *name, size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags, void *user_data)
{
ESP_LOGD(TAG, "[hdr-recv][sid:%d] %s : %s", frame->hd.stream_id, name, value);
return 0;
}
static int do_http2_connect(struct sh2lib_handle *hd)
{
int ret;
nghttp2_session_callbacks *callbacks;
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, callback_send);
nghttp2_session_callbacks_set_recv_callback(callbacks, callback_recv);
nghttp2_session_callbacks_set_on_frame_send_callback(callbacks, callback_on_frame_send);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, callback_on_frame_recv);
nghttp2_session_callbacks_set_on_stream_close_callback(callbacks, callback_on_stream_close);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks, callback_on_data_chunk_recv);
nghttp2_session_callbacks_set_on_header_callback(callbacks, callback_on_header);
ret = nghttp2_session_client_new(&hd->http2_sess, callbacks, hd);
if (ret != 0) {
ESP_LOGE(TAG, "[sh2-connect] New http2 session failed");
nghttp2_session_callbacks_del(callbacks);
return -1;
}
nghttp2_session_callbacks_del(callbacks);
/* Create the SETTINGS frame */
ret = nghttp2_submit_settings(hd->http2_sess, NGHTTP2_FLAG_NONE, NULL, 0);
if (ret != 0) {
ESP_LOGE(TAG, "[sh2-connect] Submit settings failed");
return -1;
}
return 0;
}
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(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(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", cfg->uri);
goto error;
}
return 0;
error:
sh2lib_free(hd);
return -1;
}
void sh2lib_free(struct sh2lib_handle *hd)
{
if (hd->http2_sess) {
nghttp2_session_del(hd->http2_sess);
hd->http2_sess = NULL;
}
if (hd->http2_tls) {
esp_tls_conn_destroy(hd->http2_tls);
hd->http2_tls = NULL;
}
if (hd->hostname) {
free(hd->hostname);
hd->hostname = NULL;
}
}
int sh2lib_execute(struct sh2lib_handle *hd)
{
int ret;
ret = nghttp2_session_send(hd->http2_sess);
if (ret != 0) {
ESP_LOGE(TAG, "[sh2-execute] HTTP2 session send failed %d", ret);
return -1;
}
ret = nghttp2_session_recv(hd->http2_sess);
if (ret != 0) {
ESP_LOGE(TAG, "[sh2-execute] HTTP2 session recv failed %d", ret);
return -1;
}
return 0;
}
int sh2lib_do_get_with_nv(struct sh2lib_handle *hd, const nghttp2_nv *nva, size_t nvlen, sh2lib_frame_data_recv_cb_t recv_cb)
{
int ret = nghttp2_submit_request(hd->http2_sess, NULL, nva, nvlen, NULL, recv_cb);
if (ret < 0) {
ESP_LOGE(TAG, "[sh2-do-get] HEADERS call failed");
return -1;
}
return ret;
}
int sh2lib_do_get(struct sh2lib_handle *hd, const char *path, sh2lib_frame_data_recv_cb_t recv_cb)
{
const nghttp2_nv nva[] = { SH2LIB_MAKE_NV(":method", "GET"),
SH2LIB_MAKE_NV(":scheme", "https"),
SH2LIB_MAKE_NV(":authority", hd->hostname),
SH2LIB_MAKE_NV(":path", path),
};
return sh2lib_do_get_with_nv(hd, nva, sizeof(nva) / sizeof(nva[0]), recv_cb);
}
ssize_t sh2lib_data_provider_cb(nghttp2_session *session, int32_t stream_id, uint8_t *buf,
size_t length, uint32_t *data_flags,
nghttp2_data_source *source, void *user_data)
{
struct sh2lib_handle *h2 = user_data;
sh2lib_putpost_data_cb_t data_cb = source->ptr;
return (*data_cb)(h2, (char *)buf, length, data_flags);
}
int sh2lib_do_putpost_with_nv(struct sh2lib_handle *hd, const nghttp2_nv *nva, size_t nvlen,
sh2lib_putpost_data_cb_t send_cb,
sh2lib_frame_data_recv_cb_t recv_cb)
{
nghttp2_data_provider sh2lib_data_provider;
sh2lib_data_provider.read_callback = sh2lib_data_provider_cb;
sh2lib_data_provider.source.ptr = send_cb;
int ret = nghttp2_submit_request(hd->http2_sess, NULL, nva, nvlen, &sh2lib_data_provider, recv_cb);
if (ret < 0) {
ESP_LOGE(TAG, "[sh2-do-putpost] HEADERS call failed");
return -1;
}
return ret;
}
int sh2lib_do_post(struct sh2lib_handle *hd, const char *path,
sh2lib_putpost_data_cb_t send_cb,
sh2lib_frame_data_recv_cb_t recv_cb)
{
const nghttp2_nv nva[] = { SH2LIB_MAKE_NV(":method", "POST"),
SH2LIB_MAKE_NV(":scheme", "https"),
SH2LIB_MAKE_NV(":authority", hd->hostname),
SH2LIB_MAKE_NV(":path", path),
};
return sh2lib_do_putpost_with_nv(hd, nva, sizeof(nva) / sizeof(nva[0]), send_cb, recv_cb);
}
int sh2lib_do_put(struct sh2lib_handle *hd, const char *path,
sh2lib_putpost_data_cb_t send_cb,
sh2lib_frame_data_recv_cb_t recv_cb)
{
const nghttp2_nv nva[] = { SH2LIB_MAKE_NV(":method", "PUT"),
SH2LIB_MAKE_NV(":scheme", "https"),
SH2LIB_MAKE_NV(":authority", hd->hostname),
SH2LIB_MAKE_NV(":path", path),
};
return sh2lib_do_putpost_with_nv(hd, nva, sizeof(nva) / sizeof(nva[0]), send_cb, recv_cb);
}

View File

@ -1,270 +0,0 @@
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP_EXAMPLE_SH2_LIB_H_
#define __ESP_EXAMPLE_SH2_LIB_H_
#include "esp_tls.h"
#include <nghttp2/nghttp2.h>
/*
* This is a thin API wrapper over nghttp2 that offers simplified APIs for usage
* in the application. The intention of this wrapper is to act as a stepping
* stone to quickly get started with using the HTTP/2 client. Since the focus is
* on simplicity, not all the features of HTTP/2 are supported through this
* wrapper. Once you are fairly comfortable with nghttp2, feel free to directly
* use nghttp2 APIs or make changes to sh2lib.c for realising your objectives.
*
* TODO:
* - Allowing to query response code, content-type etc in the receive callback
* - A simple function for per-stream header callback
*/
/**
* @brief Handle for working with sh2lib APIs
*/
struct sh2lib_handle {
nghttp2_session *http2_sess; /*!< Pointer to the HTTP2 session handle */
char *hostname; /*!< The hostname we are connected to */
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 */
#define DATA_RECV_FRAME_COMPLETE 2
/**
* @brief Function Prototype for data receive callback
*
* This function gets called whenever data is received on any stream. The
* function is also called for indicating events like frame receive complete, or
* end of stream. The function may get called multiple times as long as data is
* received on the stream.
*
* @param[in] handle Pointer to the sh2lib handle.
* @param[in] data Pointer to a buffer that contains the data received.
* @param[in] len The length of valid data stored at the 'data' pointer.
* @param[in] flags Flags indicating whether the stream is reset (DATA_RECV_RST_STREAM) or
* this particularly frame is completely received
* DATA_RECV_FRAME_COMPLETE).
*
* @return The function should return 0
*/
typedef int (*sh2lib_frame_data_recv_cb_t)(struct sh2lib_handle *handle, const char *data, size_t len, int flags);
/**
* @brief Function Prototype for callback to send data in PUT/POST
*
* This function gets called whenever nghttp2 wishes to send data, like for
* PUT/POST requests to the server. The function keeps getting called until this
* function sets the flag NGHTTP2_DATA_FLAG_EOF to indicate end of data.
*
* @param[in] handle Pointer to the sh2lib handle.
* @param[out] data Pointer to a buffer that should contain the data to send.
* @param[in] len The maximum length of data that can be sent out by this function.
* @param[out] data_flags Pointer to the data flags. The NGHTTP2_DATA_FLAG_EOF
* should be set in the data flags to indicate end of new data.
*
* @return The function should return the number of valid bytes stored in the
* data pointer
*/
typedef int (*sh2lib_putpost_data_cb_t)(struct sh2lib_handle *handle, char *data, size_t len, uint32_t *data_flags);
/**
* @brief Connect to a URI using HTTP/2
*
* This API opens an HTTP/2 connection with the provided URI. If successful, the
* hd pointer is populated with a valid handle for subsequent communication.
*
* 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'.
* @return
* - ESP_OK if the connection was successful
* - ESP_FAIL if the connection fails
*/
int sh2lib_connect(struct sh2lib_config_t *cfg, struct sh2lib_handle *hd);
/**
* @brief Free a sh2lib handle
*
* This API frees-up an sh2lib handle, thus closing any open connections that
* may be associated with this handle, and freeing up any resources.
*
* @param[in] hd Pointer to a variable of the type 'struct sh2lib_handle'.
*
*/
void sh2lib_free(struct sh2lib_handle *hd);
/**
* @brief Setup an HTTP GET request stream
*
* This API sets up an HTTP GET request to be sent out to the server. A new
* stream is created for handling the request. Once the request is setup, the
* API sh2lib_execute() must be called to actually perform the socket I/O with
* the server.
*
* @param[in] hd Pointer to a variable of the type 'struct sh2lib_handle'.
* @param[in] path Pointer to the string that contains the resource to
* perform the HTTP GET operation on (for example, /users).
* @param[in] recv_cb The callback function that should be called for
* processing the request's response
*
* @return
* - ESP_OK if request setup is successful
* - ESP_FAIL if the request setup fails
*/
int sh2lib_do_get(struct sh2lib_handle *hd, const char *path, sh2lib_frame_data_recv_cb_t recv_cb);
/**
* @brief Setup an HTTP POST request stream
*
* This API sets up an HTTP POST request to be sent out to the server. A new
* stream is created for handling the request. Once the request is setup, the
* API sh2lib_execute() must be called to actually perform the socket I/O with
* the server.
*
* @param[in] hd Pointer to a variable of the type 'struct sh2lib_handle'.
* @param[in] path Pointer to the string that contains the resource to
* perform the HTTP POST operation on (for example, /users).
* @param[in] send_cb The callback function that should be called for
* sending data as part of this request.
* @param[in] recv_cb The callback function that should be called for
* processing the request's response
*
* @return
* - ESP_OK if request setup is successful
* - ESP_FAIL if the request setup fails
*/
int sh2lib_do_post(struct sh2lib_handle *hd, const char *path,
sh2lib_putpost_data_cb_t send_cb,
sh2lib_frame_data_recv_cb_t recv_cb);
/**
* @brief Setup an HTTP PUT request stream
*
* This API sets up an HTTP PUT request to be sent out to the server. A new
* stream is created for handling the request. Once the request is setup, the
* API sh2lib_execute() must be called to actually perform the socket I/O with
* the server.
*
* @param[in] hd Pointer to a variable of the type 'struct sh2lib_handle'.
* @param[in] path Pointer to the string that contains the resource to
* perform the HTTP PUT operation on (for example, /users).
* @param[in] send_cb The callback function that should be called for
* sending data as part of this request.
* @param[in] recv_cb The callback function that should be called for
* processing the request's response
*
* @return
* - ESP_OK if request setup is successful
* - ESP_FAIL if the request setup fails
*/
int sh2lib_do_put(struct sh2lib_handle *hd, const char *path,
sh2lib_putpost_data_cb_t send_cb,
sh2lib_frame_data_recv_cb_t recv_cb);
/**
* @brief Execute send/receive on an HTTP/2 connection
*
* While the API sh2lib_do_get(), sh2lib_do_post() setup the requests to be
* initiated with the server, this API performs the actual data send/receive
* operations on the HTTP/2 connection. The callback functions are accordingly
* called during the processing of these requests.
*
* @param[in] hd Pointer to a variable of the type 'struct sh2lib_handle'
*
* @return
* - ESP_OK if the connection was successful
* - ESP_FAIL if the connection fails
*/
int sh2lib_execute(struct sh2lib_handle *hd);
#define SH2LIB_MAKE_NV(NAME, VALUE) \
{ \
(uint8_t *)NAME, (uint8_t *)VALUE, strlen(NAME), strlen(VALUE), \
NGHTTP2_NV_FLAG_NONE \
}
/**
* @brief Setup an HTTP GET request stream with custom name-value pairs
*
* For a simpler version of the API, please refer to sh2lib_do_get().
*
* This API sets up an HTTP GET request to be sent out to the server. A new
* stream is created for handling the request. Once the request is setup, the
* API sh2lib_execute() must be called to actually perform the socket I/O with
* the server.
*
* Please note that the following name value pairs MUST be a part of the request
* - name:value
* - ":method":"GET"
* - ":scheme":"https"
* - ":path":<the-path-for-the-GET-operation> (for example, /users)
*
* @param[in] hd Pointer to a variable of the type 'struct sh2lib_handle'.
* @param[in] nva An array of name-value pairs that should be part of the request.
* @param[in] nvlen The number of elements in the array pointed to by 'nva'.
* @param[in] recv_cb The callback function that should be called for
* processing the request's response
*
* @return
* - ESP_OK if request setup is successful
* - ESP_FAIL if the request setup fails
*/
int sh2lib_do_get_with_nv(struct sh2lib_handle *hd, const nghttp2_nv *nva, size_t nvlen, sh2lib_frame_data_recv_cb_t recv_cb);
/**
* @brief Setup an HTTP PUT/POST request stream with custom name-value pairs
*
* For a simpler version of the API, please refer to sh2lib_do_put() or
* sh2lib_do_post().
*
* This API sets up an HTTP PUT/POST request to be sent out to the server. A new
* stream is created for handling the request. Once the request is setup, the
* API sh2lib_execute() must be called to actually perform the socket I/O with
* the server.
*
* Please note that the following name value pairs MUST be a part of the request
* - name:value
* - ":method":"PUT" (or POST)
* - ":scheme":"https"
* - ":path":<the-path-for-the-PUT-operation> (for example, /users)
*
* @param[in] hd Pointer to a variable of the type 'struct sh2lib_handle'.
* @param[in] nva An array of name-value pairs that should be part of the request.
* @param[in] nvlen The number of elements in the array pointed to by 'nva'.
* @param[in] send_cb The callback function that should be called for
* sending data as part of this request.
* @param[in] recv_cb The callback function that should be called for
* processing the request's response
*
* @return
* - ESP_OK if request setup is successful
* - ESP_FAIL if the request setup fails
*/
int sh2lib_do_putpost_with_nv(struct sh2lib_handle *hd, const nghttp2_nv *nva, size_t nvlen,
sh2lib_putpost_data_cb_t send_cb,
sh2lib_frame_data_recv_cb_t recv_cb);
#endif /* ! __ESP_EXAMPLE_SH2_LIB_H_ */

View File

@ -0,0 +1,3 @@
## IDF Component Manager Manifest File
dependencies:
espressif/sh2lib: "~1.0.0"

View File

@ -72,6 +72,7 @@ ignore:
include:
- components/bt/host/nimble/nimble/
- components/bt/common/osi/
- components/http_parser/
- components/wpa_supplicant/src/
- '!components/wpa_supplicant/esp_supplicant/'
- components/bt/host/bluedroid/

View File

@ -1397,10 +1397,6 @@ components/newlib/test_apps/app_test.py
components/newlib/test_apps/main/test_newlib_main.c
components/newlib/test_apps/main/test_stdatomic.c
components/newlib/time.c
components/nghttp/port/http_parser.c
components/nghttp/port/include/http_parser.h
components/nghttp/port/include/nghttp2/nghttp2ver.h
components/nghttp/private_include/config.h
components/nvs_flash/host_test/fixtures/test_fixtures.hpp
components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp
components/nvs_flash/include/nvs.h
@ -2669,7 +2665,6 @@ examples/protocols/esp_local_ctrl/main/app_main.c
examples/protocols/esp_local_ctrl/main/esp_local_ctrl_service.c
examples/protocols/esp_local_ctrl/scripts/esp_local_ctrl.py
examples/protocols/esp_local_ctrl/scripts/proto_lc.py
examples/protocols/http2_request/components/sh2lib/sh2lib.h
examples/protocols/http2_request/main/http2_request_example_main.c
examples/protocols/http_request/main/http_request_example_main.c
examples/protocols/http_server/advanced_tests/http_server_advanced_test.py

View File

@ -49,7 +49,6 @@ components/mbedtls/port/include/
components/mbedtls/mbedtls/include/mbedtls/
components/coap/
components/nghttp/
components/esp-tls/private_include/

View File

@ -13,3 +13,7 @@ components/freertos/FreeRTOS-Kernel/include/freertos/*.h
# wpa_supplicant upstream code
components/wpa_supplicant/src/**
components/wpa_supplicant/include/**
# HTTP Parser code
components/http_parser/*.c
components/http_parser/*.h

View File

@ -26,7 +26,6 @@ skip:
- "components/lwip/lwip"
- "components/mbedtls/mbedtls"
- "components/mqtt/esp-mqtt"
- "components/nghttp/nghttp2"
- "components/openthread/lib"
- "components/openthread/openthread"
- "components/protobuf-c/protobuf-c"