24#include <fastcgi++/log.hpp> 
   25#include <fastcgi++/manager.hpp> 
   26#include <fastcgi++/request.hpp> 
   39    Log logger(
"fastcgi");
 
   44    enum class RawPostAccess {
 
   50    class FastcgippRequestAdapter : 
public Fastcgipp::Request<char> {
 
   51        shared_ptr<string> rawPost;
 
   58        FastcgippRequestAdapter() : Fastcgipp::
Request<char>() {}
 
   64        bool response() 
override;
 
   71        bool inProcessor() 
override;
 
   75bool FastcgippRequestAdapter::response() {
 
   77    auto requestHandler = any_cast<RequestHandler*>(m_externalObject);
 
   81        auto const& renv = environment();
 
   82        auto renvp = [&](
string const& k) {
 
   83            return renv.parameters.count(k) ? renv.parameters.at(k) : string();
 
   86                {
"content-type", renvp(
"CONTENT_TYPE")},
 
   92            auto https = renv.parameters.count(
"HTTPS");
 
   93            baseUrl << (https ? 
"https://" : 
"http://")
 
   94                    << renvp(
"HTTP_HOST");
 
   95            auto baseUrlStr = baseUrl.str();
 
   97            auto requestUri = renvp(
"REQUEST_URI");
 
  100            requestInit.
environment[
"FULL_URL_WITH_QS"] = baseUrlStr + requestUri;
 
  103            baseUrl << requestUri.substr(0, requestUri.find_first_of(
'?'));
 
  104            requestInit.
environment[
"FULL_URL_WITHOUT_QS"] = baseUrl.str();
 
  107        for (
auto const& [k, v] : renv.parameters) {
 
  111            if (k.substr(0, 5) == 
"HTTP_") {
 
  130        for (
auto const& [k, fcgiFile] : renv.files) {
 
  131            requestInit.
postFiles.insert({k, 
File(fcgiFile.data, fcgiFile.size).
filename(fcgiFile.filename).contentType(fcgiFile.contentType)});
 
  136    connectionInit.
requestInit = std::move(requestInit);
 
  137    connectionInit.
config = *requestHandler->getConfig();
 
  141        if (!flushInfo.flushedBefore) {
 
  142            response = 
"status: " + flushInfo.getStatusString() + 
"\r\n";
 
  144        response += flushInfo.getFullHttp();
 
  145        dump(response.c_str(), response.size());
 
  149    requestHandler->handleRequest(connection);
 
  150    connection.flushResponse();
 
  155bool FastcgippRequestAdapter::inProcessor() {
 
  156    auto requestHandler = any_cast<RequestHandler*>(m_externalObject);
 
  157    auto postContentType = environment().contentType;
 
  158    auto configPtr = requestHandler->getConfig();
 
  160    string rawPostAccess = (*configPtr)[{
"post", 
"raw_access"}];
 
  161    if (postContentType.empty() || rawPostAccess == 
"never" ||
 
  162        (rawPostAccess != 
"always" && (postContentType == 
"multipart/form-data" || postContentType == 
"application/x-www-form-urlencoded"))) {
 
  166    auto postBuffer = environment().postBuffer();
 
  167    rawPost = make_shared<string>(postBuffer.data(), postBuffer.size());
 
  171struct FastcgiRequestHandler::Data {
 
  172    unique_ptr<Fastcgipp::Manager<FastcgippRequestAdapter>> fastcgippManager;
 
  173    bool requestHandlingActive = 
false;
 
  177FastcgiRequestHandler::FastcgiRequestHandler(std::shared_ptr<HandleRequestFunctionWrapper> handleRequestFunction,
 
  178                                             Config config, 
int concurrency) {
 
  179    data = make_unique<Data>();
 
  187        postMax = configPtr->isSet({
"post", 
"max_size"})
 
  188                          ? 
static_cast<size_t>(stoul((*configPtr)[{
"post", 
"max_size"}])) * 1024
 
  190    } 
catch (invalid_argument& e) {
 
  191        NLOG_WARNING(logger, 
"WARNING: Invalid value given for post/max_size given in the config file.")
 
  195    Fastcgipp::Logging::addHeader = 
false;
 
  196    Fastcgipp::Logging::logFunction = [&](
string const& msg, Fastcgipp::Logging::Level level) {
 
  199            case Fastcgipp::Logging::INFO:
 
  202            case Fastcgipp::Logging::FAIL:
 
  203            case Fastcgipp::Logging::ERROR:
 
  206            case Fastcgipp::Logging::WARNING:
 
  209            case Fastcgipp::Logging::DEBUG:
 
  210            case Fastcgipp::Logging::DIAG:
 
  216        logger.write(msg, nawaLevel);
 
  219    data->fastcgippManager = make_unique<Fastcgipp::Manager<FastcgippRequestAdapter>>(concurrency, postMax,
 
  223    string mode = (*configPtr)[{
"fastcgi", 
"mode"}];
 
  225        auto fastcgiListen = (*configPtr)[{
"fastcgi", 
"listen"}];
 
  226        auto fastcgiPort = (*configPtr)[{
"fastcgi", 
"port"}];
 
  227        if (fastcgiListen.empty())
 
  228            fastcgiListen = 
"127.0.0.1";
 
  229        char const* fastcgiListenC = fastcgiListen.c_str();
 
  230        if (fastcgiListen == 
"all")
 
  231            fastcgiListenC = 
nullptr;
 
  232        if (fastcgiPort.empty())
 
  233            fastcgiPort = 
"8000";
 
  234        if (!data->fastcgippManager->listen(fastcgiListenC, fastcgiPort.c_str())) {
 
  236                            "Could not create TCP socket for FastCGI.");
 
  238    } 
else if (mode == 
"unix") {
 
  239        uint32_t permissions = 0xffffffffUL;
 
  240        string permStr = (*configPtr)[{
"fastcgi", 
"permissions"}];
 
  242        if (!permStr.empty()) {
 
  243            char const* psptr = permStr.c_str();
 
  245            long perm = strtol(psptr, &endptr, 8);
 
  246            if (*endptr == 
'\0') {
 
  247                permissions = (uint32_t) perm;
 
  251        auto fastcgiSocketPath = (*configPtr)[{
"fastcgi", 
"path"}];
 
  252        if (fastcgiSocketPath.empty()) {
 
  253            fastcgiSocketPath = 
"/etc/nawarun/sock.d/nawarun.sock";
 
  255        auto fastcgiOwner = (*configPtr)[{
"fastcgi", 
"owner"}];
 
  256        auto fastcgiGroup = (*configPtr)[{
"fastcgi", 
"group"}];
 
  258        if (!data->fastcgippManager->listen(fastcgiSocketPath.c_str(), permissions,
 
  259                                            fastcgiOwner.empty() ? 
nullptr : fastcgiOwner.c_str(),
 
  260                                            fastcgiGroup.empty() ? 
nullptr : fastcgiGroup.c_str())) {
 
  262                            "Could not create UNIX socket for FastCGI.");
 
  266                        "Unknown FastCGI socket mode in configuration.");
 
  270    if ((*configPtr)[{
"fastcgi", 
"reuseaddr"}] != 
"off") {
 
  271        data->fastcgippManager->reuseAddress(
true);
 
  276    if (data->requestHandlingActive && !data->joined) {
 
  277        data->fastcgippManager->terminate();
 
  280        data->fastcgippManager->join();
 
  281        data->fastcgippManager.reset(
nullptr);
 
  286    if (data->requestHandlingActive) {
 
  290        throw Exception(__PRETTY_FUNCTION__, 10, 
"FastcgiRequestHandler was already joined.");
 
  292    if (data->fastcgippManager) {
 
  294            data->fastcgippManager->start();
 
  295            data->requestHandlingActive = 
true;
 
  298                            "An unknown error occurred during start of request handling.");
 
  301        throw Exception(__PRETTY_FUNCTION__, 2, 
"FastCGI manager is not available.");
 
  309    if (data->fastcgippManager) {
 
  310        data->fastcgippManager->stop();
 
  318    if (data->fastcgippManager) {
 
  319        data->fastcgippManager->terminate();
 
  327    if (data->fastcgippManager) {
 
  328        data->fastcgippManager->join();
 
  330        data->fastcgippManager.reset(
nullptr);
 
Container used by request handlers to initiate the nawa::Connection object.
 
Response object to be passed back to NAWA and accessor to the request.
 
Exception class that can be used by apps to catch errors resulting from nawa function calls.
 
Class which connects NAWA to the fastcgi++ library.
 
Simple class for (not (yet) thread-safe) logging to stderr or to any other output stream.
 
#define NLOG_WARNING(Logger, Message)
 
Handles and serves incoming requests via the NAWA app.
 
~FastcgiRequestHandler() override
 
void stop() noexcept override
 
void join() noexcept override
 
void terminate() noexcept override
 
std::string & filename() noexcept
 
std::shared_ptr< Config const > getConfig() const noexcept
 
void setConfig(Config config) noexcept
 
void setAppRequestHandler(std::shared_ptr< HandleRequestFunctionWrapper > handleRequestFunction) noexcept
 
std::string toLowercase(std::string s)
 
std::unordered_multimap< KeyType, ValueType > toUnorderedMultimap(MapType< KeyType, ValueType, Args... > inputMap)
 
std::string stringReplace(std::string input, std::unordered_map< char, char > const &patterns)
 
std::unordered_multimap< std::string, std::string > getVars
 
std::string postContentType
 
std::unordered_map< std::string, std::string > environment
 
std::unordered_multimap< std::string, std::string > cookieVars
 
std::unordered_multimap< std::string, File > postFiles
 
RequestInitContainer requestInit
 
std::unordered_multimap< std::string, std::string > postVars
 
FlushCallbackFunction flushCallback
 
std::shared_ptr< std::string > rawPost
 
Contains useful functions that improve the readability and facilitate maintenance of the NAWA code.