Merge branch 'http_request_remove_list' into integration

# Conflicts:
#	esphome/components/http_request/http_request.h
#	esphome/components/http_request/http_request_arduino.cpp
#	esphome/components/http_request/http_request_arduino.h
#	esphome/components/http_request/http_request_host.cpp
#	esphome/components/http_request/http_request_host.h
#	esphome/components/http_request/http_request_idf.cpp
#	esphome/components/http_request/http_request_idf.h
This commit is contained in:
J. Nick Koston
2026-02-18 14:32:52 -06:00
8 changed files with 40 additions and 37 deletions

View File

@@ -314,7 +314,7 @@ async def http_request_action_to_code(config, action_id, template_arg, args):
cg.add(var.add_request_header(key, template_))
for value in config.get(CONF_COLLECT_HEADERS, []):
cg.add(var.add_collect_header(value))
cg.add(var.add_collect_header(value.lower()))
if response_conf := config.get(CONF_ON_RESPONSE):
if capture_response:

View File

@@ -80,9 +80,9 @@ inline bool is_redirect(int const status) {
inline bool is_success(int const status) { return status >= HTTP_STATUS_OK && status < HTTP_STATUS_MULTIPLE_CHOICES; }
/// Check if a header name should be collected (linear scan, fine for small lists)
inline bool should_collect_header(const std::vector<std::string> &collect_headers,
inline bool should_collect_header(const std::vector<std::string> &lower_case_collect_headers,
const std::string &lower_header_name) {
for (const auto &h : collect_headers) {
for (const auto &h : lower_case_collect_headers) {
if (h == lower_header_name)
return true;
}
@@ -337,8 +337,8 @@ class HttpRequestComponent : public Component {
return this->start(url, "GET", "", request_headers);
}
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) {
return this->start(url, "GET", "", request_headers, collect_headers);
const std::vector<std::string> &lower_case_collect_headers) {
return this->start(url, "GET", "", request_headers, lower_case_collect_headers);
}
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body) {
return this->start(url, "POST", body, std::vector<Header>{});
@@ -349,8 +349,8 @@ class HttpRequestComponent : public Component {
}
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) {
return this->start(url, "POST", body, request_headers, collect_headers);
const std::vector<std::string> &lower_case_collect_headers) {
return this->start(url, "POST", body, request_headers, lower_case_collect_headers);
}
// Remove before 2027.1.0
@@ -397,8 +397,12 @@ class HttpRequestComponent : public Component {
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::vector<Header> &request_headers,
const std::set<std::string> &collect_headers) {
return this->start(url, method, body, request_headers,
std::vector<std::string>(collect_headers.begin(), collect_headers.end()));
std::vector<std::string> lower;
lower.reserve(collect_headers.size());
for (const auto &h : collect_headers) {
lower.push_back(str_lower_case(h));
}
return this->perform(url, method, body, request_headers, lower);
}
// Remove before 2027.1.0
@@ -408,34 +412,33 @@ class HttpRequestComponent : public Component {
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers,
const std::set<std::string> &collect_headers) {
return this->start(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()),
std::vector<std::string>(collect_headers.begin(), collect_headers.end()));
std::vector<std::string> lower;
lower.reserve(collect_headers.size());
for (const auto &h : collect_headers) {
lower.push_back(str_lower_case(h));
}
return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()), lower);
}
// Remove before 2027.1.0
ESPDEPRECATED("Pass request_headers as std::vector<Header> instead of std::list. Removed in 2027.1.0.", "2026.7.0")
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::list<Header> &request_headers,
const std::vector<std::string> &collect_headers) {
return this->start(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()),
collect_headers);
const std::vector<std::string> &lower_case_collect_headers) {
return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()),
lower_case_collect_headers);
}
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) {
std::vector<std::string> lower_case_collect_headers;
lower_case_collect_headers.reserve(collect_headers.size());
for (const auto &header : collect_headers) {
lower_case_collect_headers.push_back(str_lower_case(header));
}
const std::vector<std::string> &lower_case_collect_headers) {
return this->perform(url, method, body, request_headers, lower_case_collect_headers);
}
protected:
virtual std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method,
const std::string &body, const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) = 0;
const std::vector<std::string> &lower_case_collect_headers) = 0;
const char *useragent_{nullptr};
bool follow_redirects_{};
uint16_t redirect_limit_{};
@@ -458,7 +461,7 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
this->request_headers_.push_back({key, value});
}
void add_collect_header(const char *value) { this->collect_headers_.push_back(value); }
void add_collect_header(const char *value) { this->lower_case_collect_headers_.push_back(value); }
void init_json(size_t count) { this->json_.init(count); }
void add_json(const char *key, TemplatableValue<std::string, Ts...> value) { this->json_.push_back({key, value}); }
@@ -498,7 +501,7 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
}
auto container = this->parent_->start(this->url_.value(x...), this->method_.value(x...), body, request_headers,
this->collect_headers_);
this->lower_case_collect_headers_);
auto captured_args = std::make_tuple(x...);
@@ -561,7 +564,7 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
void encode_json_func_(Ts... x, JsonObject root) { this->json_func_(x..., root); }
HttpRequestComponent *parent_;
FixedVector<std::pair<const char *, TemplatableValue<const char *, Ts...>>> request_headers_{};
std::vector<std::string> collect_headers_{"content-type", "content-length"};
std::vector<std::string> lower_case_collect_headers_{"content-type", "content-length"};
FixedVector<std::pair<const char *, TemplatableValue<std::string, Ts...>>> json_{};
std::function<void(Ts..., JsonObject)> json_func_{nullptr};
#ifdef USE_HTTP_REQUEST_RESPONSE

View File

@@ -27,7 +27,7 @@ static constexpr int ESP8266_SSL_ERR_OOM = -1000;
std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &url, const std::string &method,
const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) {
const std::vector<std::string> &lower_case_collect_headers) {
if (!network::is_connected()) {
this->status_momentary_error("failed", 1000);
ESP_LOGW(TAG, "HTTP Request failed; Not connected to network");
@@ -107,9 +107,9 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
}
// returned needed headers must be collected before the requests
const char *header_keys[collect_headers.size()];
const char *header_keys[lower_case_collect_headers.size()];
int index = 0;
for (auto const &header_name : collect_headers) {
for (auto const &header_name : lower_case_collect_headers) {
header_keys[index++] = header_name.c_str();
}
container->client_.collectHeaders(header_keys, index);
@@ -164,7 +164,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
auto header_count = container->client_.headers();
for (int i = 0; i < header_count; i++) {
const std::string header_name = str_lower_case(container->client_.headerName(i).c_str());
if (should_collect_header(collect_headers, header_name)) {
if (should_collect_header(lower_case_collect_headers, header_name)) {
std::string header_value = container->client_.header(i).c_str();
ESP_LOGD(TAG, "Received response header, name: %s, value: %s", header_name.c_str(), header_value.c_str());
container->response_headers_.push_back({header_name, header_value});

View File

@@ -50,7 +50,7 @@ class HttpRequestArduino : public HttpRequestComponent {
protected:
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) override;
const std::vector<std::string> &lower_case_collect_headers) override;
};
} // namespace esphome::http_request

View File

@@ -19,7 +19,7 @@ static const char *const TAG = "http_request.host";
std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url, const std::string &method,
const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) {
const std::vector<std::string> &lower_case_collect_headers) {
if (!network::is_connected()) {
this->status_momentary_error("failed", 1000);
ESP_LOGW(TAG, "HTTP Request failed; Not connected to network");
@@ -116,7 +116,7 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
for (auto header : response.headers) {
ESP_LOGD(TAG, "Header: %s: %s", header.first.c_str(), header.second.c_str());
auto lower_name = str_lower_case(header.first);
if (should_collect_header(collect_headers, lower_name)) {
if (should_collect_header(lower_case_collect_headers, lower_name)) {
container->response_headers_.push_back({lower_name, header.second});
}
}

View File

@@ -20,7 +20,7 @@ class HttpRequestHost : public HttpRequestComponent {
public:
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) override;
const std::vector<std::string> &lower_case_collect_headers) override;
void set_ca_path(const char *ca_path) { this->ca_path_ = ca_path; }
protected:

View File

@@ -19,7 +19,7 @@ namespace esphome::http_request {
static const char *const TAG = "http_request.idf";
struct UserData {
const std::vector<std::string> &collect_headers;
const std::vector<std::string> &lower_case_collect_headers;
std::vector<Header> &response_headers;
};
@@ -38,7 +38,7 @@ esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) {
switch (evt->event_id) {
case HTTP_EVENT_ON_HEADER: {
const std::string header_name = str_lower_case(evt->header_key);
if (should_collect_header(user_data->collect_headers, header_name)) {
if (should_collect_header(user_data->lower_case_collect_headers, header_name)) {
const std::string header_value = evt->header_value;
ESP_LOGD(TAG, "Received response header, name: %s, value: %s", header_name.c_str(), header_value.c_str());
user_data->response_headers.push_back({header_name, header_value});
@@ -55,7 +55,7 @@ esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) {
std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, const std::string &method,
const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) {
const std::vector<std::string> &lower_case_collect_headers) {
if (!network::is_connected()) {
this->status_momentary_error("failed", 1000);
ESP_LOGE(TAG, "HTTP Request failed; Not connected to network");
@@ -118,7 +118,7 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
container->set_secure(secure);
auto user_data = UserData{collect_headers, container->response_headers_};
auto user_data = UserData{lower_case_collect_headers, container->response_headers_};
esp_http_client_set_user_data(client, static_cast<void *>(&user_data));
for (const auto &header : request_headers) {

View File

@@ -38,7 +38,7 @@ class HttpRequestIDF : public HttpRequestComponent {
protected:
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
const std::vector<Header> &request_headers,
const std::vector<std::string> &collect_headers) override;
const std::vector<std::string> &lower_case_collect_headers) override;
// if zero ESP-IDF will use DEFAULT_HTTP_BUF_SIZE
uint16_t buffer_size_rx_{};
uint16_t buffer_size_tx_{};