Clean up win32 server example.

This commit is contained in:
jmsgrogan 2023-01-10 09:28:15 +00:00
parent 5362b694e0
commit 2c825adc1d
23 changed files with 337 additions and 156 deletions

View file

@ -7,6 +7,7 @@
#include "SvgConverter.h" #include "SvgConverter.h"
#include "SvgWriter.h" #include "SvgWriter.h"
#include "SvgDocument.h"
#include "File.h" #include "File.h"

View file

@ -0,0 +1,28 @@
#include "BasicWebApp.h"
#include "FileLogger.h"
HttpResponse BasicWebApp::onHttpRequest(const HttpRequest& request)
{
const auto url = request.getPath();
HttpResponse response;
if (request.getVerb() == HttpRequest::Verb::GET)
{
MLOG_INFO("Got a GET request for: " << url);
response.setBody("Hey! You hit the server \r\n");
response.setStatusCode(200);
response.setResponseReason("OK");
}
else if (request.getVerb() == HttpRequest::Verb::POST)
{
MLOG_INFO("Got a POST request for: " << url);
}
else
{
MLOG_INFO("Got an unknown request for: " << url);
response.setStatusCode(503);
response.setResponseReason("Not Implemented");
}
return response;
}

11
src/console/BasicWebApp.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include "AbstractWebApp.h"
#include "HttpRequest.h"
#include "HttpResponse.h"
class BasicWebApp : public AbstractWebApp
{
public:
HttpResponse onHttpRequest(const HttpRequest& request) override;
};

View file

@ -1,6 +1,10 @@
list(APPEND console_HEADERS MainApplication.h) list(APPEND console_HEADERS
MainApplication.h
BasicWebApp.h)
list(APPEND console_LIB_INCLUDES MainApplication.cpp) list(APPEND console_LIB_INCLUDES
BasicWebApp.cpp
MainApplication.cpp)
add_library(console SHARED ${console_LIB_INCLUDES} ${console_HEADERS}) add_library(console SHARED ${console_LIB_INCLUDES} ${console_HEADERS})

View file

@ -13,6 +13,8 @@
#include "DiscretePoint.h" #include "DiscretePoint.h"
#include "Scene.h" #include "Scene.h"
#include "BasicWebApp.h"
#include <filesystem> #include <filesystem>
@ -118,7 +120,8 @@ void MainApplication::run()
void MainApplication::runServer() void MainApplication::runServer()
{ {
mNetworkManager->RunHttpServer(); BasicWebApp web_app;
mNetworkManager->runHttpServer(&web_app);
} }
void MainApplication::playAudio() void MainApplication::playAudio()
@ -151,7 +154,7 @@ void MainApplication::shutDown()
if (mNetworkManager) if (mNetworkManager)
{ {
mNetworkManager->ShutDown(); mNetworkManager->shutDown();
} }
MLOG_INFO("Shut down"); MLOG_INFO("Shut down");

View file

@ -14,6 +14,8 @@ list(APPEND core_HEADERS
file_utilities/PathUtils.h file_utilities/PathUtils.h
StringUtils.h StringUtils.h
http/HttpResponse.h http/HttpResponse.h
http/HttpHeader.h
http/HttpRequest.h
serializers/TomlReader.h serializers/TomlReader.h
) )

View file

@ -2,6 +2,23 @@
#include "StringUtils.h" #include "StringUtils.h"
HttpHeader::HttpHeader()
: mContentType("text / html"),
mHttpVersion("1.1")
{
}
std::string HttpHeader::getContentType() const
{
return mContentType;
}
std::string HttpHeader::getHttpVersion() const
{
return mHttpVersion;
}
void HttpHeader::parse(const std::vector<std::string >& message) void HttpHeader::parse(const std::vector<std::string >& message)
{ {
std::string tag; std::string tag;

View file

@ -7,10 +7,16 @@
class HttpHeader class HttpHeader
{ {
public: public:
HttpHeader();
void parse(const std::vector<std::string >& message); void parse(const std::vector<std::string >& message);
private: std::string getContentType() const;
std::string getHttpVersion() const;
private:
std::string mHttpVersion;
std::string mContentType;
std::string mHost; std::string mHost;
std::string mUserAgent; std::string mUserAgent;
std::string mAccept; std::string mAccept;

View file

@ -1,10 +1,8 @@
#include "HttpResponse.h" #include "HttpResponse.h"
HttpResponse::HttpResponse() HttpResponse::HttpResponse()
: mHttpVersion("1.1"), : mStatusCode(200),
mStatusCode(200),
mResponseReason("OK"), mResponseReason("OK"),
mContentType("text/plain"),
mBody() mBody()
{ {
@ -15,6 +13,11 @@ HttpResponse::~HttpResponse()
} }
const HttpHeader& HttpResponse::getHeader() const
{
return mHeader;
}
unsigned short HttpResponse::getStatusCode() const unsigned short HttpResponse::getStatusCode() const
{ {
return mStatusCode; return mStatusCode;
@ -37,13 +40,13 @@ unsigned HttpResponse::getBodyLength() const
std::string HttpResponse::getHeaderString() const std::string HttpResponse::getHeaderString() const
{ {
std::string header = "HTTP/" + mHttpVersion + " " + std::to_string(mStatusCode) + " " + mResponseReason + "\n"; std::string header = "HTTP/" + mHeader.getHttpVersion() + " " + std::to_string(mStatusCode) + " " + mResponseReason + "\n";
header += "Content-Type: " + mContentType + "\n"; header += "Content-Type: " + mHeader.getContentType() + "\n";
header += "Content-Length: " + std::to_string(getBodyLength()) + "\n"; header += "Content-Length: " + std::to_string(getBodyLength()) + "\n";
return header; return header;
} }
std::string HttpResponse::getResponseReason() const const std::string& HttpResponse::getResponseReason() const
{ {
return mResponseReason; return mResponseReason;
} }
@ -52,3 +55,13 @@ std::string HttpResponse::toString() const
{ {
return getHeaderString() + "\n\n" + mBody; return getHeaderString() + "\n\n" + mBody;
} }
void HttpResponse::setStatusCode(unsigned short code)
{
mStatusCode = code;
}
void HttpResponse::setResponseReason(const std::string& reason)
{
mResponseReason = reason;
}

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "HttpHeader.h"
#include <string> #include <string>
class HttpResponse class HttpResponse
@ -9,25 +11,29 @@ public:
~HttpResponse(); ~HttpResponse();
void setBody(const std::string& body);
unsigned getBodyLength() const; unsigned getBodyLength() const;
const std::string& getBody() const; const std::string& getBody() const;
const HttpHeader& getHeader() const;
std::string getHeaderString() const; std::string getHeaderString() const;
std::string toString() const; std::string toString() const;
unsigned short getStatusCode() const; unsigned short getStatusCode() const;
std::string getResponseReason() const; const std::string& getResponseReason() const;
void setStatusCode(unsigned short code);
void setResponseReason(const std::string& reason);
void setBody(const std::string& body);
private: private:
HttpHeader mHeader;
unsigned short mStatusCode{ 200 }; unsigned short mStatusCode{ 200 };
std::string mResponseReason{ }; std::string mResponseReason{ };
std::string mHttpVersion;
std::string mContentType;
std::string mBody; std::string mBody;
}; };

View file

@ -24,18 +24,19 @@ std::unique_ptr<NetworkManager> NetworkManager::Create()
return std::make_unique<NetworkManager>(); return std::make_unique<NetworkManager>();
} }
void NetworkManager::Initialize() void NetworkManager::initialize()
{ {
#ifdef __linux__ #ifdef __linux__
mSocketInterface = UnixSocketInterface::Create(); mSocketInterface = UnixSocketInterface::Create();
#endif #endif
} }
void NetworkManager::RunHttpServer() void NetworkManager::runHttpServer(AbstractWebApp* webApp)
{ {
#ifdef _WIN32 #ifdef _WIN32
Win32WebServer server; Win32WebServer server(webApp);
server.initialize(); server.initialize();
server.run();
#else #else
if (!mSocketInterface) if (!mSocketInterface)
{ {
@ -49,11 +50,11 @@ void NetworkManager::RunHttpServer()
#endif #endif
} }
void NetworkManager::RunHttpClient() void NetworkManager::runHttpClient()
{ {
if (!mSocketInterface) if (!mSocketInterface)
{ {
Initialize(); initialize();
} }
if (!mSocketInterface) if (!mSocketInterface)
@ -66,7 +67,7 @@ void NetworkManager::RunHttpClient()
mSocketInterface->Write(socket, "Hello Friend"); mSocketInterface->Write(socket, "Hello Friend");
} }
void NetworkManager::ShutDown() void NetworkManager::shutDown()
{ {
} }

View file

@ -6,6 +6,8 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
class AbstractWebApp;
class NetworkManager class NetworkManager
{ {
public: public:
@ -16,13 +18,13 @@ public:
static std::unique_ptr<NetworkManager> Create(); static std::unique_ptr<NetworkManager> Create();
void Initialize(); void initialize();
void RunHttpServer(); void runHttpServer(AbstractWebApp* webApp);
void RunHttpClient(); void runHttpClient();
void ShutDown(); void shutDown();
private: private:
std::vector<SocketPtr> mActiveSockets; std::vector<SocketPtr> mActiveSockets;

View file

@ -21,9 +21,9 @@ Win32Buffer::~Win32Buffer()
clearBuffer(); clearBuffer();
} }
PUCHAR Win32Buffer::getBufferAsUChar() const unsigned char* Win32Buffer::getBufferAsUChar() const
{ {
return reinterpret_cast<PUCHAR>(mBuffer); return reinterpret_cast<unsigned char*>(mBuffer);
} }
void* Win32Buffer::getBuffer() const void* Win32Buffer::getBuffer() const

View file

@ -9,7 +9,7 @@ public:
void* getBuffer() const; void* getBuffer() const;
PUCHAR getBufferAsUChar() const; unsigned char* getBufferAsUChar() const;
bool isValid() const; bool isValid() const;

View file

@ -2,6 +2,9 @@
#include "StringUtils.h" #include "StringUtils.h"
#include "HttpRequest.h" #include "HttpRequest.h"
#include "FileLogger.h"
#include "Win32TempFile.h"
Win32WebRequest::Win32WebRequest() Win32WebRequest::Win32WebRequest()
: mBuffer(DEFAULT_BUFFER_SIZE) : mBuffer(DEFAULT_BUFFER_SIZE)
@ -55,8 +58,10 @@ HttpRequest Win32WebRequest::getRequest() const
{ {
case HttpVerbGET: case HttpVerbGET:
verb = HttpRequest::Verb::GET; verb = HttpRequest::Verb::GET;
break;
case HttpVerbPOST: case HttpVerbPOST:
verb = HttpRequest::Verb::POST; verb = HttpRequest::Verb::POST;
break;
default: default:
verb = HttpRequest::Verb::UNKNOWN; verb = HttpRequest::Verb::UNKNOWN;
break; break;
@ -64,4 +69,48 @@ HttpRequest Win32WebRequest::getRequest() const
HttpRequest request(verb, getUrlFromRequest()); HttpRequest request(verb, getUrlFromRequest());
return request; return request;
}
bool Win32WebRequest::startReceiveEntity()
{
mEntityBuffer = std::make_unique<Win32Buffer>(ENTITY_BUFFER_SIZE);
if (!mEntityBuffer->isValid())
{
MLOG_ERROR("Failed to allocate entity buffer");
return false;
}
mTempFile = std::make_unique<Win32TempFile>();
if (!mTempFile->isValid())
{
MLOG_ERROR("Failed to create tempfile");
return false;
}
return true;
}
Win32Buffer* Win32WebRequest::getEntityBuffer() const
{
return mEntityBuffer.get();
}
unsigned Win32WebRequest::getEntityBufferSize() const
{
return ENTITY_BUFFER_SIZE;
}
Win32TempFile* Win32WebRequest::getTempFile() const
{
return mTempFile.get();
}
void Win32WebRequest::flushEntityBuffer(unsigned numBytes)
{
mEntityTotalSize += numBytes;
mTempFile->write(mEntityBuffer->getBufferAsUChar(), numBytes);
}
unsigned Win32WebRequest::getEntityTotalSize() const
{
return mEntityTotalSize;
} }

View file

@ -14,31 +14,49 @@
#include <http.h> #include <http.h>
#include <string> #include <string>
#include <memory>
#include "Win32Buffer.h" #include "Win32Buffer.h"
class HttpRequest; class HttpRequest;
class Win32TempFile;
class Win32WebRequest class Win32WebRequest
{ {
public: public:
Win32WebRequest(); Win32WebRequest();
bool isValid() const; HttpRequest getRequest() const;
PHTTP_REQUEST getHandle() const; PHTTP_REQUEST getHandle() const;
unsigned getBufferSize() const; unsigned getBufferSize() const;
Win32Buffer* getEntityBuffer() const;
unsigned getEntityBufferSize() const;
unsigned getEntityTotalSize() const;
void flushEntityBuffer(unsigned numBytes);
Win32TempFile* getTempFile() const;
bool isValid() const;
void resizeBuffer(unsigned size); void resizeBuffer(unsigned size);
void zeroBufferMemory(); void zeroBufferMemory();
HttpRequest getRequest() const; bool startReceiveEntity();
private: private:
std::string getUrlFromRequest() const; std::string getUrlFromRequest() const;
static const unsigned ENTITY_BUFFER_SIZE{ 2048 };
std::unique_ptr<Win32Buffer> mEntityBuffer;
std::unique_ptr<Win32TempFile> mTempFile;
unsigned mEntityTotalSize{ 0 };
static const unsigned DEFAULT_BUFFER_SIZE{ sizeof(HTTP_REQUEST) + 2048 }; static const unsigned DEFAULT_BUFFER_SIZE{ sizeof(HTTP_REQUEST) + 2048 };
Win32Buffer mBuffer; Win32Buffer mBuffer;

View file

@ -1,34 +1,60 @@
#include "Win32WebResponse.h" #include "Win32WebResponse.h"
#include "HttpResponse.h" #include "HttpResponse.h"
#include "Win32WebRequest.h"
#include "FileLogger.h"
Win32WebResponse::Win32WebResponse(const HttpResponse& response) Win32WebResponse::Win32WebResponse(const HttpResponse& response)
{ {
RtlZeroMemory((&mResponse), sizeof(*(&mResponse))); RtlZeroMemory((&mResponse), sizeof(*(&mResponse)));
mResponse.StatusCode = response.getStatusCode(); mResponse.StatusCode = response.getStatusCode();
std::string reason = response.getResponseReason(); mResponseReason = response.getResponseReason();
mResponse.pReason = reason.c_str(); mResponse.pReason = mResponseReason.c_str();
mResponse.ReasonLength = (USHORT)strlen(reason.c_str()); mResponse.ReasonLength = (USHORT)strlen(mResponseReason.c_str());
const std::string content_type = "text / html"; populateHeader(response);
mResponse.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = content_type.c_str();
mResponse.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)strlen(content_type.c_str());
auto body = response.getBody(); populateBody(response);
if (!body.empty()) }
HTTP_RESPONSE& Win32WebResponse::getResponse()
{
return mResponse;
}
void Win32WebResponse::populateBody(const HttpResponse& response)
{
mBody = response.getBody();
if (!mBody.empty())
{ {
mContentLength = std::to_string(mBody.size());
mResponse.Headers.KnownHeaders[HttpHeaderContentLength].pRawValue = mContentLength.c_str();
mResponse.Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength = (USHORT)strlen(mContentLength.c_str());
HTTP_DATA_CHUNK dataChunk; HTTP_DATA_CHUNK dataChunk;
dataChunk.DataChunkType = HttpDataChunkFromMemory; dataChunk.DataChunkType = HttpDataChunkFromMemory;
dataChunk.FromMemory.pBuffer = body.data(); dataChunk.FromMemory.pBuffer = mBody.data();
dataChunk.FromMemory.BufferLength = (ULONG)strlen(body.data()); dataChunk.FromMemory.BufferLength = (ULONG)strlen(mBody.data());
mResponse.EntityChunkCount = 1; mResponse.EntityChunkCount = 1;
mResponse.pEntityChunks = &dataChunk; mResponse.pEntityChunks = &dataChunk;
} }
} }
HTTP_RESPONSE& Win32WebResponse::getResponse() void Win32WebResponse::populateHeader(const HttpResponse& response)
{ {
return mResponse; mContentType = response.getHeader().getContentType();
mResponse.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = mContentType.c_str();
mResponse.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)strlen(mContentType.c_str());
}
void Win32WebResponse::addRequestContentLength(const Win32WebRequest& request)
{
mContentLength = std::to_string(request.getEntityTotalSize());
mResponse.Headers.KnownHeaders[HttpHeaderContentLength].pRawValue = mContentLength.c_str();
mResponse.Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength = (USHORT)strlen(mContentLength.c_str());
} }

View file

@ -17,6 +17,7 @@
#include <string> #include <string>
class HttpResponse; class HttpResponse;
class Win32WebRequest;
class Win32WebResponse class Win32WebResponse
{ {
@ -25,6 +26,16 @@ public:
HTTP_RESPONSE& getResponse(); HTTP_RESPONSE& getResponse();
void addRequestContentLength(const Win32WebRequest& request);
private: private:
void populateBody(const HttpResponse& response);
void populateHeader(const HttpResponse& response);
std::string mResponseReason;
std::string mContentType;
std::string mBody;
std::string mContentLength;
HTTP_RESPONSE mResponse; HTTP_RESPONSE mResponse;
}; };

View file

@ -12,7 +12,7 @@
#include "StringUtils.h" #include "StringUtils.h"
Win32WebServer::Win32WebServer(AbstractWebApp* webApp) Win32WebServer::Win32WebServer(AbstractWebApp* webApp)
: mListenUrl("http://localhost:80/49152"), : mListenUrl("http://localhost:49153/"),
mWebApp(webApp) mWebApp(webApp)
{ {
@ -64,19 +64,66 @@ void Win32WebServer::initialize()
} }
} }
DWORD Win32WebServer::onRequest(const Win32WebRequest& request) bool Win32WebServer::onPostRequest(Win32WebRequest& request)
{ {
auto app_request = request.getRequest(); if (request.getHandle()->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS)
auto response = mWebApp->onHttpRequest(app_request); {
if (!request.startReceiveEntity())
{
return false;
}
DWORD result; ULONG bytes_read = 0;
do
{
bytes_read = 0;
auto result = ::HttpReceiveRequestEntityBody(mWorkingQueue, request.getHandle()->RequestId, 0, request.getEntityBuffer()->getBuffer(),
request.getEntityBufferSize(), &bytes_read, nullptr);
if (result == NO_ERROR || result == ERROR_HANDLE_EOF)
{
request.flushEntityBuffer(bytes_read);
if (result == ERROR_HANDLE_EOF)
{
return true;
}
}
else
{
MLOG_ERROR("HttpReceiveRequestEntityBody failed with: " << result);
return false;
}
} while (true);
}
return true;
}
bool Win32WebServer::onRequest(Win32WebRequest& request)
{
if (request.getHandle()->Verb == HttpVerbPOST)
{
if (!onPostRequest(request))
{
return false;
}
}
const auto app_request = request.getRequest();
const auto response = mWebApp->onHttpRequest(app_request);
if (app_request.getVerb() == HttpRequest::Verb::POST) if (app_request.getVerb() == HttpRequest::Verb::POST)
{ {
result = sendHttpPostResponse(request.getHandle()); if (!sendHttpPostResponse(request, response))
{
return false;
}
} }
else else
{ {
result = sendHttpResponse(request.getHandle(), response); if (!sendHttpResponse(request, response))
{
return false;
}
} }
/* /*
@ -94,123 +141,57 @@ DWORD Win32WebServer::onRequest(const Win32WebRequest& request)
break; break;
*/ */
return result; return true;
} }
DWORD Win32WebServer::sendHttpResponse(PHTTP_REQUEST pRequest, const HttpResponse& appResponse) bool Win32WebServer::sendHttpResponse(const Win32WebRequest& request, const HttpResponse& appResponse)
{ {
Win32WebResponse response(appResponse); Win32WebResponse response(appResponse);
DWORD bytesSent; DWORD bytesSent;
const auto result = ::HttpSendHttpResponse(mWorkingQueue, pRequest->RequestId, 0, &(response.getResponse()), NULL, &bytesSent, NULL, 0, NULL, NULL); const auto result = ::HttpSendHttpResponse(mWorkingQueue, request.getHandle()->RequestId, 0, &(response.getResponse()), NULL, &bytesSent, NULL, 0, NULL, NULL);
if (result != NO_ERROR) if (result != NO_ERROR)
{ {
MLOG_ERROR("Http response failed with error: " << result); MLOG_ERROR("Http response failed with error: " << result);
} }
return result; return result == NO_ERROR;
} }
#define MAX_ULONG_STR ((ULONG) sizeof("4294967295")) bool Win32WebServer::sendHttpPostResponse(const Win32WebRequest& request, const HttpResponse& appResponse)
DWORD Win32WebServer::sendHttpPostResponse(PHTTP_REQUEST pRequest)
{ {
// Allocate space for an entity buffer. Buffer can be increased on demand.
const ULONG entity_buffer_length = 2048;
Win32Buffer entity_buffer(entity_buffer_length);
if (!entity_buffer.isValid())
{
return ERROR_NOT_ENOUGH_MEMORY;
}
HTTP_RESPONSE response;
initializeHttpResponse(response, 200, "OK");
DWORD result{ 0 }; DWORD result{ 0 };
if (pRequest->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS) if (request.getEntityBuffer())
{ {
Win32TempFile temp_file; Win32WebResponse response(appResponse);
if (!temp_file.isValid()) response.addRequestContentLength(request);
{
return 0;
}
ULONG total_bytes_read = 0;
ULONG bytes_read = 0;
do
{
// Read the entity chunk from the request.
bytes_read = 0;
result = ::HttpReceiveRequestEntityBody(mWorkingQueue, pRequest->RequestId, 0, entity_buffer.getBuffer(), entity_buffer_length, &bytes_read, nullptr);
switch (result)
{
case NO_ERROR:
if (bytes_read != 0)
{
total_bytes_read += bytes_read;
temp_file.write(entity_buffer.getBufferAsUChar(), bytes_read);
}
break;
case ERROR_HANDLE_EOF:
// The last request entity body has been read. Send back a response.
//
// To illustrate entity sends via HttpSendResponseEntityBody, the response will
// be sent over multiple calls. To do this, pass the HTTP_SEND_RESPONSE_FLAG_MORE_DATA flag.
if (bytes_read != 0)
{
total_bytes_read += bytes_read;
temp_file.write(entity_buffer.getBufferAsUChar(), bytes_read);
}
// Because the response is sent over multiple API calls, add a content-length.
// Alternatively, the response could have been sent using chunked transfer encoding, by passimg "Transfer-Encoding: Chunked".
// NOTE: Because the TotalBytesread in a ULONG are accumulated, this will not work for entity bodies larger than 4 GB.
// For support of large entity bodies, use a ULONGLONG.
CHAR szContentLength[MAX_ULONG_STR];
sprintf_s(szContentLength, MAX_ULONG_STR, "%lu", total_bytes_read);
response.Headers.KnownHeaders[HttpHeaderContentLength].pRawValue = szContentLength;
response.Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength = (USHORT)strlen(szContentLength);
DWORD bytesSent;
result = ::HttpSendHttpResponse(mWorkingQueue, pRequest->RequestId, HTTP_SEND_RESPONSE_FLAG_MORE_DATA, &response, NULL, &bytesSent, NULL, 0, NULL, NULL);
if (result != NO_ERROR)
{
MLOG_ERROR("HttpSendHttpResponse failed with: " << result);
return;
}
// Send entity body from a file handle.
HTTP_DATA_CHUNK dataChunk;
dataChunk.DataChunkType = HttpDataChunkFromFileHandle;
dataChunk.FromFileHandle.ByteRange.StartingOffset.QuadPart = 0;
dataChunk.FromFileHandle.ByteRange.Length.QuadPart = HTTP_BYTE_RANGE_TO_EOF;
dataChunk.FromFileHandle.FileHandle = temp_file.getHandle();
result = ::HttpSendResponseEntityBody(mWorkingQueue, pRequest->RequestId, 0, 1, &dataChunk, NULL, NULL, 0, NULL, NULL);
if (result != NO_ERROR)
{
MLOG_ERROR("HttpSendResponseEntityBody failed" << result);
}
break;
default:
MLOG_ERROR("HttpReceiveRequestEntityBody failed with: " << result);
break;
}
} while (true);
}
else
{
DWORD bytesSent; DWORD bytesSent;
result = ::HttpSendHttpResponse(mWorkingQueue, pRequest->RequestId, 0, &response, NULL, &bytesSent, NULL, 0, NULL, NULL ); result = ::HttpSendHttpResponse(mWorkingQueue, request.getHandle()->RequestId, HTTP_SEND_RESPONSE_FLAG_MORE_DATA, &(response.getResponse()), NULL, &bytesSent, NULL, 0, NULL, NULL);
if (result != NO_ERROR) if (result != NO_ERROR)
{ {
MLOG_ERROR("HttpSendHttpResponse failed with: " << result); MLOG_ERROR("HttpSendHttpResponse failed with: " << result);
return false;
}
// Send entity body from a file handle.
HTTP_DATA_CHUNK dataChunk;
dataChunk.DataChunkType = HttpDataChunkFromFileHandle;
dataChunk.FromFileHandle.ByteRange.StartingOffset.QuadPart = 0;
dataChunk.FromFileHandle.ByteRange.Length.QuadPart = HTTP_BYTE_RANGE_TO_EOF;
dataChunk.FromFileHandle.FileHandle = request.getTempFile()->getHandle();
result = ::HttpSendResponseEntityBody(mWorkingQueue, request.getHandle()->RequestId, 0, 1, &dataChunk, NULL, NULL, 0, NULL, NULL);
if (result != NO_ERROR)
{
MLOG_ERROR("HttpSendResponseEntityBody failed" << result);
return false;
} }
} }
return result; else
{
result = sendHttpResponse(request, appResponse);
}
return result == NO_ERROR;;
} }
void Win32WebServer::run() void Win32WebServer::run()
@ -232,8 +213,7 @@ void Win32WebServer::run()
auto result = ::HttpReceiveHttpRequest(mWorkingQueue, request_id, 0, request.getHandle(), request.getBufferSize(), &bytes_read, nullptr); auto result = ::HttpReceiveHttpRequest(mWorkingQueue, request_id, 0, request.getHandle(), request.getBufferSize(), &bytes_read, nullptr);
if (NO_ERROR == result) if (NO_ERROR == result)
{ {
result = onRequest(request); if (!onRequest(request))
if (result != NO_ERROR)
{ {
break; break;
} }

View file

@ -18,7 +18,6 @@
class AbstractWebApp; class AbstractWebApp;
class Win32WebRequest; class Win32WebRequest;
class HttpResponse; class HttpResponse;
class Win32WebServer class Win32WebServer
@ -35,10 +34,11 @@ public:
void run(); void run();
private: private:
DWORD onRequest(const Win32WebRequest& request); bool onRequest(Win32WebRequest& request);
bool onPostRequest(Win32WebRequest& request);
DWORD sendHttpResponse(PHTTP_REQUEST pRequest, const HttpResponse& response); bool sendHttpResponse(const Win32WebRequest& request, const HttpResponse& response);
DWORD sendHttpPostResponse(PHTTP_REQUEST pRequest); bool sendHttpPostResponse(const Win32WebRequest& request, const HttpResponse& response);
AbstractWebApp* mWebApp{ nullptr }; AbstractWebApp* mWebApp{ nullptr };

View file

@ -9,9 +9,9 @@ std::string HttpMessageHandler::onMessage(const std::string& message)
request.parseMessage(message); request.parseMessage(message);
HttpResponse response; HttpResponse response;
response.SetBody("Hello world!"); response.setBody("Hello world!");
const auto response_message = response.ToString(); const auto response_message = response.toString();
return response_message; return response_message;
} }

View file

@ -8,5 +8,5 @@ TEST_CASE(TestNetworkManagerClient, "network")
{ {
auto network_manager = NetworkManager::Create(); auto network_manager = NetworkManager::Create();
network_manager->RunHttpClient(); network_manager->runHttpClient();
} }

View file

@ -2,9 +2,12 @@
#include "TestFramework.h" #include "TestFramework.h"
#include "BasicWebApp.h"
TEST_CASE(TestWin32WebServer, "network") TEST_CASE(TestWin32WebServer, "network")
{ {
auto network_manager = NetworkManager::Create(); auto network_manager = NetworkManager::Create();
network_manager->RunHttpServer(); BasicWebApp web_app;
network_manager->runHttpServer(&web_app);
} }