ProxyServer.cpp (2759B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 4 #include "ProxyServer.h" 5 6 #include "../util/TestHelper.h" 7 #include "ErrorHandling.h" 8 #include "ReportingHandler.h" 9 #include "ServerCommon.h" 10 #include "UrlBuilder.h" 11 12 using namespace SFS; 13 using namespace SFS::details; 14 using namespace SFS::test; 15 using namespace SFS::test::details; 16 17 namespace SFS::test::details 18 { 19 class ProxyServerImpl : public BaseServerImpl 20 { 21 private: 22 void ConfigureRequestHandlers() override; 23 std::string GetLogIdentifier() override; 24 }; 25 } // namespace SFS::test::details 26 27 ProxyServer::ProxyServer() 28 { 29 m_impl = std::make_unique<ProxyServerImpl>(); 30 m_impl->Start(); 31 } 32 33 ProxyServer::~ProxyServer() 34 { 35 const auto ret = Stop(); 36 if (!ret) 37 { 38 TEST_UNSCOPED_INFO("Failed to stop: " + std::string(ToString(ret.GetCode()))); 39 } 40 } 41 42 Result ProxyServer::Stop() 43 { 44 return m_impl->Stop(); 45 } 46 47 std::string ProxyServer::GetBaseUrl() const 48 { 49 return m_impl->GetUrl(); 50 } 51 52 void ProxyServerImpl::ConfigureRequestHandlers() 53 { 54 auto HandleRequest = [&](const httplib::Request& req, httplib::Response& res) { 55 // As a proxy, we'll parse the URL and Path/Query so we can reuse them in httplib::Client 56 ReportingHandler handler; 57 UrlBuilder urlBuilder(req.target.c_str(), handler); 58 const std::string path = urlBuilder.GetPath(); 59 const std::string query = urlBuilder.GetQuery(); 60 urlBuilder.ResetPath().ResetQuery(); 61 62 // URL may come back from UrlBuilder with a final /, which doesn't work with httplib::Client, so we remove it 63 auto url = urlBuilder.GetUrl(); 64 if (url.at(url.size() - 1) == '/') 65 { 66 url.pop_back(); 67 } 68 const std::string pathAndQuery = path + (query.empty() ? "" : ("?" + query)); 69 httplib::Client cli(url); 70 httplib::Result result; 71 if (req.method == "GET") 72 { 73 result = cli.Get(pathAndQuery, req.headers); 74 } 75 else if (req.method == "POST") 76 { 77 const auto length = std::stoi(req.get_header_value("Content-Length")); 78 result = 79 cli.Post(pathAndQuery, req.headers, req.body.c_str(), length, req.get_header_value("Content-Type")); 80 } 81 82 if (!result) 83 { 84 BUFFER_LOG("Client error: " + to_string(result.error())); 85 throw StatusCodeException(httplib::StatusCode::InternalServerError_500); 86 } 87 res = result.value(); 88 }; 89 90 m_server.Get(".*", HandleRequest); 91 m_server.Post(".*", HandleRequest); 92 } 93 94 std::string ProxyServerImpl::GetLogIdentifier() 95 { 96 return "ProxyServer"; 97 }