The 1460-byte MULTIPART_CHUNK_SIZE buffer was moved from heap to stack
in #13549, but the httpd task stack is only ~4096-5632 bytes. This
causes a stack overflow crash when processing OTA uploads, especially
on configs with BLE components that add additional stack pressure.
Move it back to heap since this buffer is only used during OTA uploads
(not a hot path), so heap fragmentation is not a concern here.
Fixes stack overflow: "A stack overflow in task httpd has been detected"
Refactor multipart utility functions to work with const char* + length
instead of std::string to eliminate temporary heap allocations during
header parsing. The original implementations used std::string for
convenience when the OTA multipart support was first added, but these
can be avoided since the multipart parser already provides raw pointers
and lengths in its callbacks.
- extract_header_param: takes (const char*, size_t, const char*, std::string&)
instead of (const std::string&, const std::string&) -> std::string.
Assigns directly to destination, avoiding intermediate string construction.
- str_startswith_case_insensitive: takes (const char*, size_t, const char*)
instead of (const std::string&, const std::string&)
- str_trim: takes (const char*, size_t, std::string&) instead of
(const std::string&) -> std::string
- Rename stristr to strcasestr_n with explicit haystack length parameter
to make the relationship to POSIX strcasestr clear and fix a latent
buffer over-read risk (stristr relied on null-termination which the
multipart parser does not guarantee for its callback data)
- process_header_ no longer creates a std::string copy of the raw
parser buffer before calling utility functions
Saves ~350 bytes of flash.
Replace ProtoVarInt temporaries with direct uint32_t encoding functions
to avoid unnecessary 64-bit widening on 32-bit architectures (ESP32 Xtensa).
- Add encode_varint_to_buffer() free function for direct buffer encoding
- Replace encode_varint_raw(ProtoVarInt) with uint32_t-native implementation
- Add encode_varint_raw_64() for the few call sites needing 64-bit (BLE)
- Remove unused ProtoVarInt::encode() and encode_to_buffer_unchecked()
- Remove dead null checks from ProtoVarInt::parse()
Net savings: -152 bytes flash on ESP32 IDF.
NVS/FDB write failures are permanent (flash worn out, partition full,
handle invalid). The NVS layer already performs internal garbage
collection during writes, so retrying the same call will always fail
again. Keeping failed entries in the vector leaked memory and forced
a reverse-iterate + per-element erase pattern that generated ~130
bytes of inlined vector move/destroy code for NVSData objects.
Replace with a forward range-for and a single clear() at the end.