1
\$\begingroup\$

If you want all the code in a buildable format from the last 10 or so posts. You can find it here:

The PathMatcher object allows you to register paths with named sections of the path. But there are other vaiables available in the reuest. I want to make all the variables available to the lambda in a logic way.

So I have a wrapper class that Implements the PyntHttp interface and uses the PathMatcher to check if a request has a handler. If it does then we combine the header parameters query parameters and path match parameters into the variables() object to be used by the lambda:

HTTPHandler.h

#ifndef THORSANVIL_NISSE_NISSEHTTP_HTTP_HANDLER_H
#define THORSANVIL_NISSE_NISSEHTTP_HTTP_HANDLER_H

#include "NisseHTTPConfig.h"
#include "PyntHTTP.h"
#include "PathMatcher.h"
#include "Util.h"
#include <string_view>

namespace ThorsAnvil::Nisse::NisseHTTP
{

class HeaderRequest;

class HTTPHandler: public PyntHTTP
{
    using HTTPAction = std::function<void(Request& request, Response& response)>;

    PathMatcher             pathMatcher;
    std::vector<HTTPAction> actions;
    public:
        virtual void       processRequest(Request& request, Response& response);

        void addPath(std::string const& path, HTTPAction&& action);
    private:
        std::string normalize(std::string_view path);

        void addHeaders(RequestVariables& var, HeaderRequest const& headers);
        void addQueryParam(RequestVariables& var, std::string_view query);
        void addPathMatch(RequestVariables& var, Match const& matches);
};

}

#endif

HTTPHandler.cpp

#include "HTTPHandler.h"
#include "Request.h"
#include "Response.h"

using namespace ThorsAnvil::Nisse::NisseHTTP;

std::string HTTPHandler::normalize(std::string_view path)
{
    return std::string(path);
}

void HTTPHandler::processRequest(Request& request, Response& response)
{
    std::string path = normalize(request.getUrl().pathname());

    if (!pathMatcher.findMatch(path, request, response)) {
        response.setStatus(404);
    }
}

void HTTPHandler::addHeaders(RequestVariables& var, HeaderRequest const& headers)
{
    for (auto const& head: headers) {
        var[head.first] = head.second.back();
    }
}

void HTTPHandler::addQueryParam(RequestVariables& var, std::string_view query)
{
    // Add URL paramets to the variables object.
    if (query.size() == 0) {
        return;
    }

    // Remove the first ? or &
    query.remove_prefix(1);

    std::smatch     queryParamMatch;
    std::regex      queryParamExpr{"([^=]*)=([^&]*)&"};
    std::string     queryStr(query);
    queryStr += "&";

    while (std::regex_search(queryStr, queryParamMatch, queryParamExpr))
    {
        var[queryParamMatch[1].str()] = queryParamMatch[2].str();
        queryStr = queryParamMatch.suffix().str();
    }
}

void HTTPHandler::addPathMatch(RequestVariables& var, Match const& matches)
{
    for (auto const& match: matches) {
        var[match.first] = match.second;
    }
}

void HTTPHandler::addPath(std::string const& path, HTTPAction&& action)
{
    actions.emplace_back(std::move(action));

    pathMatcher.addPath(path, [&, actionId = actions.size() - 1](Match const& matches, Request& request, Response& response)
    {
        // Get the variable object
        RequestVariables&   var     = request.variables();

        addHeaders(var, request.headers());
        addQueryParam(var,  request.getUrl().query());
        addPathMatch(var, matches);

        actions[actionId](request, response);
    });
}

Hello World

We can now simplify the Hello World handler to:

    // Processes HTTP connection on port.
    ThorsAnvil::Nisse::NisseHTTP::HTTPHandler   http;
    http.addPath("/HW-Length{Who}.html", [](ThorsAnvil::Nisse::NisseHTTP::Request& request, ThorsAnvil::Nisse::NisseHTTP::Response& response)
    {
        std::string     who  = request.variables()["Who"];
        std::string     page = R"(
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head><title>Nisse server 1.1</title></head>
<body>Hello world: )" + who + R"(</body>
</html>
)";

        ThorsAnvil::Nisse::NisseHTTP::HeaderResponse   header;
        response.addHeaders(header, page.size()) << page;
    });
    http.addPath("/HW-Chunked{Who}.html", [](ThorsAnvil::Nisse::NisseHTTP::Request& request, ThorsAnvil::Nisse::NisseHTTP::Response& response)
    {
        ThorsAnvil::Nisse::NisseHTTP::HeaderResponse   header;
        response.addHeaders(header, ThorsAnvil::Nisse::NisseHTTP::Encoding::Chunked) << R"(
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head><title>Nisse server 1.1</title></head>
<body>Hello world: )" << request.variables()["Who"] << R"(</body>
</html>
)";
    });
\$\endgroup\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.