diff --git a/esphome/components/http_request/__init__.py b/esphome/components/http_request/__init__.py index 78064fb4b4..fcf341825d 100644 --- a/esphome/components/http_request/__init__.py +++ b/esphome/components/http_request/__init__.py @@ -276,7 +276,7 @@ async def http_request_action_to_code(config, action_id, template_arg, args): trigger, [ (cg.std_shared_ptr.template(HttpContainer), "response"), - (cg.std_string_ref, "body"), + (cg.std_shared_ptr.template(cg.std_string), "body"), ], conf, ) diff --git a/esphome/components/http_request/http_request.h b/esphome/components/http_request/http_request.h index b2ce718ec4..4e1ad59f90 100644 --- a/esphome/components/http_request/http_request.h +++ b/esphome/components/http_request/http_request.h @@ -100,10 +100,10 @@ class HttpContainer : public Parented { bool secure_{false}; }; -class HttpRequestResponseTrigger : public Trigger, std::string &> { +class HttpRequestResponseTrigger : public Trigger, std::shared_ptr> { public: - void process(std::shared_ptr container, std::string &response_body) { - this->trigger(std::move(container), response_body); + void process(std::shared_ptr container, std::shared_ptr response_body) { + this->trigger(std::move(container), std::move(response_body)); } }; @@ -196,7 +196,7 @@ template class HttpRequestSendAction : public Action { size_t content_length = container->content_length; size_t max_length = std::min(content_length, this->max_response_buffer_size_); - std::string response_body; + std::shared_ptr response_body; if (this->capture_response_.value(x...)) { ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); uint8_t *buf = allocator.allocate(max_length); @@ -208,23 +208,23 @@ template class HttpRequestSendAction : public Action { yield(); read_index += read; } - response_body.reserve(read_index); - response_body.assign((char *) buf, read_index); + response_body = std::make_shared((char *) buf, read_index); allocator.deallocate(buf, max_length); } } - if (this->response_triggers_.size() == 1) { - // if there is only one trigger, no need to copy the response body - this->response_triggers_[0]->process(container, response_body); - } else { - for (auto *trigger : this->response_triggers_) { - // with multiple triggers, pass a copy of the response body to each - // one so that modifications made in one trigger are not visible to - // the others - auto response_body_copy = std::string(response_body); - trigger->process(container, response_body_copy); + size_t index = 0u; + auto num_triggers = this->response_triggers_.size(); + for (auto *trigger : this->response_triggers_) { + // pass a copy of the response body to each trigger so that modifications + // made in one trigger are not visible to the others. Re-use the original + // response body for the last trigger. + std::shared_ptr response_body_copy{response_body}; + if (response_body && index != num_triggers - 1) { + response_body_copy = std::make_shared(*response_body); } + trigger->process(container, response_body_copy); + index++; } container->end(); } diff --git a/tests/components/http_request/common.yaml b/tests/components/http_request/common.yaml index 8408f27a05..980d16a45d 100644 --- a/tests/components/http_request/common.yaml +++ b/tests/components/http_request/common.yaml @@ -21,6 +21,24 @@ esphome: args: - response->status_code - (long) response->duration_ms + + # regression test for http://github.com/esphome/issues/issues/5987s + - wait_until: + not: + wifi.connected: + + - repeat: + count: 3 + then: + - logger.log: "got response :-)" + + - while: + condition: + not: + wifi.connected: + then: + - logger.log: "still offline" + - http_request.post: url: https://esphome.io headers: