Quellcode durchsuchen

Merge branch 'kbf-2' of kraxor/kbf into develop

Bence Balint vor 3 Jahren
Ursprung
Commit
a7e1e0f2fb
4 geänderte Dateien mit 48 neuen und 9 gelöschten Zeilen
  1. 9 3
      include/kbf/http/client.h
  2. 6 5
      src/http/client.cpp
  3. 6 1
      src/http/server.cpp
  4. 27 0
      test/test_http.cpp

+ 9 - 3
include/kbf/http/client.h

@@ -26,9 +26,10 @@ namespace kbf::http {
          *
          * @warning Async mode is only supported by IDF for HTTPS.
          *
+         * @param timeoutMs request timeout in milliseconds; 0 means no timeout; default is 0
          * @param async perform request asynchronously; default is false
          */
-        explicit Client(bool async = false);
+        explicit Client(int timeoutMs = 0, bool async = false);
 
         /**
          * @brief Destructor.
@@ -85,11 +86,17 @@ namespace kbf::http {
          */
         [[nodiscard]] bool isRunning() const { return running; }
 
+        /** @brief Request timeout in milliseconds. */
+        const int timeoutMs;
+
+        /** @brief Async mode */
+        const bool async;
+
     private:
         void init();
 
         std::shared_ptr<kbf::http::Response>
-        performRequest(const kbf::http::Method method, const std::string &url, const nlohmann::json *postData);
+        performRequest(kbf::http::Method method, const std::string &url, const nlohmann::json *postData);
 
         static void updateResponse(Client &client);
 
@@ -105,7 +112,6 @@ namespace kbf::http {
         std::shared_ptr<Response> response;
         bool                      running = false;
         bool                      retry   = false;
-        bool                      async;
     };
 
 }

+ 6 - 5
src/http/client.cpp

@@ -10,7 +10,7 @@ using std::make_shared;
 using std::string;
 using std::shared_ptr;
 
-http::Client::Client(bool async) : buffer(), async(async) {
+http::Client::Client(int timeoutMs, bool async) : timeoutMs(timeoutMs), async(async), buffer() {
     ESP_LOGD(TAG, "Client()");
     init();
 }
@@ -24,11 +24,11 @@ void http::Client::init() {
     config.path                  = "/";
     config.disable_auto_redirect = false; // do not set to true, IDF bug :(
     config.max_redirection_count = 0;
+    config.timeout_ms            = timeoutMs;
     config.is_async              = async;
     handle = esp_http_client_init(&config);
 }
 
-
 http::Client::~Client() {
     ESP_LOGD(TAG, "~Client()");
     CHECK(esp_http_client_cleanup(handle));
@@ -78,14 +78,16 @@ http::Client::performRequest(const kbf::http::Method method, const std::string &
         ESP_LOGD(TAG, "success");
         return response;
     } else if (err == ESP_ERR_HTTP_FETCH_HEADER && !retry) {
-        ESP_LOGD(TAG, "fetching headers failed, maybe the connection was dropped? retrying...");
+        // TODO this will happen on timeout as well; perhaps set a retry limit in ctor / get / post?
+        ESP_LOGW(TAG, "fetching headers failed, maybe the connection was dropped? retrying...");
         retry = true;
         esp_http_client_cleanup(handle);
         init();
         return get(url);
     } else {
         ESP_LOGE(TAG, "HTTP GET failed: %s", esp_err_to_name(err));
-        ABORT("debug me");
+        if (onError) onError(*this);
+        return nullptr;
     }
 }
 
@@ -124,7 +126,6 @@ esp_err_t http::Client::handleHttpEvent(esp_http_client_event_t *event) {
         case HTTP_EVENT_DISCONNECTED:
             ESP_LOGW(TAG, "disconnected");
             client->running = false;
-            client->retry   = false;
             break;
     }
 

+ 6 - 1
src/http/server.cpp

@@ -79,7 +79,12 @@ esp_err_t http::Server::handleHttpRequest(httpd_req_t *httpdRequest) {
 
     ESP_LOG_BUFFER_HEXDUMP(TAG, response.body.c_str(), response.body.size(), ESP_LOG_VERBOSE);
 
-    CHECK(httpd_resp_send(httpdRequest, response.body.c_str(), response.body.length()));
+    auto err = httpd_resp_send(httpdRequest, response.body.c_str(), response.body.length());
+    if (err == ESP_ERR_HTTPD_RESP_SEND) {
+        ESP_LOGW(TAG, "send failed; maybe client disconnected?");
+        return ESP_ERR_HTTPD_RESP_SEND;
+    }
+    CHECK(err);
     return ESP_OK;
 }
 

+ 27 - 0
test/test_http.cpp

@@ -14,6 +14,7 @@ using namespace std;
 using nlohmann::json;
 
 std::atomic<bool> asyncFinished = {false};
+std::atomic<int> state;
 
 TEST_CASE("HTTP GET, POST, 404, 405", "[kbf_http]") {
     wifi::start();
@@ -182,6 +183,32 @@ TEST_CASE("HTTP JSON request / response", "[kbf_http]") {
     wifi::stop();
 }
 
+TEST_CASE("HTTP timeout", "[kbf_http]") {
+    wifi::start();
+
+    auto server = http::Server();
+    http::Response (*handler)(const http::Request &, void *) = {[](const http::Request &request, void *) {
+        kbf::sleep(stoi(request.query.at("sleep")));
+        return http::Response("OK");
+    }};
+
+    server.route({http::GET, "/", handler, nullptr});
+    server.start();
+
+    state = 0;
+    auto client = http::Client(1000);
+    client.onError = {[](http::Client &) {
+        TEST_ASSERT_EQUAL(0, state++);
+    }};
+
+    TEST_ASSERT_EQUAL_STRING("OK", client.get("http://localhost/?sleep=200")->body.c_str());
+    TEST_ASSERT_EQUAL(0, state);
+    TEST_ASSERT_NULL(client.get("http://localhost/?sleep=1200"))
+    TEST_ASSERT_EQUAL(1, state);
+
+    wifi::stop();
+}
+
 TEST_CASE("HTTP CORS", "[notimplemented]") {
     TEST_FAIL_MESSAGE("not yet implemented");
 }