mirror of
https://github.com/esphome/esphome.git
synced 2026-09-17 18:18:43 +00:00
[http_request] Take the URL and method as C strings (#19215)
This commit is contained in:
@@ -331,27 +331,46 @@ class HttpRequestComponent : public Component {
|
||||
void set_follow_redirects(bool follow_redirects) { this->follow_redirects_ = follow_redirects; }
|
||||
void set_redirect_limit(uint16_t limit) { this->redirect_limit_ = limit; }
|
||||
|
||||
std::shared_ptr<HttpContainer> get(const std::string &url) {
|
||||
return this->start(url, "GET", "", std::vector<Header>{});
|
||||
}
|
||||
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers) {
|
||||
std::shared_ptr<HttpContainer> get(const char *url) { return this->start(url, "GET", "", std::vector<Header>{}); }
|
||||
std::shared_ptr<HttpContainer> get(const char *url, const std::vector<Header> &request_headers) {
|
||||
return this->start(url, "GET", "", request_headers);
|
||||
}
|
||||
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers,
|
||||
std::shared_ptr<HttpContainer> get(const char *url, const std::vector<Header> &request_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) {
|
||||
std::shared_ptr<HttpContainer> post(const char *url, const std::string &body) {
|
||||
return this->start(url, "POST", body, std::vector<Header>{});
|
||||
}
|
||||
std::shared_ptr<HttpContainer> post(const char *url, const std::string &body,
|
||||
const std::vector<Header> &request_headers) {
|
||||
return this->start(url, "POST", body, request_headers);
|
||||
}
|
||||
std::shared_ptr<HttpContainer> post(const char *url, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
return this->start(url, "POST", body, request_headers, lower_case_collect_headers);
|
||||
}
|
||||
|
||||
std::shared_ptr<HttpContainer> get(const std::string &url) { return this->get(url.c_str()); }
|
||||
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers) {
|
||||
return this->get(url.c_str(), request_headers);
|
||||
}
|
||||
std::shared_ptr<HttpContainer> get(const std::string &url, const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
return this->get(url.c_str(), request_headers, lower_case_collect_headers);
|
||||
}
|
||||
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body) {
|
||||
return this->post(url.c_str(), body);
|
||||
}
|
||||
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
|
||||
const std::vector<Header> &request_headers) {
|
||||
return this->start(url, "POST", body, request_headers);
|
||||
return this->post(url.c_str(), body, request_headers);
|
||||
}
|
||||
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
return this->start(url, "POST", body, request_headers, lower_case_collect_headers);
|
||||
return this->post(url.c_str(), body, request_headers, lower_case_collect_headers);
|
||||
}
|
||||
|
||||
// Remove before 2027.1.0
|
||||
@@ -379,11 +398,15 @@ class HttpRequestComponent : public Component {
|
||||
return this->post(url, body, std::vector<Header>(request_headers.begin(), request_headers.end()), collect_headers);
|
||||
}
|
||||
|
||||
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
|
||||
std::shared_ptr<HttpContainer> start(const char *url, const char *method, const std::string &body,
|
||||
const std::vector<Header> &request_headers) {
|
||||
// Call perform() directly to avoid ambiguity with the deprecated overloads
|
||||
return this->perform(url, method, body, request_headers, {});
|
||||
}
|
||||
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
|
||||
const std::vector<Header> &request_headers) {
|
||||
return this->start(url.c_str(), method.c_str(), body, request_headers);
|
||||
}
|
||||
|
||||
// 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")
|
||||
@@ -403,7 +426,7 @@ class HttpRequestComponent : public Component {
|
||||
for (const auto &h : collect_headers) {
|
||||
lower.push_back(str_lower_case(h)); // NOLINT
|
||||
}
|
||||
return this->perform(url, method, body, request_headers, lower);
|
||||
return this->perform(url.c_str(), method.c_str(), body, request_headers, lower);
|
||||
}
|
||||
|
||||
// Remove before 2027.1.0
|
||||
@@ -418,7 +441,8 @@ class HttpRequestComponent : public Component {
|
||||
for (const auto &h : collect_headers) {
|
||||
lower.push_back(str_lower_case(h)); // NOLINT
|
||||
}
|
||||
return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()), lower);
|
||||
return this->perform(url.c_str(), method.c_str(), body,
|
||||
std::vector<Header>(request_headers.begin(), request_headers.end()), lower);
|
||||
}
|
||||
|
||||
// Remove before 2027.1.0
|
||||
@@ -426,19 +450,25 @@ 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::vector<std::string> &lower_case_collect_headers) {
|
||||
return this->perform(url, method, body, std::vector<Header>(request_headers.begin(), request_headers.end()),
|
||||
return this->perform(url.c_str(), method.c_str(), 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,
|
||||
std::shared_ptr<HttpContainer> start(const char *url, const char *method, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
return this->perform(url, method, body, request_headers, 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> &lower_case_collect_headers) {
|
||||
return this->start(url.c_str(), method.c_str(), 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,
|
||||
virtual std::shared_ptr<HttpContainer> perform(const char *url, const char *method, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) = 0;
|
||||
const char *useragent_{nullptr};
|
||||
bool follow_redirects_{};
|
||||
@@ -499,8 +529,8 @@ template<typename... Ts> class HttpRequestSendAction final : public Action<Ts...
|
||||
request_headers.push_back({key, val.value(x...)});
|
||||
}
|
||||
|
||||
auto container = this->parent_->start(this->url_.value(x...), this->method_.value(x...), body, request_headers,
|
||||
this->lower_case_collect_headers_);
|
||||
auto container = this->parent_->start(this->url_.value(x...).c_str(), this->method_.value(x...), body,
|
||||
request_headers, this->lower_case_collect_headers_);
|
||||
|
||||
auto captured_args = std::make_tuple(x...);
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#if defined(USE_ARDUINO) && !defined(USE_ESP32) && !defined(USE_LIBRETINY)
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/components/watchdog/watchdog.h"
|
||||
|
||||
@@ -22,8 +24,7 @@ static const char *const TAG = "http_request";
|
||||
static constexpr int ESP8266_SSL_ERR_OOM = -1000;
|
||||
#endif
|
||||
|
||||
std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &url, const std::string &method,
|
||||
const std::string &body,
|
||||
std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const char *url, const char *method, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
if (!network::is_connected()) {
|
||||
@@ -37,7 +38,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
|
||||
|
||||
const uint32_t start = millis();
|
||||
|
||||
bool secure = url.find("https:") != std::string::npos;
|
||||
bool secure = strstr(url, "https:") != nullptr;
|
||||
container->set_secure(secure);
|
||||
|
||||
watchdog::WatchdogManager wdm(this->get_watchdog_timeout());
|
||||
@@ -70,19 +71,19 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
|
||||
stream_ptr = std::make_unique<WiFiClient>();
|
||||
#endif // USE_HTTP_REQUEST_ESP8266_HTTPS
|
||||
|
||||
bool status = container->client_.begin(*stream_ptr, url.c_str());
|
||||
bool status = container->client_.begin(*stream_ptr, url);
|
||||
|
||||
#elif defined(USE_RP2)
|
||||
if (secure) {
|
||||
container->client_.setInsecure();
|
||||
}
|
||||
bool status = container->client_.begin(url.c_str());
|
||||
bool status = container->client_.begin(url);
|
||||
#endif
|
||||
|
||||
App.feed_wdt();
|
||||
|
||||
if (!status) {
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s", url.c_str());
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s", url);
|
||||
container->end();
|
||||
this->status_momentary_error("failed", 1000);
|
||||
return nullptr;
|
||||
@@ -107,7 +108,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
|
||||
container->client_.collectHeaders(header_keys, index);
|
||||
|
||||
App.feed_wdt();
|
||||
container->status_code = container->client_.sendRequest(method.c_str(), body.c_str());
|
||||
container->status_code = container->client_.sendRequest(method, body.c_str());
|
||||
App.feed_wdt();
|
||||
if (container->status_code < 0) {
|
||||
#if defined(USE_ESP8266) && defined(USE_HTTP_REQUEST_ESP8266_HTTPS)
|
||||
@@ -139,7 +140,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s", url.c_str(),
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s; Error: %s", url,
|
||||
HTTPClient::errorToString(container->status_code).c_str());
|
||||
|
||||
this->status_momentary_error("failed", 1000);
|
||||
@@ -147,7 +148,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
|
||||
return nullptr;
|
||||
}
|
||||
if (!is_success(container->status_code)) {
|
||||
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code);
|
||||
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url, container->status_code);
|
||||
this->status_momentary_error("failed", 1000);
|
||||
// Still return the container, so it can be used to get the status code and error message
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ class HttpRequestArduino final : public HttpRequestComponent {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
|
||||
std::shared_ptr<HttpContainer> perform(const char *url, const char *method, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) override;
|
||||
#ifdef USE_ESP8266
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "httplib.h"
|
||||
#include "http_request_host.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <regex>
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/components/watchdog/watchdog.h"
|
||||
@@ -16,8 +18,7 @@ namespace esphome::http_request {
|
||||
|
||||
static const char *const TAG = "http_request";
|
||||
|
||||
std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url, const std::string &method,
|
||||
const std::string &body,
|
||||
std::shared_ptr<HttpContainer> HttpRequestHost::perform(const char *url, const char *method, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
if (!network::is_connected()) {
|
||||
@@ -27,10 +28,10 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
|
||||
}
|
||||
|
||||
std::regex url_regex(R"(^(([^:\/?#]+):)?(//([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)", std::regex::extended);
|
||||
std::smatch url_match_result;
|
||||
std::cmatch url_match_result;
|
||||
|
||||
if (!std::regex_match(url, url_match_result, url_regex) || url_match_result.length() < 7) {
|
||||
ESP_LOGE(TAG, "HTTP Request failed; Malformed URL: %s", url.c_str());
|
||||
ESP_LOGE(TAG, "HTTP Request failed; Malformed URL: %s", url);
|
||||
return nullptr;
|
||||
}
|
||||
auto host = url_match_result[4].str();
|
||||
@@ -54,7 +55,7 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
|
||||
}
|
||||
httplib::Client client(scheme_host.c_str());
|
||||
if (!client.is_valid()) {
|
||||
ESP_LOGE(TAG, "HTTP Request failed; Invalid URL: %s", url.c_str());
|
||||
ESP_LOGE(TAG, "HTTP Request failed; Invalid URL: %s", url);
|
||||
return nullptr;
|
||||
}
|
||||
client.set_follow_location(this->follow_redirects_);
|
||||
@@ -64,41 +65,41 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
|
||||
#endif
|
||||
|
||||
httplib::Result result;
|
||||
if (method == "GET") {
|
||||
if (strcmp(method, "GET") == 0) {
|
||||
result = client.Get(path, h_headers, [&](const char *data, size_t data_length) {
|
||||
ESP_LOGV(TAG, "Got data length: %zu", data_length);
|
||||
container->response_body_.insert(container->response_body_.end(), (const uint8_t *) data,
|
||||
(const uint8_t *) data + data_length);
|
||||
return true;
|
||||
});
|
||||
} else if (method == "HEAD") {
|
||||
} else if (strcmp(method, "HEAD") == 0) {
|
||||
result = client.Head(path, h_headers);
|
||||
} else if (method == "PUT") {
|
||||
} else if (strcmp(method, "PUT") == 0) {
|
||||
result = client.Put(path, h_headers, body, "");
|
||||
if (result) {
|
||||
auto data = std::vector<uint8_t>(result->body.begin(), result->body.end());
|
||||
container->response_body_.insert(container->response_body_.end(), data.begin(), data.end());
|
||||
}
|
||||
} else if (method == "PATCH") {
|
||||
} else if (strcmp(method, "PATCH") == 0) {
|
||||
result = client.Patch(path, h_headers, body, "");
|
||||
if (result) {
|
||||
auto data = std::vector<uint8_t>(result->body.begin(), result->body.end());
|
||||
container->response_body_.insert(container->response_body_.end(), data.begin(), data.end());
|
||||
}
|
||||
} else if (method == "POST") {
|
||||
} else if (strcmp(method, "POST") == 0) {
|
||||
result = client.Post(path, h_headers, body, "");
|
||||
if (result) {
|
||||
auto data = std::vector<uint8_t>(result->body.begin(), result->body.end());
|
||||
container->response_body_.insert(container->response_body_.end(), data.begin(), data.end());
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "HTTP Request failed - unsupported method %s; URL: %s", method.c_str(), url.c_str());
|
||||
ESP_LOGW(TAG, "HTTP Request failed - unsupported method %s; URL: %s", method, url);
|
||||
container->end();
|
||||
return nullptr;
|
||||
}
|
||||
App.feed_wdt();
|
||||
if (!result) {
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s, error code: %u", url.c_str(), (unsigned) result.error());
|
||||
ESP_LOGW(TAG, "HTTP Request failed; URL: %s, error code: %u", url, (unsigned) result.error());
|
||||
container->end();
|
||||
this->status_momentary_error("failed", 1000);
|
||||
return nullptr;
|
||||
@@ -107,7 +108,7 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
|
||||
auto response = *result;
|
||||
container->status_code = response.status;
|
||||
if (!is_success(response.status)) {
|
||||
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), response.status);
|
||||
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url, response.status);
|
||||
this->status_momentary_error("failed", 1000);
|
||||
// Still return the container, so it can be used to get the status code and error message
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class HttpContainerHost : public HttpContainer {
|
||||
|
||||
class HttpRequestHost final : public HttpRequestComponent {
|
||||
public:
|
||||
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
|
||||
std::shared_ptr<HttpContainer> perform(const char *url, const char *method, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) override;
|
||||
void set_ca_path(const char *ca_path) { this->ca_path_ = ca_path; }
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/components/watchdog/watchdog.h"
|
||||
|
||||
@@ -48,8 +50,7 @@ esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, const std::string &method,
|
||||
const std::string &body,
|
||||
std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const char *url, const char *method, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
if (!network::is_connected()) {
|
||||
@@ -59,15 +60,15 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
|
||||
}
|
||||
|
||||
esp_http_client_method_t method_idf;
|
||||
if (method == "GET") {
|
||||
if (strcmp(method, "GET") == 0) {
|
||||
method_idf = HTTP_METHOD_GET;
|
||||
} else if (method == "POST") {
|
||||
} else if (strcmp(method, "POST") == 0) {
|
||||
method_idf = HTTP_METHOD_POST;
|
||||
} else if (method == "PUT") {
|
||||
} else if (strcmp(method, "PUT") == 0) {
|
||||
method_idf = HTTP_METHOD_PUT;
|
||||
} else if (method == "DELETE") {
|
||||
} else if (strcmp(method, "DELETE") == 0) {
|
||||
method_idf = HTTP_METHOD_DELETE;
|
||||
} else if (method == "PATCH") {
|
||||
} else if (strcmp(method, "PATCH") == 0) {
|
||||
method_idf = HTTP_METHOD_PATCH;
|
||||
} else {
|
||||
this->status_momentary_error("failed", ERROR_DURATION_MS);
|
||||
@@ -75,11 +76,11 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool secure = url.find("https:") != std::string::npos;
|
||||
bool secure = strstr(url, "https:") != nullptr;
|
||||
|
||||
esp_http_client_config_t config = {};
|
||||
|
||||
config.url = url.c_str();
|
||||
config.url = url;
|
||||
config.method = method_idf;
|
||||
config.timeout_ms = this->timeout_;
|
||||
config.disable_auto_redirect = !this->follow_redirects_;
|
||||
@@ -218,7 +219,7 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url.c_str(), container->status_code);
|
||||
ESP_LOGE(TAG, "HTTP Request failed; URL: %s; Code: %d", url, container->status_code);
|
||||
this->status_momentary_error("failed", ERROR_DURATION_MS);
|
||||
return container;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class HttpRequestIDF final : public HttpRequestComponent {
|
||||
void set_ca_certificate(const char *ca_certificate) { this->ca_certificate_ = ca_certificate; }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
|
||||
std::shared_ptr<HttpContainer> perform(const char *url, const char *method, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
const std::vector<std::string> &lower_case_collect_headers) override;
|
||||
// if zero ESP-IDF will use DEFAULT_HTTP_BUF_SIZE
|
||||
|
||||
Reference in New Issue
Block a user