can send a response, cannot process body yet
This commit is contained in:
		@@ -5,6 +5,8 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "IXHttp.h"
 | 
			
		||||
#include "IXCancellationRequest.h"
 | 
			
		||||
#include "IXSocket.h"
 | 
			
		||||
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
@@ -53,4 +55,74 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        return std::make_tuple(method, requestUri, httpVersion);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::tuple<bool, std::string, HttpRequestPtr> Http::parseRequest(std::shared_ptr<Socket> socket)
 | 
			
		||||
    {
 | 
			
		||||
        HttpRequestPtr httpRequest;
 | 
			
		||||
 | 
			
		||||
        std::atomic<bool> requestInitCancellation(false);
 | 
			
		||||
 | 
			
		||||
        int timeoutSecs = 5; // FIXME
 | 
			
		||||
 | 
			
		||||
        auto isCancellationRequested =
 | 
			
		||||
            makeCancellationRequestWithTimeout(timeoutSecs, requestInitCancellation);
 | 
			
		||||
 | 
			
		||||
        // Read first line
 | 
			
		||||
        auto lineResult = socket->readLine(isCancellationRequested);
 | 
			
		||||
        auto lineValid = lineResult.first;
 | 
			
		||||
        auto line = lineResult.second;
 | 
			
		||||
 | 
			
		||||
        if (!lineValid)
 | 
			
		||||
        {
 | 
			
		||||
            return std::make_tuple(false, "Error reading HTTP request line", httpRequest);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Parse request line (GET /foo HTTP/1.1\r\n)
 | 
			
		||||
        auto requestLine = Http::parseRequestLine(line);
 | 
			
		||||
        auto method      = std::get<0>(requestLine);
 | 
			
		||||
        auto uri         = std::get<1>(requestLine);
 | 
			
		||||
        auto httpVersion = std::get<2>(requestLine);
 | 
			
		||||
 | 
			
		||||
        // Retrieve and validate HTTP headers
 | 
			
		||||
        auto result = parseHttpHeaders(socket, isCancellationRequested);
 | 
			
		||||
        auto headersValid = result.first;
 | 
			
		||||
        auto headers = result.second;
 | 
			
		||||
 | 
			
		||||
        if (!headersValid)
 | 
			
		||||
        {
 | 
			
		||||
            return std::make_tuple(false, "Error parsing HTTP headers", httpRequest);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        httpRequest = std::make_shared<HttpRequest>(uri, method, httpVersion, headers);
 | 
			
		||||
        return std::make_tuple(true, "", httpRequest);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // FIXME: Write a mime type
 | 
			
		||||
    bool Http::sendResponse(HttpResponsePtr response, std::shared_ptr<Socket> socket)
 | 
			
		||||
    {
 | 
			
		||||
        // Write the response to the socket
 | 
			
		||||
        std::stringstream ss;
 | 
			
		||||
        ss << "HTTP/1.1 ";
 | 
			
		||||
        ss << response->statusCode;
 | 
			
		||||
        ss << " ";
 | 
			
		||||
        ss << response->description;
 | 
			
		||||
        ss << "\r\n";
 | 
			
		||||
 | 
			
		||||
        if (!socket->writeBytes(ss.str(), nullptr))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Write headers
 | 
			
		||||
        ss.str("");
 | 
			
		||||
        ss << "Content-Length: " << response->payload.size() << "\r\n";
 | 
			
		||||
        ss << "\r\n";
 | 
			
		||||
 | 
			
		||||
        if (!socket->writeBytes(ss.str(), nullptr))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return socket->writeBytes(response->payload, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@ namespace ix
 | 
			
		||||
    struct HttpResponse
 | 
			
		||||
    {
 | 
			
		||||
        int statusCode;
 | 
			
		||||
        std::string description;
 | 
			
		||||
        HttpErrorCode errorCode;
 | 
			
		||||
        WebSocketHttpHeaders headers;
 | 
			
		||||
        std::string payload;
 | 
			
		||||
@@ -43,6 +44,7 @@ namespace ix
 | 
			
		||||
        uint64_t downloadSize;
 | 
			
		||||
 | 
			
		||||
        HttpResponse(int s = 0,
 | 
			
		||||
                     const std::string& des = std::string(),
 | 
			
		||||
                     const HttpErrorCode& c = HttpErrorCode::Ok,
 | 
			
		||||
                     const WebSocketHttpHeaders& h = WebSocketHttpHeaders(),
 | 
			
		||||
                     const std::string& p = std::string(),
 | 
			
		||||
@@ -50,6 +52,7 @@ namespace ix
 | 
			
		||||
                     uint64_t u = 0,
 | 
			
		||||
                     uint64_t d = 0)
 | 
			
		||||
            : statusCode(s)
 | 
			
		||||
            , description(des)
 | 
			
		||||
            , errorCode(c)
 | 
			
		||||
            , headers(h)
 | 
			
		||||
            , payload(p)
 | 
			
		||||
@@ -84,9 +87,33 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
    using HttpRequestArgsPtr = std::shared_ptr<HttpRequestArgs>;
 | 
			
		||||
 | 
			
		||||
    struct HttpRequest
 | 
			
		||||
    {
 | 
			
		||||
        std::string uri;
 | 
			
		||||
        std::string method;
 | 
			
		||||
        std::string version;
 | 
			
		||||
        WebSocketHttpHeaders headers;
 | 
			
		||||
 | 
			
		||||
        HttpRequest(const std::string& u,
 | 
			
		||||
                    const std::string& m,
 | 
			
		||||
                    const std::string& v,
 | 
			
		||||
                    const WebSocketHttpHeaders& h = WebSocketHttpHeaders())
 | 
			
		||||
            : uri(u)
 | 
			
		||||
            , method(m)
 | 
			
		||||
            , version(v)
 | 
			
		||||
            , headers(h)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    using HttpRequestPtr = std::shared_ptr<HttpRequest>;
 | 
			
		||||
 | 
			
		||||
    class Http
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        static std::tuple<bool, std::string, HttpRequestPtr> parseRequest(std::shared_ptr<Socket> socket);
 | 
			
		||||
        static bool sendResponse(HttpResponsePtr response, std::shared_ptr<Socket> socket);
 | 
			
		||||
 | 
			
		||||
        static std::tuple<std::string, std::string, std::string> parseRequestLine(const std::string& line);
 | 
			
		||||
        static std::string trim(const std::string& str);
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -118,6 +118,7 @@ namespace ix
 | 
			
		||||
        int code = 0;
 | 
			
		||||
        WebSocketHttpHeaders headers;
 | 
			
		||||
        std::string payload;
 | 
			
		||||
        std::string description;
 | 
			
		||||
 | 
			
		||||
        std::string protocol, host, path, query;
 | 
			
		||||
        int port;
 | 
			
		||||
@@ -126,9 +127,9 @@ namespace ix
 | 
			
		||||
        {
 | 
			
		||||
            std::stringstream ss;
 | 
			
		||||
            ss << "Cannot parse url: " << url;
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, HttpErrorCode::UrlMalformed,
 | 
			
		||||
                                headers, payload, ss.str(),
 | 
			
		||||
                                uploadSize, downloadSize);
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, description, HttpErrorCode::UrlMalformed,
 | 
			
		||||
                                                  headers, payload, ss.str(),
 | 
			
		||||
                                                  uploadSize, downloadSize);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool tls = protocol == "https";
 | 
			
		||||
@@ -137,9 +138,9 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        if (!_socket)
 | 
			
		||||
        {
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, HttpErrorCode::CannotCreateSocket,
 | 
			
		||||
                                headers, payload, errorMsg,
 | 
			
		||||
                                uploadSize, downloadSize);
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, description, HttpErrorCode::CannotCreateSocket,
 | 
			
		||||
                                                  headers, payload, errorMsg,
 | 
			
		||||
                                                  uploadSize, downloadSize);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Build request string
 | 
			
		||||
@@ -200,7 +201,7 @@ namespace ix
 | 
			
		||||
        {
 | 
			
		||||
            std::stringstream ss;
 | 
			
		||||
            ss << "Cannot connect to url: " << url << " / error : " << errMsg;
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, HttpErrorCode::CannotConnect,
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, description, HttpErrorCode::CannotConnect,
 | 
			
		||||
                                                  headers, payload, ss.str(),
 | 
			
		||||
                                                  uploadSize, downloadSize);
 | 
			
		||||
        }
 | 
			
		||||
@@ -226,7 +227,7 @@ namespace ix
 | 
			
		||||
        if (!_socket->writeBytes(req, isCancellationRequested))
 | 
			
		||||
        {
 | 
			
		||||
            std::string errorMsg("Cannot send request");
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, HttpErrorCode::SendError,
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, description, HttpErrorCode::SendError,
 | 
			
		||||
                                                  headers, payload, errorMsg,
 | 
			
		||||
                                                  uploadSize, downloadSize);
 | 
			
		||||
        }
 | 
			
		||||
@@ -240,7 +241,7 @@ namespace ix
 | 
			
		||||
        if (!lineValid)
 | 
			
		||||
        {
 | 
			
		||||
            std::string errorMsg("Cannot retrieve status line");
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, HttpErrorCode::CannotReadStatusLine,
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, description, HttpErrorCode::CannotReadStatusLine,
 | 
			
		||||
                                                  headers, payload, errorMsg,
 | 
			
		||||
                                                  uploadSize, downloadSize);
 | 
			
		||||
        }
 | 
			
		||||
@@ -255,7 +256,7 @@ namespace ix
 | 
			
		||||
        if (sscanf(line.c_str(), "HTTP/1.1 %d", &code) != 1)
 | 
			
		||||
        {
 | 
			
		||||
            std::string errorMsg("Cannot parse response code from status line");
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, HttpErrorCode::MissingStatus,
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, description, HttpErrorCode::MissingStatus,
 | 
			
		||||
                                                  headers, payload, errorMsg,
 | 
			
		||||
                                                  uploadSize, downloadSize);
 | 
			
		||||
        }
 | 
			
		||||
@@ -267,7 +268,7 @@ namespace ix
 | 
			
		||||
        if (!headersValid)
 | 
			
		||||
        {
 | 
			
		||||
            std::string errorMsg("Cannot parse http headers");
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, HttpErrorCode::HeaderParsingError,
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, description, HttpErrorCode::HeaderParsingError,
 | 
			
		||||
                                                  headers, payload, errorMsg,
 | 
			
		||||
                                                  uploadSize, downloadSize);
 | 
			
		||||
        }
 | 
			
		||||
@@ -278,7 +279,7 @@ namespace ix
 | 
			
		||||
            if (headers.find("Location") == headers.end())
 | 
			
		||||
            {
 | 
			
		||||
                std::string errorMsg("Missing location header for redirect");
 | 
			
		||||
                return std::make_shared<HttpResponse>(code, HttpErrorCode::MissingLocation,
 | 
			
		||||
                return std::make_shared<HttpResponse>(code, description, HttpErrorCode::MissingLocation,
 | 
			
		||||
                                                      headers, payload, errorMsg,
 | 
			
		||||
                                                      uploadSize, downloadSize);
 | 
			
		||||
            }
 | 
			
		||||
@@ -287,7 +288,7 @@ namespace ix
 | 
			
		||||
            {
 | 
			
		||||
                std::stringstream ss;
 | 
			
		||||
                ss << "Too many redirects: " << redirects;
 | 
			
		||||
                return std::make_shared<HttpResponse>(code, HttpErrorCode::TooManyRedirects,
 | 
			
		||||
                return std::make_shared<HttpResponse>(code, description, HttpErrorCode::TooManyRedirects,
 | 
			
		||||
                                                      headers, payload, ss.str(),
 | 
			
		||||
                                                      uploadSize, downloadSize);
 | 
			
		||||
            }
 | 
			
		||||
@@ -299,7 +300,7 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        if (verb == "HEAD")
 | 
			
		||||
        {
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, HttpErrorCode::Ok,
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, description, HttpErrorCode::Ok,
 | 
			
		||||
                                                  headers, payload, std::string(),
 | 
			
		||||
                                                  uploadSize, downloadSize);
 | 
			
		||||
        }
 | 
			
		||||
@@ -320,7 +321,7 @@ namespace ix
 | 
			
		||||
            if (!chunkResult.first)
 | 
			
		||||
            {
 | 
			
		||||
                errorMsg = "Cannot read chunk";
 | 
			
		||||
                return std::make_shared<HttpResponse>(code, HttpErrorCode::ChunkReadError,
 | 
			
		||||
                return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
 | 
			
		||||
                                                      headers, payload, errorMsg,
 | 
			
		||||
                                                      uploadSize, downloadSize);
 | 
			
		||||
            }
 | 
			
		||||
@@ -338,7 +339,7 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
                if (!lineResult.first)
 | 
			
		||||
                {
 | 
			
		||||
                    return std::make_shared<HttpResponse>(code, HttpErrorCode::ChunkReadError,
 | 
			
		||||
                    return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
 | 
			
		||||
                                                          headers, payload, errorMsg,
 | 
			
		||||
                                                          uploadSize, downloadSize);
 | 
			
		||||
                }
 | 
			
		||||
@@ -365,7 +366,7 @@ namespace ix
 | 
			
		||||
                if (!chunkResult.first)
 | 
			
		||||
                {
 | 
			
		||||
                    errorMsg = "Cannot read chunk";
 | 
			
		||||
                    return std::make_shared<HttpResponse>(code, HttpErrorCode::ChunkReadError,
 | 
			
		||||
                    return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
 | 
			
		||||
                                                          headers, payload, errorMsg,
 | 
			
		||||
                                                          uploadSize, downloadSize);
 | 
			
		||||
                }
 | 
			
		||||
@@ -376,7 +377,7 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
                if (!lineResult.first)
 | 
			
		||||
                {
 | 
			
		||||
                    return std::make_shared<HttpResponse>(code, HttpErrorCode::ChunkReadError,
 | 
			
		||||
                    return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
 | 
			
		||||
                                                          headers, payload, errorMsg,
 | 
			
		||||
                                                          uploadSize, downloadSize);
 | 
			
		||||
                }
 | 
			
		||||
@@ -391,7 +392,7 @@ namespace ix
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            std::string errorMsg("Cannot read http body");
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, HttpErrorCode::CannotReadBody,
 | 
			
		||||
            return std::make_shared<HttpResponse>(code, description, HttpErrorCode::CannotReadBody,
 | 
			
		||||
                                                  headers, payload, errorMsg,
 | 
			
		||||
                                                  uploadSize, downloadSize);
 | 
			
		||||
        }
 | 
			
		||||
@@ -405,14 +406,14 @@ namespace ix
 | 
			
		||||
            if (!gzipInflate(payload, decompressedPayload))
 | 
			
		||||
            {
 | 
			
		||||
                std::string errorMsg("Error decompressing payload");
 | 
			
		||||
                return std::make_shared<HttpResponse>(code, HttpErrorCode::Gzip,
 | 
			
		||||
                return std::make_shared<HttpResponse>(code, description, HttpErrorCode::Gzip,
 | 
			
		||||
                                                      headers, payload, errorMsg,
 | 
			
		||||
                                                      uploadSize, downloadSize);
 | 
			
		||||
            }
 | 
			
		||||
            payload = decompressedPayload;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return std::make_shared<HttpResponse>(code, HttpErrorCode::Ok,
 | 
			
		||||
        return std::make_shared<HttpResponse>(code, description, HttpErrorCode::Ok,
 | 
			
		||||
                                              headers, payload, std::string(),
 | 
			
		||||
                                              uploadSize, downloadSize);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
 | 
			
		||||
#include "IXSocket.h"
 | 
			
		||||
#include "IXWebSocketHttpHeaders.h"
 | 
			
		||||
#include "IXHttp.h"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
@@ -20,78 +21,6 @@
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    enum class HttpErrorCode : int
 | 
			
		||||
    {
 | 
			
		||||
        Ok = 0,
 | 
			
		||||
        CannotConnect = 1,
 | 
			
		||||
        Timeout = 2,
 | 
			
		||||
        Gzip = 3,
 | 
			
		||||
        UrlMalformed = 4,
 | 
			
		||||
        CannotCreateSocket = 5,
 | 
			
		||||
        SendError = 6,
 | 
			
		||||
        ReadError = 7,
 | 
			
		||||
        CannotReadStatusLine = 8,
 | 
			
		||||
        MissingStatus = 9,
 | 
			
		||||
        HeaderParsingError = 10,
 | 
			
		||||
        MissingLocation = 11,
 | 
			
		||||
        TooManyRedirects = 12,
 | 
			
		||||
        ChunkReadError = 13,
 | 
			
		||||
        CannotReadBody = 14,
 | 
			
		||||
        Invalid = 100
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct HttpResponse
 | 
			
		||||
    {
 | 
			
		||||
        int statusCode;
 | 
			
		||||
        HttpErrorCode errorCode;
 | 
			
		||||
        WebSocketHttpHeaders headers;
 | 
			
		||||
        std::string payload;
 | 
			
		||||
        std::string errorMsg;
 | 
			
		||||
        uint64_t uploadSize;
 | 
			
		||||
        uint64_t downloadSize;
 | 
			
		||||
 | 
			
		||||
        HttpResponse(int s = 0,
 | 
			
		||||
                     const HttpErrorCode& c = HttpErrorCode::Ok,
 | 
			
		||||
                     const WebSocketHttpHeaders& h = WebSocketHttpHeaders(),
 | 
			
		||||
                     const std::string& p = std::string(),
 | 
			
		||||
                     const std::string& e = std::string(),
 | 
			
		||||
                     uint64_t u = 0,
 | 
			
		||||
                     uint64_t d = 0)
 | 
			
		||||
            : statusCode(s)
 | 
			
		||||
            , errorCode(c)
 | 
			
		||||
            , headers(h)
 | 
			
		||||
            , payload(p)
 | 
			
		||||
            , errorMsg(e)
 | 
			
		||||
            , uploadSize(u)
 | 
			
		||||
            , downloadSize(d)
 | 
			
		||||
        {
 | 
			
		||||
            ;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    using HttpResponsePtr = std::shared_ptr<HttpResponse>;
 | 
			
		||||
    using HttpParameters = std::map<std::string, std::string>;
 | 
			
		||||
    using Logger = std::function<void(const std::string&)>;
 | 
			
		||||
    using OnResponseCallback = std::function<void(const HttpResponsePtr&)>;
 | 
			
		||||
 | 
			
		||||
    struct HttpRequestArgs
 | 
			
		||||
    {
 | 
			
		||||
        std::string url;
 | 
			
		||||
        std::string verb;
 | 
			
		||||
        WebSocketHttpHeaders extraHeaders;
 | 
			
		||||
        std::string body;
 | 
			
		||||
        int connectTimeout;
 | 
			
		||||
        int transferTimeout;
 | 
			
		||||
        bool followRedirects;
 | 
			
		||||
        int maxRedirects;
 | 
			
		||||
        bool verbose;
 | 
			
		||||
        bool compress;
 | 
			
		||||
        Logger logger;
 | 
			
		||||
        OnProgressCallback onProgressCallback;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    using HttpRequestArgsPtr = std::shared_ptr<HttpRequestArgs>;
 | 
			
		||||
 | 
			
		||||
    class HttpClient
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
 
 | 
			
		||||
@@ -56,9 +56,13 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        std::string errorMsg;
 | 
			
		||||
        auto socket = createSocket(fd, errorMsg);
 | 
			
		||||
        // Set the socket to non blocking mode + other tweaks
 | 
			
		||||
        SocketConnect::configure(fd);
 | 
			
		||||
 | 
			
		||||
        std::cout << "I was here" << std::endl;
 | 
			
		||||
        auto ret = Http::parseRequest(socket);
 | 
			
		||||
        auto response = _onConnectionCallback(std::get<2>(ret), connectionState);
 | 
			
		||||
 | 
			
		||||
        Http::sendResponse(response, socket);
 | 
			
		||||
#if 0
 | 
			
		||||
        // Parse request
 | 
			
		||||
        auto httpRequest = std::make_shared<HttpRequestArgs>();
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
 | 
			
		||||
#include "IXSocketServer.h"
 | 
			
		||||
#include "IXWebSocket.h"
 | 
			
		||||
#include "IXHttp.h"
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
@@ -19,7 +20,7 @@
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    using OnConnectionCallback =
 | 
			
		||||
        std::function<void(std::shared_ptr<WebSocket>, std::shared_ptr<ConnectionState>)>;
 | 
			
		||||
        std::function<HttpResponsePtr(HttpRequestPtr, std::shared_ptr<ConnectionState>)>;
 | 
			
		||||
 | 
			
		||||
    class HttpServer final : public SocketServer
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include "IXWebSocketHandshake.h"
 | 
			
		||||
#include "IXSocketConnect.h"
 | 
			
		||||
#include "IXUrlParser.h"
 | 
			
		||||
#include "IXHttp.h"
 | 
			
		||||
 | 
			
		||||
#include "libwshandshake.hpp"
 | 
			
		||||
 | 
			
		||||
@@ -31,15 +32,6 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string WebSocketHandshake::trim(const std::string& str)
 | 
			
		||||
    {
 | 
			
		||||
        std::string out(str);
 | 
			
		||||
        out.erase(std::remove(out.begin(), out.end(), ' '), out.end());
 | 
			
		||||
        out.erase(std::remove(out.begin(), out.end(), '\r'), out.end());
 | 
			
		||||
        out.erase(std::remove(out.begin(), out.end(), '\n'), out.end());
 | 
			
		||||
        return out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool WebSocketHandshake::insensitiveStringCompare(const std::string& a, const std::string& b)
 | 
			
		||||
    {
 | 
			
		||||
        return std::equal(a.begin(), a.end(),
 | 
			
		||||
@@ -50,40 +42,6 @@ namespace ix
 | 
			
		||||
                          });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::tuple<std::string, std::string, std::string> WebSocketHandshake::parseRequestLine(const std::string& line)
 | 
			
		||||
    {
 | 
			
		||||
        // Request-Line   = Method SP Request-URI SP HTTP-Version CRLF
 | 
			
		||||
        std::string token;
 | 
			
		||||
        std::stringstream tokenStream(line);
 | 
			
		||||
        std::vector<std::string> tokens;
 | 
			
		||||
 | 
			
		||||
        // Split by ' '
 | 
			
		||||
        while (std::getline(tokenStream, token, ' '))
 | 
			
		||||
        {
 | 
			
		||||
            tokens.push_back(token);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::string method;
 | 
			
		||||
        if (tokens.size() >= 1)
 | 
			
		||||
        {
 | 
			
		||||
            method = trim(tokens[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::string requestUri;
 | 
			
		||||
        if (tokens.size() >= 2)
 | 
			
		||||
        {
 | 
			
		||||
            requestUri = trim(tokens[1]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::string httpVersion;
 | 
			
		||||
        if (tokens.size() >= 3)
 | 
			
		||||
        {
 | 
			
		||||
            httpVersion = trim(tokens[2]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return std::make_tuple(method, requestUri, httpVersion);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string WebSocketHandshake::genRandomString(const int len)
 | 
			
		||||
    {
 | 
			
		||||
        std::string alphanum =
 | 
			
		||||
@@ -294,7 +252,7 @@ namespace ix
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Validate request line (GET /foo HTTP/1.1\r\n)
 | 
			
		||||
        auto requestLine = parseRequestLine(line);
 | 
			
		||||
        auto requestLine = Http::parseRequestLine(line);
 | 
			
		||||
        auto method      = std::get<0>(requestLine);
 | 
			
		||||
        auto uri         = std::get<1>(requestLine);
 | 
			
		||||
        auto httpVersion = std::get<2>(requestLine);
 | 
			
		||||
 
 | 
			
		||||
@@ -64,8 +64,6 @@ namespace ix
 | 
			
		||||
        // Parse HTTP headers
 | 
			
		||||
        WebSocketInitResult sendErrorResponse(int code, const std::string& reason);
 | 
			
		||||
 | 
			
		||||
        std::tuple<std::string, std::string, std::string> parseRequestLine(const std::string& line);
 | 
			
		||||
        std::string trim(const std::string& str);
 | 
			
		||||
        bool insensitiveStringCompare(const std::string& a, const std::string& b);
 | 
			
		||||
 | 
			
		||||
        std::atomic<bool>& _requestInitCancellation;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user