Pārlūkot izejas kodu

implement parsing query string in http::Request

Bence Balint 3 gadi atpakaļ
vecāks
revīzija
f6e4f0aaa0
4 mainītis faili ar 79 papildinājumiem un 24 dzēšanām
  1. 0 1
      include/kbf.h
  2. 32 10
      include/kbf_http_server.h
  3. 2 0
      src/kbf.cpp
  4. 45 13
      src/kbf_http_server.cpp

+ 0 - 1
include/kbf.h

@@ -5,7 +5,6 @@
 
 namespace kbf {
     typedef const char *const Tag;
-    static Tag TAG = "kbf";
 
     void sleep(uint32_t milliseconds);
 }

+ 32 - 10
include/kbf_http_server.h

@@ -10,16 +10,45 @@ using std::vector;
 using std::string;
 
 namespace kbf::http {
+    /**
+     * Supported HTTP methods.
+     * Mostly used for syntax consistency; values match that of httpd_method_t.
+     */
+    enum Method {
+        GET = 1,
+        POST = 3
+    };
+
     struct Header {
         string name;
         string value;
     };
 
-    struct Request {
-        int method; // TODO enumerate
+    struct QueryArg {
+        string name;
+        string value;
+    };
+
+    class Request {
+    public:
+        explicit Request(httpd_req_t *httpdRequest);
+
+        static inline const vector<string> acceptedHeaders = {
+                "Host",
+                "User-Agent",
+        };
+
+        Method method;
         string uri;
+        vector<QueryArg> query;
         vector<Header> headers;
         string body;
+    private:
+        httpd_req_t *httpdRequest;
+
+        void readHeader(const string &header);
+
+        void readQuery();
     };
 
     struct Response {
@@ -31,13 +60,8 @@ namespace kbf::http {
 
     class Server {
     public:
-        static inline const vector<string> acceptedHeaders = {
-                "Host",
-                "User-Agent",
-        };
-
         struct Route {
-            httpd_method_t method;
+            Method method;
             const string &uri;
 
             Response (*handler)(const Request &request);
@@ -57,8 +81,6 @@ namespace kbf::http {
         vector<Route> routes;
 
         static esp_err_t handleHttpRequest(httpd_req_t *httpdRequest);
-
-        static string readHeader(httpd_req_t *httpdRequest, const string &header);
     };
 }
 

+ 2 - 0
src/kbf.cpp

@@ -3,6 +3,8 @@
 #include <freertos/FreeRTOS.h>
 #include <freertos/task.h>
 
+static kbf::Tag TAG = "kbf";
+
 void kbf::sleep(uint32_t milliseconds) {
     vTaskDelay(milliseconds / portTICK_PERIOD_MS);
 }

+ 45 - 13
src/kbf_http_server.cpp

@@ -1,5 +1,7 @@
 #include "kbf_http_server.h"
 
+#include <regex>
+
 #include <esp_log.h>
 
 #include "kbf_assert.h"
@@ -25,10 +27,10 @@ void kbf::http::Server::start(int port) {
 
     ESP_LOGI(TAG, "registering URI handlers");
     for (auto &route : routes) {
-        ESP_LOGI(TAG, "  method: %d; uri: %s", route.method, route.uri.c_str());
+        ESP_LOGI(TAG, "  method: %d; uri: %s", static_cast<int>(route.method), route.uri.c_str());
         httpd_uri_t uriHandler = {
                 .uri = route.uri.c_str(),
-                .method = route.method,
+                .method = static_cast<httpd_method_t>(route.method),
                 .handler = handleHttpRequest,
                 .user_ctx = &route
         };
@@ -42,30 +44,60 @@ void kbf::http::Server::stop() {
 
 esp_err_t kbf::http::Server::handleHttpRequest(httpd_req_t *httpdRequest) {
     auto route = static_cast<Route *>(httpdRequest->user_ctx);
-    ESP_LOGI(TAG, "incoming request: method %d, uri %s", httpdRequest->method, route->uri.c_str());
-
-    auto request = Request();
-    request.method = httpdRequest->method;
-    request.uri = httpdRequest->uri;
-    for (const auto &name : acceptedHeaders) {
-        request.headers.push_back({name, readHeader(httpdRequest, name)});
-    }
+    ESP_LOGI(TAG, "incoming request: method %d, path %s", httpdRequest->method, route->uri.c_str());
 
+    auto request = Request(httpdRequest);
     auto response = route->handler(request);
+
     httpd_resp_set_hdr(httpdRequest, "Server", "kbf_http_server/0.1");
     httpd_resp_send(httpdRequest, response.body.c_str(), response.body.length());
 
     return ESP_OK;
 }
 
-string kbf::http::Server::readHeader(httpd_req_t *httpdRequest, const string &header) {
+kbf::http::Request::Request(httpd_req_t *httpdRequest) {
+    this->httpdRequest = httpdRequest;
+    method = static_cast<Method>(httpdRequest->method);
+    uri = httpdRequest->uri;
+
+    for (const auto &name : acceptedHeaders) {
+        readHeader(name);
+    }
+    readQuery();
+}
+
+void kbf::http::Request::readHeader(const string &header) {
     auto len = httpd_req_get_hdr_value_len(httpdRequest, header.c_str());
     if (len == 0) {
         ESP_LOGI(TAG, "  header not found: %s", header.c_str());
-        return "";
+        return;
     }
     char buffer[len + 1];
     CHECK(httpd_req_get_hdr_value_str(httpdRequest, header.c_str(), buffer, len + 1));
     ESP_LOGI(TAG, "  found header: %s", header.c_str());
-    return buffer;
+    headers.push_back({header, buffer});
+}
+
+void kbf::http::Request::readQuery() {
+    auto queryLen = httpd_req_get_url_query_len(httpdRequest);
+    char buffer[queryLen + 1];
+
+    auto err = httpd_req_get_url_query_str(httpdRequest, buffer, queryLen + 1);
+    if (err == ESP_ERR_NOT_FOUND) {
+        ESP_LOGI(TAG, "no query found");
+        return;
+    } else
+        CHECK(err);
+
+    ESP_LOGI(TAG, "found query:       %s", buffer);
+    auto queryString = string(buffer, queryLen);
+
+    std::regex regex("([\\w]+)=([\\w]+)");
+    std::smatch submatch;
+    while (std::regex_search(queryString, submatch, regex)) {
+        QueryArg arg = {submatch[1], submatch[2]};
+        ESP_LOGI(TAG, "  query arg: %s = %s", arg.name.c_str(), arg.value.c_str());
+        query.push_back(arg);
+        queryString = submatch.suffix();
+    }
 }