From ea2492090a2017d0b235dc1aa9aaa3fc3185941e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=85=E3=81=AE=E5=A3=AB?= Date: Wed, 16 Apr 2025 04:07:26 +0800 Subject: [PATCH] Improve some defects related to http service request path add hv_normalize_path function to hbase.h support http legal relative path request optimize http server path file cache map key fix false positives '/..file' normal path bug --- base/hbase.c | 56 +++++++++++++++++++++++++++++++++++++ base/hbase.h | 2 ++ http/server/HttpHandler.cpp | 9 +++--- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/base/hbase.c b/base/hbase.c index 583161271..0ab750f64 100644 --- a/base/hbase.c +++ b/base/hbase.c @@ -540,3 +540,59 @@ int hv_parse_url(hurl_t* stURL, const char* strURL) { stURL->fields[HV_URL_FRAGMENT].len = ep - sp; return 0; } + +int hv_normalize_path(char *path) { + if (*path != '/') return 0; + int pos = 1; +#ifdef OS_WIN + int sum = 0; +#endif + for (int i = 1; path[i] != '\0'; ++i) { + switch (path[i]) { + case '\\': + case '/': + if (path[pos - 1] != '/') path[pos++] = '/'; + break; + + case '.': + if (path[pos - 1] == '/') { + if (path[i + 1] == '.' && (path[i + 2] == '/' || path[i + 2] == '\\' || path[i + 2] == '\0')) { + while (--pos > 0) { + if (path[pos - 1] == '/') break; + } + if (pos < 1) return 0; + i += path[i + 2] == '\0' ? 1 : 2; + break; + } + if (path[i + 1] == '\0') break; + if (path[i + 1] == '/' || path[i + 1] == '\\') { + ++i; + break; + } + } + path[pos++] = '.'; +#ifdef OS_WIN + // windows does not have a trailing '.' + sum = 1; + while (path[i + sum] == '.') { + path[pos++] = '.'; + ++sum; + } + if (path[i + sum] == '\0') pos -= sum; + i += sum - 1; +#endif + break; + + default: +#ifdef OS_WIN + // windows is not case sensitive + path[pos++] = (char)tolower(path[i]); +#else + path[pos++] = path[i]; +#endif + break; + } + } + path[pos] = '\0'; + return pos; +} diff --git a/base/hbase.h b/base/hbase.h index c1ff0f46f..127e4969c 100644 --- a/base/hbase.h +++ b/base/hbase.h @@ -140,6 +140,8 @@ typedef struct hurl_s { HV_EXPORT int hv_parse_url(hurl_t* stURL, const char* strURL); +HV_EXPORT int hv_normalize_path(char *path); + END_EXTERN_C #endif // HV_BASE_H_ diff --git a/http/server/HttpHandler.cpp b/http/server/HttpHandler.cpp index 54a05c71a..993f924fc 100644 --- a/http/server/HttpHandler.cpp +++ b/http/server/HttpHandler.cpp @@ -524,14 +524,15 @@ int HttpHandler::defaultRequestHandler() { int HttpHandler::defaultStaticHandler() { // file service std::string path = req->Path(); - const char* req_path = path.c_str(); - // path safe check - if (req_path[0] != '/' || strstr(req_path, "/..") || strstr(req_path, "\\..")) { + path.resize(hv_normalize_path(const_cast(path.c_str()))); + if (path.empty()) { + hloge("[%s:%d] Illegal relative path: %s", ip, port, req->path.c_str()); return HTTP_STATUS_BAD_REQUEST; } + const char* req_path = path.c_str(); std::string filepath; - bool is_dir = path.back() == '/' && + const bool is_dir = path.back() == '/' && service->index_of.size() > 0 && hv_strstartswith(req_path, service->index_of.c_str()); if (is_dir) {