Compare commits

...

4 Commits

Author SHA1 Message Date
J. Nick Koston
4e67898073 improve comment 2026-01-28 06:45:14 -10:00
J. Nick Koston
0c868cbcc5 adjust comments, cases were reversed as I had the wrong file open 2026-01-28 06:38:01 -10:00
J. Nick Koston
e8ea90cb13 fix comment 2026-01-28 06:31:52 -10:00
J. Nick Koston
3744186c3d [http_request] Fix empty body for chunked transfer encoding responses 2026-01-28 05:02:24 -10:00
2 changed files with 33 additions and 7 deletions

View File

@@ -131,6 +131,10 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
}
}
// HTTPClient::getSize() returns -1 for chunked transfer encoding (no Content-Length).
// When cast to size_t, -1 becomes SIZE_MAX (4294967295 on 32-bit).
// The read() method handles this: bytes_read_ can never reach SIZE_MAX, so the
// early return check (bytes_read_ >= content_length) will never trigger.
int content_length = container->client_.getSize();
ESP_LOGD(TAG, "Content-Length: %d", content_length);
container->content_length = (size_t) content_length;
@@ -167,17 +171,23 @@ int HttpContainerArduino::read(uint8_t *buf, size_t max_len) {
}
int available_data = stream_ptr->available();
int bufsize = std::min(max_len, std::min(this->content_length - this->bytes_read_, (size_t) available_data));
// For chunked transfer encoding, HTTPClient::getSize() returns -1, which becomes SIZE_MAX when
// cast to size_t. SIZE_MAX - bytes_read_ is still huge, so it won't limit the read.
size_t remaining = (this->content_length > 0) ? (this->content_length - this->bytes_read_) : max_len;
int bufsize = std::min(max_len, std::min(remaining, (size_t) available_data));
if (bufsize == 0) {
this->duration_ms += (millis() - start);
// Check if we've read all expected content
if (this->bytes_read_ >= this->content_length) {
// Check if we've read all expected content (only valid when content_length is known and not SIZE_MAX)
// For chunked encoding (content_length == SIZE_MAX), we can't use this check
if (this->content_length > 0 && this->bytes_read_ >= this->content_length) {
return 0; // All content read successfully
}
// No data available - check if connection is still open
// For chunked encoding, !connected() after reading means EOF (all chunks received)
// For known content_length with bytes_read_ < content_length, it means connection dropped
if (!stream_ptr->connected()) {
return HTTP_ERROR_CONNECTION_CLOSED; // Connection closed prematurely
return HTTP_ERROR_CONNECTION_CLOSED; // Connection closed or EOF for chunked
}
return 0; // No data yet, caller should retry
}

View File

@@ -157,6 +157,8 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
}
container->feed_wdt();
// esp_http_client_fetch_headers() returns 0 for chunked transfer encoding (no Content-Length header).
// The read() method handles content_length == 0 specially to support chunked responses.
container->content_length = esp_http_client_fetch_headers(client);
container->feed_wdt();
container->status_code = esp_http_client_get_status_code(client);
@@ -225,14 +227,22 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
//
// We normalize to HttpContainer::read() contract:
// > 0: bytes read
// 0: no data yet / all content read (caller should check bytes_read vs content_length)
// 0: all content read (only returned when content_length is known and fully read)
// < 0: error/connection closed
//
// Note on chunked transfer encoding:
// esp_http_client_fetch_headers() returns 0 for chunked responses (no Content-Length header).
// We handle this by skipping the content_length check when content_length is 0,
// allowing esp_http_client_read() to handle chunked decoding internally and signal EOF
// by returning 0.
int HttpContainerIDF::read(uint8_t *buf, size_t max_len) {
const uint32_t start = millis();
watchdog::WatchdogManager wdm(this->parent_->get_watchdog_timeout());
// Check if we've already read all expected content
if (this->bytes_read_ >= this->content_length) {
// Skip this check when content_length is 0 (chunked transfer encoding or unknown length)
// For chunked responses, esp_http_client_read() will return 0 when all data is received
if (this->content_length > 0 && this->bytes_read_ >= this->content_length) {
return 0; // All content read successfully
}
@@ -247,7 +257,13 @@ int HttpContainerIDF::read(uint8_t *buf, size_t max_len) {
return read_len_or_error;
}
// Connection closed by server before all content received
// esp_http_client_read() returns 0 in two cases:
// 1. Known content_length: connection closed before all data received (error)
// 2. Chunked encoding (content_length == 0): end of stream reached (EOF)
// For case 1, returning HTTP_ERROR_CONNECTION_CLOSED is correct.
// For case 2, 0 indicates that all chunked data has already been delivered
// in previous successful read() calls, so treating this as a closed
// connection does not cause any loss of response data.
if (read_len_or_error == 0) {
return HTTP_ERROR_CONNECTION_CLOSED;
}