Browse Source

support custom http handler chain headerHandler (#715)

optimize http path safe check Performance and Process
宅の士 8 months ago
parent
commit
03e5eb1565

+ 3 - 2
docs/cn/HttpServer.md

@@ -93,10 +93,11 @@ class HttpService {
     // 返回注册的路由路径列表
     hv::StringList Paths();
 
-    // 处理流程:前处理器 -> 中间件 -> 处理器 -> 后处理器
-    // preprocessor -> middleware -> processor -> postprocessor
+    // 处理流程:标头处理器 -> 前处理器 -> 中间件 -> 处理器 -> 后处理器
+    // headerHandler -> preprocessor -> middleware -> processor -> postprocessor
 
     // 数据成员
+    http_handler    headerHandler;  // 标头处理器
     http_handler    preprocessor;   // 前处理器
     http_handlers   middleware;     // 中间件
     http_handler    processor;      // 处理器

+ 6 - 3
examples/httpd/handler.cpp

@@ -9,10 +9,8 @@
 #include "hstring.h"
 #include "EventLoop.h" // import setTimeout, setInterval
 
-int Handler::preprocessor(HttpRequest* req, HttpResponse* resp) {
+int Handler::headerHandler(HttpRequest* req, HttpResponse* resp) {
     // printf("%s:%d\n", req->client_addr.ip.c_str(), req->client_addr.port);
-    // printf("%s\n", req->Dump(true, true).c_str());
-
 #if REDIRECT_HTTP_TO_HTTPS
     // 301
     if (req->scheme == "http") {
@@ -25,6 +23,11 @@ int Handler::preprocessor(HttpRequest* req, HttpResponse* resp) {
     // if (req->content_type != APPLICATION_JSON) {
     //     return response_status(resp, HTTP_STATUS_BAD_REQUEST);
     // }
+    return HTTP_STATUS_NEXT;
+}
+
+int Handler::preprocessor(HttpRequest* req, HttpResponse* resp) {
+    // printf("%s\n", req->Dump(true, true).c_str());
 
     // Deserialize request body to json, form, etc.
     req->ParseBody();

+ 2 - 1
examples/httpd/handler.h

@@ -5,7 +5,8 @@
 
 class Handler {
 public:
-    // preprocessor => middleware -> handlers => postprocessor
+    // headerHandler => preprocessor => middleware -> handlers => postprocessor
+    static int headerHandler(HttpRequest* req, HttpResponse* resp);
     static int preprocessor(HttpRequest* req, HttpResponse* resp);
     static int postprocessor(HttpRequest* req, HttpResponse* resp);
     static int errorHandler(const HttpContextPtr& ctx);

+ 2 - 1
examples/httpd/router.cpp

@@ -7,8 +7,9 @@
 
 void Router::Register(hv::HttpService& router) {
     /* handler chain */
-    // preprocessor -> middleware -> processor -> postprocessor
+    // headerHandler -> preprocessor -> middleware -> processor -> postprocessor
     // processor: pathHandlers -> staticHandler -> errorHandler
+    router.headerHandler = Handler::headerHandler;
     router.preprocessor = Handler::preprocessor;
     router.postprocessor = Handler::postprocessor;
     // router.errorHandler = Handler::errorHandler;

+ 27 - 16
http/server/HttpHandler.cpp

@@ -251,13 +251,35 @@ int HttpHandler::invokeHttpHandler(const http_handler* handler) {
 
 void HttpHandler::onHeadersComplete() {
     // printf("onHeadersComplete\n");
-    int status_code = handleRequestHeaders();
-    if (status_code != HTTP_STATUS_OK) {
-        error = ERR_REQUEST;
-        return;
+    handleRequestHeaders();
+    if (service->headerHandler) {
+        const int status_code = customHttpHandler(service->headerHandler);
+        if (status_code != HTTP_STATUS_OK && status_code != HTTP_STATUS_NEXT) {
+            SetError(ERR_REQUEST, static_cast<http_status>(status_code));
+            return;
+        }
     }
 
     HttpRequest* pReq = req.get();
+    const char *p = pReq->path.c_str();
+    while (*p != '\0') {
+        switch (*p) {
+            case '%':
+                if (p[1] != '0') break;
+                if (p[2] != 'd' && p[2] != 'D' && p[2] != 'a' && p[2] != 'A') break;
+            case '\r':
+            case '\n':
+                // fix CVE-2023-26147
+                hloge("[%s:%d] Illegal crlf path: %s", ip, port, pReq->path.c_str());
+                SetError(ERR_REQUEST);
+                return;
+
+            default:
+                break;
+        }
+        ++p;
+    }
+
     if (service && service->pathHandlers.size() != 0) {
         service->GetRoute(pReq, &api_handler);
     }
@@ -339,7 +361,7 @@ void HttpHandler::onMessageComplete() {
     }
 }
 
-int HttpHandler::handleRequestHeaders() {
+void HttpHandler::handleRequestHeaders() {
     HttpRequest* pReq = req.get();
     pReq->scheme = ssl ? "https" : "http";
     pReq->client_addr.ip = ip;
@@ -367,16 +389,6 @@ int HttpHandler::handleRequestHeaders() {
 
     // printf("url=%s\n", pReq->url.c_str());
     pReq->ParseUrl();
-    // printf("path=%s\n",  pReq->path.c_str());
-    // fix CVE-2023-26147
-    if (pReq->path.find("%") != std::string::npos) {
-        std::string unescaped_path = HUrl::unescape(pReq->path);
-        if (unescaped_path.find("\r\n") != std::string::npos) {
-            hlogw("Illegal path: %s\n",  unescaped_path.c_str());
-            resp->status_code = HTTP_STATUS_BAD_REQUEST;
-            return resp->status_code;
-        }
-    }
 
     if (proxy) {
         // Proxy-Connection
@@ -404,7 +416,6 @@ int HttpHandler::handleRequestHeaders() {
     }
 
     // TODO: rewrite url
-    return HTTP_STATUS_OK;
 }
 
 void HttpHandler::handleExpect100() {

+ 1 - 1
http/server/HttpHandler.h

@@ -143,7 +143,7 @@ public:
 
 private:
     const HttpContextPtr& context();
-    int   handleRequestHeaders();
+    void  handleRequestHeaders();
     // Expect: 100-continue
     void  handleExpect100();
     void  addResponseHeaders();

+ 2 - 1
http/server/HttpService.h

@@ -108,7 +108,8 @@ namespace hv {
 
 struct HV_EXPORT HttpService {
     /* handler chain */
-    // preprocessor -> middleware -> processor -> postprocessor
+    // headerHandler -> preprocessor -> middleware -> processor -> postprocessor
+    http_handler        headerHandler;
     http_handler        preprocessor;
     http_handlers       middleware;
     // processor: pathHandlers -> staticHandler -> errorHandler