winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

ServerCommon.cpp (3607B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 
      4 #include "ServerCommon.h"
      5 
      6 #include "../util/TestHelper.h"
      7 #include "Result.h"
      8 
      9 using SFS::test::BufferedLogData;
     10 using SFS::test::StatusCodeException;
     11 using SFS::test::details::BaseServerImpl;
     12 using namespace SFS;
     13 using namespace std::string_literals;
     14 
     15 static constexpr const char* c_listenHostName = "localhost";
     16 
     17 static std::string ToString(httplib::StatusCode status)
     18 {
     19     return std::to_string(status) + " " + std::string(httplib::status_message(status));
     20 }
     21 
     22 StatusCodeException::StatusCodeException(httplib::StatusCode status) : m_status(status), m_message(::ToString(m_status))
     23 {
     24 }
     25 
     26 const char* StatusCodeException::what() const noexcept
     27 {
     28     return m_message.c_str();
     29 }
     30 
     31 httplib::StatusCode StatusCodeException::GetStatusCode() const
     32 {
     33     return m_status;
     34 }
     35 
     36 static SFS::LogData ToLogData(const BufferedLogData& data)
     37 {
     38     return {LogSeverity::Info, data.message.c_str(), data.file.c_str(), data.line, data.function.c_str(), data.time};
     39 }
     40 
     41 void BaseServerImpl::Start()
     42 {
     43     ConfigureServerSettings();
     44     ConfigureRequestHandlers();
     45 
     46     m_port = m_server.bind_to_any_port(c_listenHostName);
     47     m_listenerThread = std::thread([&]() { m_server.listen_after_bind(); });
     48 }
     49 
     50 void BaseServerImpl::ConfigureServerSettings()
     51 {
     52     m_server.set_logger([&](const httplib::Request& req, const httplib::Response& res) {
     53         BUFFER_LOG("Request: " + req.method + " " + req.path + " " + req.version);
     54         BUFFER_LOG("Request Body: " + req.body);
     55 
     56         BUFFER_LOG("Response: " + res.version + " " + ::ToString(static_cast<httplib::StatusCode>(res.status)) + " " +
     57                    res.reason);
     58         BUFFER_LOG("Response body: " + res.body);
     59     });
     60 
     61     m_server.set_exception_handler([&](const httplib::Request&, httplib::Response& res, std::exception_ptr ep) {
     62         try
     63         {
     64             std::rethrow_exception(ep);
     65         }
     66         catch (std::exception& e)
     67         {
     68             m_lastException = Result(Result::HttpUnexpected, e.what());
     69         }
     70         catch (...)
     71         {
     72             m_lastException = Result(Result::HttpUnexpected, "Unknown Exception");
     73         }
     74 
     75         ProcessBufferedLogs();
     76 
     77         res.status = httplib::StatusCode::InternalServerError_500;
     78     });
     79 
     80     // Keeping this interval to a minimum ensures tests run quicker
     81     m_server.set_keep_alive_timeout(1); // 1 second
     82 }
     83 
     84 void BaseServerImpl::BufferLog(const BufferedLogData& data)
     85 {
     86     std::lock_guard guard(m_logMutex);
     87     m_bufferedLog.push_back(data);
     88 }
     89 
     90 BufferedLogData BaseServerImpl::BuildBufferedLogData(const std::string& message,
     91                                                      const char* file,
     92                                                      unsigned line,
     93                                                      const char* function)
     94 {
     95     return BufferedLogData{GetLogIdentifier() + ": " + message, file, line, function, std::chrono::system_clock::now()};
     96 }
     97 
     98 void BaseServerImpl::ProcessBufferedLogs()
     99 {
    100     for (const auto& data : m_bufferedLog)
    101     {
    102         LogCallbackToTest(ToLogData(data));
    103     }
    104     m_bufferedLog.clear();
    105 }
    106 
    107 Result BaseServerImpl::Stop()
    108 {
    109     if (m_listenerThread.joinable())
    110     {
    111         m_server.stop();
    112         m_listenerThread.join();
    113     }
    114     ProcessBufferedLogs();
    115     return m_lastException.value_or(Result::Success);
    116 }
    117 
    118 std::string BaseServerImpl::GetUrl() const
    119 {
    120     return "http://"s + c_listenHostName + ":"s + std::to_string(m_port);
    121 }