void HttpServerLog::Append(rs::httpserver::socket_ptr socket, rs::httpserver::request_ptr request, rs::httpserver::response_ptr response, const std::time_t& start, long duration) {
    
    int year, month, day, hour, min, sec;
    GetTimestamp(start, year, month, day, hour, min, sec);
    
    const auto queryString = request->getHeaders()->getQueryString();
    
    const auto localAddr = socket->getLocalEndpoint().address().to_string();
    const auto remoteAddr = socket->getRemoteEndpoint().address().to_string();
    
    auto index = writeRowIndex++;    
    index %= maxLogRows;
    
    // TODO: optimize the string formatting to reduce ad-hoc allocations and re-use already known string values (dates, etc.)
    logRows[index].status = response->getStatusCode();
    std::snprintf(logRows[index].data, sizeof(logRows[0].data), 
        "%04d-%02d-%02d %02d:%02d:%02dZ %s %s %s %s %u %s %s %d %u",
        year, month, day, hour, min, sec,
        localAddr.c_str(),
        request->getMethod().c_str(),
        request->getUri().c_str(),
        queryString.size() > 0 ? queryString.c_str() : "-",
        socket->getLocalEndpoint().port(),
        remoteAddr.c_str(),
        boost::replace_all_copy(request->getHeaders()->getUserAgent(), " ", "+").c_str(),
        response->getStatusCode(),
        duration);        
}
void HttpServer::HandleUtilsRequest(rs::httpserver::request_ptr request, rs::httpserver::response_ptr response) {
    auto uri = request->getUri();

    if (uri == "/_utils" || uri == "/_utils/") {
        response->Redirect("/_utils/index.html");
    } else {
        auto contentType = rs::httpserver::MimeTypes::GetType(uri);
        if (contentType) {
            uri = "www" + uri;

            rs::httpserver::FileStream stream(uri);
            if (stream) {
                auto lastModifiedTime = stream.getLastModifiedTime();
                if (lastModifiedTime) {
                    auto etag = boost::lexical_cast<std::string>(lastModifiedTime.get());

                    if (etag == request->getIfNoneMatch()) {
                      response->setStatusCode(304).setStatusDescription("Not Modified").Send();
                    } else {
                        response->setETag(etag);
                    }

                }
                if (!response->HasResponded()) {
                    response->setContentType(contentType.get()).Send(stream);
                }
            }
        }
    }
}
Beispiel #3
0
void RestServer::RouteRequest(rs::httpserver::socket_ptr, rs::httpserver::request_ptr request, rs::httpserver::response_ptr response) {
    router_.Match(request, response);
    
    if (!response->HasResponded()) {
        response->setContentType(ContentTypes::textPlain).setStatusCode(404).setStatusDescription("Not Found").Send(R"({"error":"not_found","reason":"no_db_file"})");
    }
}

bool RestServer::GetActiveTasks(rs::httpserver::request_ptr request, const rs::httpserver::RequestRouter::CallbackArgs&, rs::httpserver::response_ptr response) {
    response->setContentType(ContentTypes::applicationJson).Send("[]");
    return true;
}

bool RestServer::GetSession(rs::httpserver::request_ptr request, const rs::httpserver::RequestRouter::CallbackArgs&, rs::httpserver::response_ptr response) {
    response->setContentType(ContentTypes::applicationJson).Send(R"({"ok":true,"userCtx":{"name":null,"roles":["_admin"]},"info":{"authentication_db":"_users","authentication_handlers":["oauth","cookie","default"],"authenticated":"default"}})");
    return true;
}

bool RestServer::GetAllDbs(rs::httpserver::request_ptr request, const rs::httpserver::RequestRouter::CallbackArgs&, rs::httpserver::response_ptr response) {
    auto dbs = databases_.GetDatabases();
    
    JsonStream stream{JsonStream::ContextType::Array};
    for (int i = 0; i < dbs.size(); ++i) {
        stream.Append(dbs[i]);
    }
    
    response->setContentType(ContentTypes::applicationJson).Send(stream.Flush());
    return true;
}
void HttpServer::RequestCallback(rs::httpserver::socket_ptr socket, rs::httpserver::request_ptr request, rs::httpserver::response_ptr response) {
    
    auto start = boost::chrono::system_clock::now();
    
    try {
        if (request->getUri().find("/_utils") == 0) {
            HandleUtilsRequest(request, response);
            
            if (!response->HasResponded()) {
                response->setStatusCode(404).setStatusDescription("Not Found").Send();
            }
        } else {
            rest_.RouteRequest(socket, request, response);
        }                
    } catch (const HttpServerException& ex) {
        if (!response->HasResponded()) {
            try {
                response->setContentType(ex.ContentType()).setStatusCode(ex.StatusCode()).setStatusDescription(ex.Description()).Send(ex.Body());
            } catch (...) {}
        }
    } catch (const boost::exception& ex) {
        if (!response->HasResponded()) {
            InternalErrorResponse(socket, request, response);
        }
    } catch (const std::exception& ex) {
        if (!response->HasResponded()) {
            InternalErrorResponse(socket, request, response);
        }
    }           
    
    if (response->HasResponded()) {
        auto duration = boost::chrono::system_clock::now() - start;
        auto durationMS = boost::chrono::duration_cast<boost::chrono::milliseconds>(duration);

        HttpServerLog::Append(socket, request, response, boost::chrono::system_clock::to_time_t(start), durationMS.count());
    }
}
void HttpServer::InternalErrorResponse(rs::httpserver::socket_ptr socket, rs::httpserver::request_ptr request, rs::httpserver::response_ptr response) noexcept {
    try {
        response->setContentType("text/plain").setStatusCode(500).setStatusDescription("Internal Server Error").Send();
    } catch (...) {}
}