mirror of
https://github.com/espressif/esp-protocols.git
synced 2026-07-10 02:20:46 +02:00
feat(lws): add LWS_WITH_CUSTOM_HEADERS option and UTC timegm
Two ESP-IDF usability additions for libwebsockets consumers such as the AWS KVS WebRTC signaling client: - LWS_WITH_CUSTOM_HEADERS Kconfig option (off by default). When set, the websockets target gets LWS_WITH_CUSTOM_HEADERS / LWS_WITH_CUSTOM_HTTP_HEADERS as PUBLIC compile definitions, so lws_hdr_custom_copy() is available to lws and its consumers. lws's own option(LWS_WITH_CUSTOM_HEADERS) is gated 'H1 only' and is dropped on the FreeRTOS/minimal profile, so the compile-def is the reliable route. Used to read service-specific response headers (e.g. x-amzn-RequestId). - UTC timegm(). ESP picolibc ships timegm() but gates its <time.h> prototype behind BSD/GNU visibility and the symbol isn't reliably linkable, so lws's CHECK_FUNCTION_EXISTS(timegm) fails and lws_http_date_parse_unix() falls back to mktime() (local TZ) — misreading a server 'GMT' Date header by the TZ offset, which breaks HTTP clock-skew handling (e.g. AWS SigV4). Force LWS_HAVE_TIMEGM and provide a dependency-free UTC timegm() in port/, prototype force-included. Validated on an ESP32-P4 esp-rainmaker camera (CONFIG_LWS_WITH_CUSTOM_HEADERS=y + CONFIG_LWS_WITH_THREADPOOL=y): KVS WebRTC signaling links and streams end-to-end, SigV4 clock-skew correct.
This commit is contained in:
@@ -25,6 +25,19 @@ else()
|
||||
set(LWS_WITH_THREADPOOL OFF CACHE INTERNAL "No worker thread pool")
|
||||
endif()
|
||||
|
||||
# Custom HTTP header support (lws_hdr_custom_*) is applied as a compile definition
|
||||
# after add_subdirectory() below: lws's option(LWS_WITH_CUSTOM_HEADERS) is gated
|
||||
# "H1 only" and gets dropped on the FreeRTOS/minimal profile, so the CMake-option
|
||||
# route leaves it #undef in lws_config.h. A PUBLIC compile define is reliable.
|
||||
|
||||
# ESP picolibc ships timegm() in libc but gates its <time.h> prototype behind
|
||||
# BSD/GNU visibility (and the symbol isn't reliably linkable), so lws's
|
||||
# CHECK_FUNCTION_EXISTS(timegm) fails and lws_http_date_parse_unix() falls back to
|
||||
# mktime() — which applies the local TZ and misreads a server "GMT" Date header by
|
||||
# the TZ offset (breaks HTTP clock-skew handling, e.g. AWS SigV4). Force-enable and
|
||||
# supply a UTC timegm() via the port (prototype shim force-included into lws).
|
||||
set(LWS_HAVE_TIMEGM 1 CACHE INTERNAL "ESP port provides UTC timegm()" FORCE)
|
||||
|
||||
|
||||
set(WRAP_FUNCTIONS mbedtls_ssl_handshake_step
|
||||
lws_adopt_descriptor_vhost)
|
||||
@@ -42,3 +55,16 @@ add_subdirectory(libwebsockets)
|
||||
|
||||
# pollfd.c at this lws pin has an unused 'vpt' on FreeRTOS; drop after the next bump.
|
||||
target_compile_options(websockets PRIVATE -Wno-unused-variable)
|
||||
|
||||
# Supply a UTC timegm() for lws (LWS_HAVE_TIMEGM set above). lws_http_date_parse_unix()
|
||||
# calls timegm(); the port source defines it and the shim force-includes a prototype
|
||||
# so date.c links against it instead of an implicit (int-returning) declaration.
|
||||
target_sources(websockets PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/port/lws_timegm.c")
|
||||
target_compile_options(websockets PRIVATE "-include${CMAKE_CURRENT_SOURCE_DIR}/port/lws_timegm_shim.h")
|
||||
|
||||
# Enable custom HTTP header read APIs (lws_hdr_custom_*). PUBLIC so both lws's own
|
||||
# sources and consumers (e.g. KVS WebRTC signaling) see the macro. Reliable where
|
||||
# the lws CMake option is dropped on the FreeRTOS/minimal profile.
|
||||
if(CONFIG_LWS_WITH_CUSTOM_HEADERS)
|
||||
target_compile_definitions(websockets PUBLIC LWS_WITH_CUSTOM_HEADERS=1 LWS_WITH_CUSTOM_HTTP_HEADERS=1)
|
||||
endif()
|
||||
|
||||
@@ -32,4 +32,14 @@ menu "libwebsockets"
|
||||
or other work from the lws service thread (e.g. AWS KVS
|
||||
WebRTC signaling). Costs a few hundred bytes of static data.
|
||||
|
||||
config LWS_WITH_CUSTOM_HEADERS
|
||||
bool "Build libwebsockets with custom HTTP header support"
|
||||
default n
|
||||
help
|
||||
Enables the lws_hdr_custom_* APIs for reading non-standard
|
||||
HTTP headers (sets LWS_WITH_CUSTOM_HEADERS and
|
||||
LWS_WITH_CUSTOM_HTTP_HEADERS). Required by clients that must
|
||||
read service-specific response headers — e.g. AWS KVS WebRTC
|
||||
signaling reads the x-amzn-RequestId header over HTTP/1.1.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* UTC timegm() for the libwebsockets build on ESP-IDF.
|
||||
*
|
||||
* ESP's picolibc ships timegm() in libc but its <time.h> prototype is gated
|
||||
* behind BSD/GNU visibility, and the symbol is not reliably linkable in the
|
||||
* IDF cross-build, so lws's CHECK_FUNCTION_EXISTS(timegm) fails. With
|
||||
* LWS_HAVE_TIMEGM off, lws_http_date_parse_unix() falls back to mktime(),
|
||||
* which interprets a struct tm in the LOCAL timezone — so a server "GMT" Date
|
||||
* header is misread by the configured TZ offset, corrupting HTTP clock-skew
|
||||
* handling (e.g. AWS SigV4 signing). Provide a dependency-free UTC conversion.
|
||||
*/
|
||||
#include <time.h>
|
||||
|
||||
static int lws_is_leap(int y)
|
||||
{
|
||||
return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
|
||||
}
|
||||
|
||||
/* weak: if a future picolibc/newlib exports a linkable timegm(), the libc one
|
||||
* wins and this definition is discarded — no multiple-definition error. */
|
||||
__attribute__((weak)) time_t timegm(struct tm *tm)
|
||||
{
|
||||
static const int mdays_cum[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
|
||||
|
||||
int year = tm->tm_year + 1900;
|
||||
int month = tm->tm_mon;
|
||||
/* Normalize month into [0,11], carrying the remainder into the year.
|
||||
* Works for negative tm_mon too (including exact multiples of -12), so
|
||||
* mdays_cum[] is never indexed out of bounds. */
|
||||
year += month / 12;
|
||||
month %= 12;
|
||||
if (month < 0) {
|
||||
month += 12;
|
||||
year -= 1;
|
||||
}
|
||||
|
||||
long long days = 0;
|
||||
if (year >= 1970) {
|
||||
for (int y = 1970; y < year; ++y) {
|
||||
days += 365 + lws_is_leap(y);
|
||||
}
|
||||
} else {
|
||||
for (int y = year; y < 1970; ++y) {
|
||||
days -= 365 + lws_is_leap(y);
|
||||
}
|
||||
}
|
||||
|
||||
days += mdays_cum[month];
|
||||
if (month > 1 && lws_is_leap(year)) {
|
||||
days += 1;
|
||||
}
|
||||
days += (tm->tm_mday - 1);
|
||||
|
||||
return (time_t)(days * 86400LL
|
||||
+ (long long)tm->tm_hour * 3600
|
||||
+ (long long)tm->tm_min * 60
|
||||
+ (long long)tm->tm_sec);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* Prototype shim, force-included into the libwebsockets build.
|
||||
*
|
||||
* picolibc gates the timegm() prototype behind BSD/GNU visibility, so lws's
|
||||
* date.c would otherwise see an implicit (int-returning) declaration and
|
||||
* truncate the 64-bit time_t. This declares it so date.c links against the
|
||||
* UTC timegm() provided in port/lws_timegm.c. See CMakeLists.txt.
|
||||
*/
|
||||
#pragma once
|
||||
#include <time.h>
|
||||
|
||||
/* Only the ESP libc (picolibc/newlib) hides timegm()'s prototype behind BSD/GNU
|
||||
* visibility; declare it for those. A libc that already declares it (e.g. glibc)
|
||||
* needs no redeclaration. `#pragma once` already guards double-inclusion. */
|
||||
#if defined(__PICOLIBC__) || defined(__NEWLIB__)
|
||||
time_t timegm(struct tm *__tp);
|
||||
#endif
|
||||
Reference in New Issue
Block a user