Loading src/http/HttpProxyServer.cpp +15 −2 Changes for src/http/HttpProxyServer.cpp: 15 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -103,6 +103,19 @@ netplus::TlsTrustPolicy trustPolicyFor(const store::HttpRouteRecord &route) { } // namespace std::string detail::buildForwardTarget(const std::string &routePath, const std::string &originalTarget, const std::string &pathPrefix) { std::string target = routePath.substr(pathPrefix.size()); if (target.empty() || target[0] != '/') target = "/" + target; // HttpRequest::getRequestURL() intentionally strips the query string for route matching. // Recover it from getRequest(), which retains the complete request target for H1/H2/H3. const size_t query = originalTarget.find('?'); if (query != std::string::npos) target.append(originalTarget.substr(query)); return target; } HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSockets, std::string listenerLabel, bool tlsActive, Loading Loading @@ -371,8 +384,8 @@ void HttpProxyController::RequestEvent(libhttppp::HttpRequest &curreq, const int // The route matches on pathPrefix (e.g. "/bolli"), but the backend is mounted // at "/" and knows nothing about that prefix -- forward the remainder only. std::string forwardPath = url.substr(matched.pathPrefix.size()); if (forwardPath.empty() || forwardPath[0] != '/') forwardPath = "/" + forwardPath; std::string forwardPath = detail::buildForwardTarget( url, curreq.getRequest(), matched.pathPrefix); bool upstreamOk = false; try { Loading src/http/HttpProxyServer.h +11 −0 Changes for src/http/HttpProxyServer.h: 11 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -17,6 +17,17 @@ namespace proxyplus::httpproxy { namespace detail { // Builds the origin-form request target sent upstream. routePath is deliberately the // query-free value used for route matching, while originalTarget supplies the query string // that must survive proxying (notably Git smart HTTP's ?service=git-upload-pack discovery). std::string buildForwardTarget(const std::string &routePath, const std::string &originalTarget, const std::string &pathPrefix); } // namespace detail // The per-connection request handler. There is no reverse-proxy class in libhttppp (see // docs/ARCHITECTURE.md §4) -- this combines HttpEvent::RequestEvent (inbound) with // HttpClient (outbound) itself. Loading test/CMakeLists.txt +4 −0 Changes for test/CMakeLists.txt: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -19,3 +19,7 @@ add_test(NAME test_jose COMMAND test_jose) add_executable(test_loadbalancer test_loadbalancer.cpp) target_link_libraries(test_loadbalancer PRIVATE proxyplus_core) add_test(NAME test_loadbalancer COMMAND test_loadbalancer) add_executable(test_http_proxy_paths test_http_proxy_paths.cpp) target_link_libraries(test_http_proxy_paths PRIVATE proxyplus_core) add_test(NAME test_http_proxy_paths COMMAND test_http_proxy_paths) test/test_http_proxy_paths.cpp 0 → 100644 +30 −0 Changes for test/test_http_proxy_paths.cpp: 30 added lines, 0 removed lines. Original line number Diff line number Diff line #include <cassert> #include <iostream> #include "../src/http/HttpProxyServer.h" using proxyplus::httpproxy::detail::buildForwardTarget; int main() { assert(buildForwardTarget("/git/tuxist/authdb.git/info/refs", "/git/tuxist/authdb.git/info/refs?service=git-upload-pack", "/git") == "/tuxist/authdb.git/info/refs?service=git-upload-pack"); assert(buildForwardTarget("/git/tuxist/authdb.git/git-upload-pack", "/git/tuxist/authdb.git/git-upload-pack", "/git") == "/tuxist/authdb.git/git-upload-pack"); assert(buildForwardTarget("/git", "/git?service=git-upload-pack", "/git") == "/?service=git-upload-pack"); // Absolute-form request targets are legal in HTTP/1.1 and still carry the same query. assert(buildForwardTarget("/git/project/info/refs", "https://git.tuxist.de/git/project/info/refs?service=git-upload-pack", "/git") == "/project/info/refs?service=git-upload-pack"); std::cout << "test_http_proxy_paths: OK" << std::endl; return 0; } Loading
src/http/HttpProxyServer.cpp +15 −2 Changes for src/http/HttpProxyServer.cpp: 15 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -103,6 +103,19 @@ netplus::TlsTrustPolicy trustPolicyFor(const store::HttpRouteRecord &route) { } // namespace std::string detail::buildForwardTarget(const std::string &routePath, const std::string &originalTarget, const std::string &pathPrefix) { std::string target = routePath.substr(pathPrefix.size()); if (target.empty() || target[0] != '/') target = "/" + target; // HttpRequest::getRequestURL() intentionally strips the query string for route matching. // Recover it from getRequest(), which retains the complete request target for H1/H2/H3. const size_t query = originalTarget.find('?'); if (query != std::string::npos) target.append(originalTarget.substr(query)); return target; } HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSockets, std::string listenerLabel, bool tlsActive, Loading Loading @@ -371,8 +384,8 @@ void HttpProxyController::RequestEvent(libhttppp::HttpRequest &curreq, const int // The route matches on pathPrefix (e.g. "/bolli"), but the backend is mounted // at "/" and knows nothing about that prefix -- forward the remainder only. std::string forwardPath = url.substr(matched.pathPrefix.size()); if (forwardPath.empty() || forwardPath[0] != '/') forwardPath = "/" + forwardPath; std::string forwardPath = detail::buildForwardTarget( url, curreq.getRequest(), matched.pathPrefix); bool upstreamOk = false; try { Loading
src/http/HttpProxyServer.h +11 −0 Changes for src/http/HttpProxyServer.h: 11 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -17,6 +17,17 @@ namespace proxyplus::httpproxy { namespace detail { // Builds the origin-form request target sent upstream. routePath is deliberately the // query-free value used for route matching, while originalTarget supplies the query string // that must survive proxying (notably Git smart HTTP's ?service=git-upload-pack discovery). std::string buildForwardTarget(const std::string &routePath, const std::string &originalTarget, const std::string &pathPrefix); } // namespace detail // The per-connection request handler. There is no reverse-proxy class in libhttppp (see // docs/ARCHITECTURE.md §4) -- this combines HttpEvent::RequestEvent (inbound) with // HttpClient (outbound) itself. Loading
test/CMakeLists.txt +4 −0 Changes for test/CMakeLists.txt: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -19,3 +19,7 @@ add_test(NAME test_jose COMMAND test_jose) add_executable(test_loadbalancer test_loadbalancer.cpp) target_link_libraries(test_loadbalancer PRIVATE proxyplus_core) add_test(NAME test_loadbalancer COMMAND test_loadbalancer) add_executable(test_http_proxy_paths test_http_proxy_paths.cpp) target_link_libraries(test_http_proxy_paths PRIVATE proxyplus_core) add_test(NAME test_http_proxy_paths COMMAND test_http_proxy_paths)
test/test_http_proxy_paths.cpp 0 → 100644 +30 −0 Changes for test/test_http_proxy_paths.cpp: 30 added lines, 0 removed lines. Original line number Diff line number Diff line #include <cassert> #include <iostream> #include "../src/http/HttpProxyServer.h" using proxyplus::httpproxy::detail::buildForwardTarget; int main() { assert(buildForwardTarget("/git/tuxist/authdb.git/info/refs", "/git/tuxist/authdb.git/info/refs?service=git-upload-pack", "/git") == "/tuxist/authdb.git/info/refs?service=git-upload-pack"); assert(buildForwardTarget("/git/tuxist/authdb.git/git-upload-pack", "/git/tuxist/authdb.git/git-upload-pack", "/git") == "/tuxist/authdb.git/git-upload-pack"); assert(buildForwardTarget("/git", "/git?service=git-upload-pack", "/git") == "/?service=git-upload-pack"); // Absolute-form request targets are legal in HTTP/1.1 and still carry the same query. assert(buildForwardTarget("/git/project/info/refs", "https://git.tuxist.de/git/project/info/refs?service=git-upload-pack", "/git") == "/project/info/refs?service=git-upload-pack"); std::cout << "test_http_proxy_paths: OK" << std::endl; return 0; }