can send a response, cannot process body yet
This commit is contained in:
parent
44f37a4140
commit
74cc6b815a
@ -25,7 +25,9 @@ set( IXWEBSOCKET_SOURCES
|
|||||||
ixwebsocket/IXCancellationRequest.cpp
|
ixwebsocket/IXCancellationRequest.cpp
|
||||||
ixwebsocket/IXConnectionState.cpp
|
ixwebsocket/IXConnectionState.cpp
|
||||||
ixwebsocket/IXDNSLookup.cpp
|
ixwebsocket/IXDNSLookup.cpp
|
||||||
|
ixwebsocket/IXHttp.cpp
|
||||||
ixwebsocket/IXHttpClient.cpp
|
ixwebsocket/IXHttpClient.cpp
|
||||||
|
ixwebsocket/IXHttpServer.cpp
|
||||||
ixwebsocket/IXNetSystem.cpp
|
ixwebsocket/IXNetSystem.cpp
|
||||||
ixwebsocket/IXSelectInterrupt.cpp
|
ixwebsocket/IXSelectInterrupt.cpp
|
||||||
ixwebsocket/IXSelectInterruptFactory.cpp
|
ixwebsocket/IXSelectInterruptFactory.cpp
|
||||||
@ -51,7 +53,9 @@ set( IXWEBSOCKET_HEADERS
|
|||||||
ixwebsocket/IXCancellationRequest.h
|
ixwebsocket/IXCancellationRequest.h
|
||||||
ixwebsocket/IXConnectionState.h
|
ixwebsocket/IXConnectionState.h
|
||||||
ixwebsocket/IXDNSLookup.h
|
ixwebsocket/IXDNSLookup.h
|
||||||
|
ixwebsocket/IXHttp.h
|
||||||
ixwebsocket/IXHttpClient.h
|
ixwebsocket/IXHttpClient.h
|
||||||
|
ixwebsocket/IXHttpServer.h
|
||||||
ixwebsocket/IXNetSystem.h
|
ixwebsocket/IXNetSystem.h
|
||||||
ixwebsocket/IXProgressCallback.h
|
ixwebsocket/IXProgressCallback.h
|
||||||
ixwebsocket/IXSelectInterrupt.h
|
ixwebsocket/IXSelectInterrupt.h
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "IXHttp.h"
|
#include "IXHttp.h"
|
||||||
|
#include "IXCancellationRequest.h"
|
||||||
|
#include "IXSocket.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -53,4 +55,74 @@ namespace ix
|
|||||||
|
|
||||||
return std::make_tuple(method, requestUri, httpVersion);
|
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
|
struct HttpResponse
|
||||||
{
|
{
|
||||||
int statusCode;
|
int statusCode;
|
||||||
|
std::string description;
|
||||||
HttpErrorCode errorCode;
|
HttpErrorCode errorCode;
|
||||||
WebSocketHttpHeaders headers;
|
WebSocketHttpHeaders headers;
|
||||||
std::string payload;
|
std::string payload;
|
||||||
@ -43,6 +44,7 @@ namespace ix
|
|||||||
uint64_t downloadSize;
|
uint64_t downloadSize;
|
||||||
|
|
||||||
HttpResponse(int s = 0,
|
HttpResponse(int s = 0,
|
||||||
|
const std::string& des = std::string(),
|
||||||
const HttpErrorCode& c = HttpErrorCode::Ok,
|
const HttpErrorCode& c = HttpErrorCode::Ok,
|
||||||
const WebSocketHttpHeaders& h = WebSocketHttpHeaders(),
|
const WebSocketHttpHeaders& h = WebSocketHttpHeaders(),
|
||||||
const std::string& p = std::string(),
|
const std::string& p = std::string(),
|
||||||
@ -50,6 +52,7 @@ namespace ix
|
|||||||
uint64_t u = 0,
|
uint64_t u = 0,
|
||||||
uint64_t d = 0)
|
uint64_t d = 0)
|
||||||
: statusCode(s)
|
: statusCode(s)
|
||||||
|
, description(des)
|
||||||
, errorCode(c)
|
, errorCode(c)
|
||||||
, headers(h)
|
, headers(h)
|
||||||
, payload(p)
|
, payload(p)
|
||||||
@ -84,9 +87,33 @@ namespace ix
|
|||||||
|
|
||||||
using HttpRequestArgsPtr = std::shared_ptr<HttpRequestArgs>;
|
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
|
class Http
|
||||||
{
|
{
|
||||||
public:
|
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::tuple<std::string, std::string, std::string> parseRequestLine(const std::string& line);
|
||||||
static std::string trim(const std::string& str);
|
static std::string trim(const std::string& str);
|
||||||
};
|
};
|
||||||
|
@ -118,6 +118,7 @@ namespace ix
|
|||||||
int code = 0;
|
int code = 0;
|
||||||
WebSocketHttpHeaders headers;
|
WebSocketHttpHeaders headers;
|
||||||
std::string payload;
|
std::string payload;
|
||||||
|
std::string description;
|
||||||
|
|
||||||
std::string protocol, host, path, query;
|
std::string protocol, host, path, query;
|
||||||
int port;
|
int port;
|
||||||
@ -126,9 +127,9 @@ namespace ix
|
|||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Cannot parse url: " << url;
|
ss << "Cannot parse url: " << url;
|
||||||
return std::make_shared<HttpResponse>(code, HttpErrorCode::UrlMalformed,
|
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::UrlMalformed,
|
||||||
headers, payload, ss.str(),
|
headers, payload, ss.str(),
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tls = protocol == "https";
|
bool tls = protocol == "https";
|
||||||
@ -137,9 +138,9 @@ namespace ix
|
|||||||
|
|
||||||
if (!_socket)
|
if (!_socket)
|
||||||
{
|
{
|
||||||
return std::make_shared<HttpResponse>(code, HttpErrorCode::CannotCreateSocket,
|
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::CannotCreateSocket,
|
||||||
headers, payload, errorMsg,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build request string
|
// Build request string
|
||||||
@ -200,7 +201,7 @@ namespace ix
|
|||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Cannot connect to url: " << url << " / error : " << errMsg;
|
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(),
|
headers, payload, ss.str(),
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -226,7 +227,7 @@ namespace ix
|
|||||||
if (!_socket->writeBytes(req, isCancellationRequested))
|
if (!_socket->writeBytes(req, isCancellationRequested))
|
||||||
{
|
{
|
||||||
std::string errorMsg("Cannot send request");
|
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,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -240,7 +241,7 @@ namespace ix
|
|||||||
if (!lineValid)
|
if (!lineValid)
|
||||||
{
|
{
|
||||||
std::string errorMsg("Cannot retrieve status line");
|
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,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -255,7 +256,7 @@ namespace ix
|
|||||||
if (sscanf(line.c_str(), "HTTP/1.1 %d", &code) != 1)
|
if (sscanf(line.c_str(), "HTTP/1.1 %d", &code) != 1)
|
||||||
{
|
{
|
||||||
std::string errorMsg("Cannot parse response code from status line");
|
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,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -267,7 +268,7 @@ namespace ix
|
|||||||
if (!headersValid)
|
if (!headersValid)
|
||||||
{
|
{
|
||||||
std::string errorMsg("Cannot parse http headers");
|
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,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -278,7 +279,7 @@ namespace ix
|
|||||||
if (headers.find("Location") == headers.end())
|
if (headers.find("Location") == headers.end())
|
||||||
{
|
{
|
||||||
std::string errorMsg("Missing location header for redirect");
|
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,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -287,7 +288,7 @@ namespace ix
|
|||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Too many redirects: " << redirects;
|
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(),
|
headers, payload, ss.str(),
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -299,7 +300,7 @@ namespace ix
|
|||||||
|
|
||||||
if (verb == "HEAD")
|
if (verb == "HEAD")
|
||||||
{
|
{
|
||||||
return std::make_shared<HttpResponse>(code, HttpErrorCode::Ok,
|
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::Ok,
|
||||||
headers, payload, std::string(),
|
headers, payload, std::string(),
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -320,7 +321,7 @@ namespace ix
|
|||||||
if (!chunkResult.first)
|
if (!chunkResult.first)
|
||||||
{
|
{
|
||||||
errorMsg = "Cannot read chunk";
|
errorMsg = "Cannot read chunk";
|
||||||
return std::make_shared<HttpResponse>(code, HttpErrorCode::ChunkReadError,
|
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
|
||||||
headers, payload, errorMsg,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -338,7 +339,7 @@ namespace ix
|
|||||||
|
|
||||||
if (!lineResult.first)
|
if (!lineResult.first)
|
||||||
{
|
{
|
||||||
return std::make_shared<HttpResponse>(code, HttpErrorCode::ChunkReadError,
|
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
|
||||||
headers, payload, errorMsg,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -365,7 +366,7 @@ namespace ix
|
|||||||
if (!chunkResult.first)
|
if (!chunkResult.first)
|
||||||
{
|
{
|
||||||
errorMsg = "Cannot read chunk";
|
errorMsg = "Cannot read chunk";
|
||||||
return std::make_shared<HttpResponse>(code, HttpErrorCode::ChunkReadError,
|
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
|
||||||
headers, payload, errorMsg,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -376,7 +377,7 @@ namespace ix
|
|||||||
|
|
||||||
if (!lineResult.first)
|
if (!lineResult.first)
|
||||||
{
|
{
|
||||||
return std::make_shared<HttpResponse>(code, HttpErrorCode::ChunkReadError,
|
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
|
||||||
headers, payload, errorMsg,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -391,7 +392,7 @@ namespace ix
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string errorMsg("Cannot read http body");
|
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,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
@ -405,14 +406,14 @@ namespace ix
|
|||||||
if (!gzipInflate(payload, decompressedPayload))
|
if (!gzipInflate(payload, decompressedPayload))
|
||||||
{
|
{
|
||||||
std::string errorMsg("Error decompressing payload");
|
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,
|
headers, payload, errorMsg,
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
payload = decompressedPayload;
|
payload = decompressedPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<HttpResponse>(code, HttpErrorCode::Ok,
|
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::Ok,
|
||||||
headers, payload, std::string(),
|
headers, payload, std::string(),
|
||||||
uploadSize, downloadSize);
|
uploadSize, downloadSize);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "IXSocket.h"
|
#include "IXSocket.h"
|
||||||
#include "IXWebSocketHttpHeaders.h"
|
#include "IXWebSocketHttpHeaders.h"
|
||||||
|
#include "IXHttp.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
@ -20,78 +21,6 @@
|
|||||||
|
|
||||||
namespace ix
|
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
|
class HttpClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -56,9 +56,13 @@ namespace ix
|
|||||||
|
|
||||||
std::string errorMsg;
|
std::string errorMsg;
|
||||||
auto socket = createSocket(fd, 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
|
#if 0
|
||||||
// Parse request
|
// Parse request
|
||||||
auto httpRequest = std::make_shared<HttpRequestArgs>();
|
auto httpRequest = std::make_shared<HttpRequestArgs>();
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "IXSocketServer.h"
|
#include "IXSocketServer.h"
|
||||||
#include "IXWebSocket.h"
|
#include "IXWebSocket.h"
|
||||||
|
#include "IXHttp.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -19,7 +20,7 @@
|
|||||||
namespace ix
|
namespace ix
|
||||||
{
|
{
|
||||||
using OnConnectionCallback =
|
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
|
class HttpServer final : public SocketServer
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "IXWebSocketHandshake.h"
|
#include "IXWebSocketHandshake.h"
|
||||||
#include "IXSocketConnect.h"
|
#include "IXSocketConnect.h"
|
||||||
#include "IXUrlParser.h"
|
#include "IXUrlParser.h"
|
||||||
|
#include "IXHttp.h"
|
||||||
|
|
||||||
#include "libwshandshake.hpp"
|
#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)
|
bool WebSocketHandshake::insensitiveStringCompare(const std::string& a, const std::string& b)
|
||||||
{
|
{
|
||||||
return std::equal(a.begin(), a.end(),
|
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 WebSocketHandshake::genRandomString(const int len)
|
||||||
{
|
{
|
||||||
std::string alphanum =
|
std::string alphanum =
|
||||||
@ -294,7 +252,7 @@ namespace ix
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate request line (GET /foo HTTP/1.1\r\n)
|
// 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 method = std::get<0>(requestLine);
|
||||||
auto uri = std::get<1>(requestLine);
|
auto uri = std::get<1>(requestLine);
|
||||||
auto httpVersion = std::get<2>(requestLine);
|
auto httpVersion = std::get<2>(requestLine);
|
||||||
|
@ -64,8 +64,6 @@ namespace ix
|
|||||||
// Parse HTTP headers
|
// Parse HTTP headers
|
||||||
WebSocketInitResult sendErrorResponse(int code, const std::string& reason);
|
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);
|
bool insensitiveStringCompare(const std::string& a, const std::string& b);
|
||||||
|
|
||||||
std::atomic<bool>& _requestInitCancellation;
|
std::atomic<bool>& _requestInitCancellation;
|
||||||
|
@ -68,6 +68,7 @@ add_executable(ws
|
|||||||
ws_cobra_to_statsd.cpp
|
ws_cobra_to_statsd.cpp
|
||||||
ws_cobra_to_sentry.cpp
|
ws_cobra_to_sentry.cpp
|
||||||
ws_snake.cpp
|
ws_snake.cpp
|
||||||
|
ws_httpd.cpp
|
||||||
ws.cpp)
|
ws.cpp)
|
||||||
|
|
||||||
target_link_libraries(ws ixwebsocket)
|
target_link_libraries(ws ixwebsocket)
|
||||||
|
@ -216,6 +216,10 @@ int main(int argc, char** argv)
|
|||||||
->check(CLI::ExistingPath);
|
->check(CLI::ExistingPath);
|
||||||
runApp->add_flag("-v", verbose, "Verbose");
|
runApp->add_flag("-v", verbose, "Verbose");
|
||||||
|
|
||||||
|
CLI::App* httpServerApp = app.add_subcommand("httpd", "HTTP server");
|
||||||
|
httpServerApp->add_option("--port", port, "Port");
|
||||||
|
httpServerApp->add_option("--host", hostname, "Hostname");
|
||||||
|
|
||||||
CLI11_PARSE(app, argc, argv);
|
CLI11_PARSE(app, argc, argv);
|
||||||
|
|
||||||
// pid file handling
|
// pid file handling
|
||||||
@ -313,6 +317,10 @@ int main(int argc, char** argv)
|
|||||||
redisPassword, verbose,
|
redisPassword, verbose,
|
||||||
appsConfigPath);
|
appsConfigPath);
|
||||||
}
|
}
|
||||||
|
else if (app.got_subcommand("httpd"))
|
||||||
|
{
|
||||||
|
ret = ix::ws_httpd_main(port, hostname);
|
||||||
|
}
|
||||||
|
|
||||||
ix::uninitNetSystem();
|
ix::uninitNetSystem();
|
||||||
return ret;
|
return ret;
|
||||||
|
2
ws/ws.h
2
ws/ws.h
@ -93,4 +93,6 @@ namespace ix
|
|||||||
const std::string& redisPassword,
|
const std::string& redisPassword,
|
||||||
bool verbose,
|
bool verbose,
|
||||||
const std::string& appsConfigPath);
|
const std::string& appsConfigPath);
|
||||||
|
|
||||||
|
int ws_httpd_main(int port, const std::string& hostname);
|
||||||
} // namespace ix
|
} // namespace ix
|
||||||
|
Loading…
x
Reference in New Issue
Block a user