In httpd_parse.c, cb_headers_complete() converted the HTTP parser's
content_length (uint64_t) to the request's content_len (size_t) via an
unsafe cast through (int). On a 32-bit size_t target a Content-Length
above 4 GiB silently truncated, enabling request smuggling where the
server and an upstream proxy disagree on the body length (CWE-681).
Reject any Content-Length above UINT32_MAX with 413 Content Too Large
before any handler runs. UINT32_MAX is the largest body length the
server can represent in size_t content_len on every target, so this is
the maximum the server can support; no configuration knob is needed.
Closes SEC-102
Closes SEC-229
httpd_req_get_hdr_value_str() detected truncation with `val_size < full_size`, where full_size is the strlcpy() return value. strlcpy() returns strlen() of the source (the terminating null is not counted), so truncation actually occurs when strlen(src) >= val_size. At strlen(src) == val_size the value is copied as val_size - 1 chars + NUL (i.e. truncated) yet ESP_OK was returned, so the caller never learned the value was cut.
Use `val_size <= full_size` and correct the misleading comment about strlcpy()'s return value.
Same truncation-reporting class fixed for httpd_cookie_key_value in PR #16202; httpd_req_get_hdr_value_str was missed. No memory-safety impact: strlcpy() null-terminates if val_size > 0.
Refactor the esp_err_to_name() system to decouple esp_common from
higher-level components. Instead of a monolithic generated table,
each component registers its error codes into a dedicated linker
section (.esp_err_msg_table) via idf_define_esp_err_codes() in its
CMakeLists.txt.
New files:
- tools/err_codes_extract.py: extract ESP_ERR_* defines from headers to CSV
- tools/err_codes_to_c.py: generate C source placing entries into linker section
- tools/err_codes_to_rst.py: generate RST documentation from error codes
- tools/cmake/err_codes.cmake: CMake module providing idf_define_esp_err_codes()
- components/esp_common/include/esp_err_codes.h: esp_err_msg_t typedef
- components/esp_common/src/esp_err_to_name_new.c: new lookup using link-time array
- tools/test_apps/build_system/err_codes_check/: CI test app
Changes:
- Remove all optional component dependencies from esp_common/CMakeLists.txt
- Add .esp_err_msg_table section to all 5 linker scripts
- Register error codes in 18 components via idf_define_esp_err_codes()
- Add new scripts to .gitlab/ci/rules.yml build_check patterns
- use new scripts to generate doc and add CI validation
- Update esp_err.rst to add description of composable code registration
httpd_stop() and httpd_req_async_handler_complete() both pushed
messages onto the control mbox via cs_send_to_ctrl_sock() without
reserving a slot in ctrl_sock_semaphore. Once the silent-drop fix
made the semaphore unconditional, the bypass became a real bug:
when the mbox is saturated by pending httpd_queue_work() items the
unguarded sendto() can return ENOBUFS, and even when it succeeds it
leaves the semaphore overstating free slots until the consumer
drains the message — a window during which a concurrent
httpd_queue_work() can take a slot but still find the mbox full.
Acquire the semaphore (portMAX_DELAY) before both sends and give it
back on send failure so the take/give invariant is preserved. The
httpd task is the consumer in both paths, so blocking is bounded
and deadlock-free. Reword the stale "no-op give on full" comment in
httpd_process_ctrl_msg() to reflect that only the recv-error path
relies on the cap behavior now.
PONG frames (opcode 0xA) were never dispatched to the user's WebSocket
handler despite an existing comment stating they should be. The dispatch
condition `ra->ws_type < HTTPD_WS_TYPE_CLOSE` excluded PONG (0xA)
since CLOSE is 0x8.
This caused a critical secondary bug: when the server sends PING frames
and the client responds with PONG, httpd_ws_recv_frame() is never
called for the PONG, leaving the remaining frame bytes (second_byte
plus 4-byte mask_key) unconsumed in the TCP buffer. On the next
WebSocket read, these orphaned bytes are misinterpreted as a new frame
header, causing either "WS frame is not properly masked" errors or
EAGAIN timeouts with garbage length values, effectively destroying
the connection.
Add `ra->ws_type == HTTPD_WS_TYPE_PONG` to the dispatch condition so
PONG frames reach the user handler, which calls httpd_ws_recv_frame()
to properly consume the frame bytes from the socket.
Closes https://github.com/espressif/esp-idf/issues/18227
This commit added demo to receive websocket single frame in chunks
using newly added API httpd_ws_recv_frame_part() with optimized memory.
closes https://github.com/espressif/esp-idf/pull/15622
Make it possible to disable http(s) server events. This improves
performance of the server, as http server creates events on every signle
read or write to the socket.
1. In async requests, if the two or more requests are made on same
socket then it used to block the second request.
2. The main thread is used to block on select call. And there done
no FD_SET for particular fd.
Closes https://github.com/espressif/esp-idf/issues/16998
1. If the user wants authenticate the request, then user needs to do
this before upgrading the protocol to websocket.
2. To achieve this, added pre_handshake_callack, which will execute
before handshake, i.e. before switching protocol.