Skip to content

Commit c53d5a0

Browse files
committed
support custom http handler chain headerHandler
optimize http path safe check Performance and Process
1 parent 1e3dd55 commit c53d5a0

7 files changed

Lines changed: 43 additions & 25 deletions

File tree

docs/cn/HttpServer.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ class HttpService {
9393
// 返回注册的路由路径列表
9494
hv::StringList Paths();
9595

96-
// 处理流程:前处理器 -> 中间件 -> 处理器 -> 后处理器
97-
// preprocessor -> middleware -> processor -> postprocessor
96+
// 处理流程:标头处理器 -> 前处理器 -> 中间件 -> 处理器 -> 后处理器
97+
// headerHandler -> preprocessor -> middleware -> processor -> postprocessor
9898

9999
// 数据成员
100+
http_handler headerHandler; // 标头处理器
100101
http_handler preprocessor; // 前处理器
101102
http_handlers middleware; // 中间件
102103
http_handler processor; // 处理器

examples/httpd/handler.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@
99
#include "hstring.h"
1010
#include "EventLoop.h" // import setTimeout, setInterval
1111

12-
int Handler::preprocessor(HttpRequest* req, HttpResponse* resp) {
12+
int Handler::headerHandler(HttpRequest* req, HttpResponse* resp) {
1313
// printf("%s:%d\n", req->client_addr.ip.c_str(), req->client_addr.port);
14-
// printf("%s\n", req->Dump(true, true).c_str());
15-
1614
#if REDIRECT_HTTP_TO_HTTPS
1715
// 301
1816
if (req->scheme == "http") {
@@ -25,6 +23,11 @@ int Handler::preprocessor(HttpRequest* req, HttpResponse* resp) {
2523
// if (req->content_type != APPLICATION_JSON) {
2624
// return response_status(resp, HTTP_STATUS_BAD_REQUEST);
2725
// }
26+
return HTTP_STATUS_NEXT;
27+
}
28+
29+
int Handler::preprocessor(HttpRequest* req, HttpResponse* resp) {
30+
// printf("%s\n", req->Dump(true, true).c_str());
2831

2932
// Deserialize request body to json, form, etc.
3033
req->ParseBody();

examples/httpd/handler.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
class Handler {
77
public:
8-
// preprocessor => middleware -> handlers => postprocessor
8+
// headerHandler => preprocessor => middleware -> handlers => postprocessor
9+
static int headerHandler(HttpRequest* req, HttpResponse* resp);
910
static int preprocessor(HttpRequest* req, HttpResponse* resp);
1011
static int postprocessor(HttpRequest* req, HttpResponse* resp);
1112
static int errorHandler(const HttpContextPtr& ctx);

examples/httpd/router.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77

88
void Router::Register(hv::HttpService& router) {
99
/* handler chain */
10-
// preprocessor -> middleware -> processor -> postprocessor
10+
// headerHandler -> preprocessor -> middleware -> processor -> postprocessor
1111
// processor: pathHandlers -> staticHandler -> errorHandler
12+
router.headerHandler = Handler::headerHandler;
1213
router.preprocessor = Handler::preprocessor;
1314
router.postprocessor = Handler::postprocessor;
1415
// router.errorHandler = Handler::errorHandler;

http/server/HttpHandler.cpp

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -251,13 +251,35 @@ int HttpHandler::invokeHttpHandler(const http_handler* handler) {
251251

252252
void HttpHandler::onHeadersComplete() {
253253
// printf("onHeadersComplete\n");
254-
int status_code = handleRequestHeaders();
255-
if (status_code != HTTP_STATUS_OK) {
256-
error = ERR_REQUEST;
257-
return;
254+
handleRequestHeaders();
255+
if (service->headerHandler) {
256+
const int status_code = customHttpHandler(service->headerHandler);
257+
if (status_code != HTTP_STATUS_OK && status_code != HTTP_STATUS_NEXT) {
258+
SetError(ERR_REQUEST, static_cast<http_status>(status_code));
259+
return;
260+
}
258261
}
259262

260263
HttpRequest* pReq = req.get();
264+
const char *p = pReq->path.c_str();
265+
while (*p != '\0') {
266+
switch (*p) {
267+
case '%':
268+
if (p[1] != '0') break;
269+
if (p[2] != 'd' && p[2] != 'D' && p[2] != 'a' && p[2] != 'A') break;
270+
case '\r':
271+
case '\n':
272+
// fix CVE-2023-26147
273+
hloge("[%s:%d] Illegal crlf path: %s", ip, port, pReq->path.c_str());
274+
SetError(ERR_REQUEST);
275+
return;
276+
277+
default:
278+
break;
279+
}
280+
++p;
281+
}
282+
261283
if (service && service->pathHandlers.size() != 0) {
262284
service->GetRoute(pReq, &api_handler);
263285
}
@@ -339,7 +361,7 @@ void HttpHandler::onMessageComplete() {
339361
}
340362
}
341363

342-
int HttpHandler::handleRequestHeaders() {
364+
void HttpHandler::handleRequestHeaders() {
343365
HttpRequest* pReq = req.get();
344366
pReq->scheme = ssl ? "https" : "http";
345367
pReq->client_addr.ip = ip;
@@ -367,16 +389,6 @@ int HttpHandler::handleRequestHeaders() {
367389

368390
// printf("url=%s\n", pReq->url.c_str());
369391
pReq->ParseUrl();
370-
// printf("path=%s\n", pReq->path.c_str());
371-
// fix CVE-2023-26147
372-
if (pReq->path.find("%") != std::string::npos) {
373-
std::string unescaped_path = HUrl::unescape(pReq->path);
374-
if (unescaped_path.find("\r\n") != std::string::npos) {
375-
hlogw("Illegal path: %s\n", unescaped_path.c_str());
376-
resp->status_code = HTTP_STATUS_BAD_REQUEST;
377-
return resp->status_code;
378-
}
379-
}
380392

381393
if (proxy) {
382394
// Proxy-Connection
@@ -404,7 +416,6 @@ int HttpHandler::handleRequestHeaders() {
404416
}
405417

406418
// TODO: rewrite url
407-
return HTTP_STATUS_OK;
408419
}
409420

410421
void HttpHandler::handleExpect100() {

http/server/HttpHandler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ class HttpHandler {
143143

144144
private:
145145
const HttpContextPtr& context();
146-
int handleRequestHeaders();
146+
void handleRequestHeaders();
147147
// Expect: 100-continue
148148
void handleExpect100();
149149
void addResponseHeaders();

http/server/HttpService.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ namespace hv {
108108

109109
struct HV_EXPORT HttpService {
110110
/* handler chain */
111-
// preprocessor -> middleware -> processor -> postprocessor
111+
// headerHandler -> preprocessor -> middleware -> processor -> postprocessor
112+
http_handler headerHandler;
112113
http_handler preprocessor;
113114
http_handlers middleware;
114115
// processor: pathHandlers -> staticHandler -> errorHandler

0 commit comments

Comments
 (0)