Initial quantum compute and cleaning up win server.
This commit is contained in:
parent
af50eea208
commit
5362b694e0
45 changed files with 884 additions and 429 deletions
|
@ -1,4 +1,5 @@
|
||||||
add_subdirectory(circuits)
|
add_subdirectory(circuits)
|
||||||
|
add_subdirectory(math)
|
||||||
add_subdirectory(machine_learning)
|
add_subdirectory(machine_learning)
|
||||||
add_subdirectory(physics_simulation)
|
add_subdirectory(physics_simulation)
|
||||||
add_subdirectory(quantum_computing)
|
add_subdirectory(quantum_computing)
|
||||||
|
|
12
plugins/math/CMakeLists.txt
Normal file
12
plugins/math/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
set(PLUGIN_NAME ntk_math)
|
||||||
|
|
||||||
|
list(APPEND math_HEADERS ComplexNumber.h)
|
||||||
|
|
||||||
|
list(APPEND math_LIB_INCLUDES ComplexNumber.cpp)
|
||||||
|
|
||||||
|
add_library(${PLUGIN_NAME} SHARED ${math_LIB_INCLUDES} ${math_HEADERS})
|
||||||
|
|
||||||
|
target_include_directories(${PLUGIN_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_link_libraries(${PLUGIN_NAME} PUBLIC core)
|
||||||
|
set_property(TARGET ${PLUGIN_NAME} PROPERTY FOLDER plugins)
|
||||||
|
set_target_properties( ${PLUGIN_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
28
plugins/math/ComplexNumber.cpp
Normal file
28
plugins/math/ComplexNumber.cpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#include "ComplexNumber.h"
|
||||||
|
|
||||||
|
ComplexNumber::ComplexNumber(double real, double imaginary)
|
||||||
|
: mReal(real),
|
||||||
|
mImaginary(imaginary)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
double ComplexNumber::getReal() const
|
||||||
|
{
|
||||||
|
return mReal;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ComplexNumber::getImaginary() const
|
||||||
|
{
|
||||||
|
return mImaginary;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComplexNumber::setReal(double value)
|
||||||
|
{
|
||||||
|
mReal = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComplexNumber::setImaginary(double value)
|
||||||
|
{
|
||||||
|
mImaginary = value;
|
||||||
|
}
|
19
plugins/math/ComplexNumber.h
Normal file
19
plugins/math/ComplexNumber.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class ComplexNumber
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ComplexNumber(double real = 0.0, double imaginary = 0.0);
|
||||||
|
|
||||||
|
double getReal() const;
|
||||||
|
|
||||||
|
double getImaginary() const;
|
||||||
|
|
||||||
|
void setReal(double value);
|
||||||
|
|
||||||
|
void setImaginary(double value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
double mReal{ 0.0 };
|
||||||
|
double mImaginary{ 0.0 };
|
||||||
|
};
|
|
@ -1,15 +1,2 @@
|
||||||
set(PLUGIN_NAME quantum_computing)
|
add_subdirectory(src)
|
||||||
|
add_subdirectory(test)
|
||||||
list(APPEND client_HEADERS
|
|
||||||
QuantumCircuit.h)
|
|
||||||
|
|
||||||
list(APPEND client_LIB_INCLUDES
|
|
||||||
QuantumCircuit.cpp)
|
|
||||||
|
|
||||||
add_library(${PLUGIN_NAME} SHARED ${client_LIB_INCLUDES})
|
|
||||||
|
|
||||||
target_include_directories(${PLUGIN_NAME} PUBLIC
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
target_link_libraries(${PLUGIN_NAME} PUBLIC core)
|
|
||||||
set_property(TARGET ${PLUGIN_NAME} PROPERTY FOLDER plugins)
|
|
||||||
|
|
12
plugins/quantum_computing/src/BlochSphere.cpp
Normal file
12
plugins/quantum_computing/src/BlochSphere.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "BlochSphere.h"
|
||||||
|
|
||||||
|
BlochSphere::BlochSphere(const Qubit& state)
|
||||||
|
: mState(state)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const Qubit& BlochSphere::getState() const
|
||||||
|
{
|
||||||
|
return mState;
|
||||||
|
}
|
13
plugins/quantum_computing/src/BlochSphere.h
Normal file
13
plugins/quantum_computing/src/BlochSphere.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Qubit.h"
|
||||||
|
|
||||||
|
class BlochSphere
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BlochSphere(const Qubit& state);
|
||||||
|
|
||||||
|
const Qubit& getState() const;
|
||||||
|
private:
|
||||||
|
Qubit mState;
|
||||||
|
};
|
30
plugins/quantum_computing/src/CMakeLists.txt
Normal file
30
plugins/quantum_computing/src/CMakeLists.txt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
set(PLUGIN_NAME quantum_computing)
|
||||||
|
|
||||||
|
list(APPEND quantum_computing_HEADERS
|
||||||
|
QuantumCircuit.h
|
||||||
|
BlochSphere.h
|
||||||
|
QuantumState.h
|
||||||
|
Qubit.h
|
||||||
|
QuantumGate.h
|
||||||
|
QuantumOperator.h
|
||||||
|
visuals/BlochSphereNode.h
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND quantum_computing_LIB_INCLUDES
|
||||||
|
QuantumCircuit.cpp
|
||||||
|
BlochSphere.cpp
|
||||||
|
QuantumState.cpp
|
||||||
|
Qubit.cpp
|
||||||
|
QuantumGate.cpp
|
||||||
|
QuantumOperator.cpp
|
||||||
|
visuals/BlochSphereNode.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(${PLUGIN_NAME} SHARED ${quantum_computing_LIB_INCLUDES} ${quantum_computing_HEADERS})
|
||||||
|
|
||||||
|
target_include_directories(${PLUGIN_NAME} PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/visuals
|
||||||
|
)
|
||||||
|
target_link_libraries(${PLUGIN_NAME} PUBLIC core visual_elements ntk_math)
|
||||||
|
set_property(TARGET ${PLUGIN_NAME} PROPERTY FOLDER plugins)
|
0
plugins/quantum_computing/src/QuantumGate.cpp
Normal file
0
plugins/quantum_computing/src/QuantumGate.cpp
Normal file
0
plugins/quantum_computing/src/QuantumGate.h
Normal file
0
plugins/quantum_computing/src/QuantumGate.h
Normal file
0
plugins/quantum_computing/src/QuantumOperator.cpp
Normal file
0
plugins/quantum_computing/src/QuantumOperator.cpp
Normal file
0
plugins/quantum_computing/src/QuantumOperator.h
Normal file
0
plugins/quantum_computing/src/QuantumOperator.h
Normal file
0
plugins/quantum_computing/src/QuantumState.cpp
Normal file
0
plugins/quantum_computing/src/QuantumState.cpp
Normal file
0
plugins/quantum_computing/src/QuantumState.h
Normal file
0
plugins/quantum_computing/src/QuantumState.h
Normal file
18
plugins/quantum_computing/src/Qubit.cpp
Normal file
18
plugins/quantum_computing/src/Qubit.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "Qubit.h"
|
||||||
|
|
||||||
|
Qubit::Qubit(const ComplexNumber& alpha, const ComplexNumber& beta)
|
||||||
|
: mAlpha(alpha),
|
||||||
|
mBeta(beta)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const ComplexNumber& Qubit::getAlpha() const
|
||||||
|
{
|
||||||
|
return mAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ComplexNumber& Qubit::getBeta() const
|
||||||
|
{
|
||||||
|
return mBeta;
|
||||||
|
}
|
16
plugins/quantum_computing/src/Qubit.h
Normal file
16
plugins/quantum_computing/src/Qubit.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ComplexNumber.h"
|
||||||
|
|
||||||
|
class Qubit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Qubit(const ComplexNumber& alpha, const ComplexNumber& beta);
|
||||||
|
|
||||||
|
const ComplexNumber& getAlpha() const;
|
||||||
|
|
||||||
|
const ComplexNumber& getBeta() const;
|
||||||
|
private:
|
||||||
|
ComplexNumber mAlpha;
|
||||||
|
ComplexNumber mBeta;
|
||||||
|
};
|
40
plugins/quantum_computing/src/visuals/BlochSphereNode.cpp
Normal file
40
plugins/quantum_computing/src/visuals/BlochSphereNode.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "BlochSphereNode.h"
|
||||||
|
|
||||||
|
#include "CircleNode.h"
|
||||||
|
|
||||||
|
BlochSphereNode::BlochSphereNode(const DiscretePoint& location)
|
||||||
|
: AbstractVisualNode(location, "BlochSphereNode")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlochSphereNode::setContent(BlochSphere* content)
|
||||||
|
{
|
||||||
|
mContent = content;
|
||||||
|
mContentDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlochSphereNode::setSize(double size)
|
||||||
|
{
|
||||||
|
if (size != mSize)
|
||||||
|
{
|
||||||
|
mSize = size;
|
||||||
|
mContentDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlochSphereNode::update(FontsManager* fontsManager)
|
||||||
|
{
|
||||||
|
if (!mContentDirty)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mChildren.clear();
|
||||||
|
|
||||||
|
auto loc = DiscretePoint(mSize / 2.0, mSize / 2.0);
|
||||||
|
mOuterCircle = std::make_unique<CircleNode>(loc, mSize/2.0);
|
||||||
|
|
||||||
|
addChild(mOuterCircle.get());
|
||||||
|
|
||||||
|
}
|
34
plugins/quantum_computing/src/visuals/BlochSphereNode.h
Normal file
34
plugins/quantum_computing/src/visuals/BlochSphereNode.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AbstractVisualNode.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class BlochSphere;
|
||||||
|
class CircleNode;
|
||||||
|
class LineNode;
|
||||||
|
|
||||||
|
class BlochSphereNode : public AbstractVisualNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BlochSphereNode(const DiscretePoint& location);
|
||||||
|
|
||||||
|
void setContent(BlochSphere* content);
|
||||||
|
|
||||||
|
void update(FontsManager* fontsManager) override;
|
||||||
|
|
||||||
|
void setSize(double size);
|
||||||
|
private:
|
||||||
|
double mSize{ 1.0 };
|
||||||
|
bool mContentDirty{ true };
|
||||||
|
BlochSphere* mContent{ nullptr };
|
||||||
|
|
||||||
|
std::unique_ptr<CircleNode> mOuterCircle;
|
||||||
|
std::unique_ptr<CircleNode> mInnerCircle;
|
||||||
|
std::unique_ptr<CircleNode> mCentreCircle;
|
||||||
|
std::unique_ptr<CircleNode> mStateMarkerCircle;
|
||||||
|
std::unique_ptr<LineNode> mXAxis;
|
||||||
|
std::unique_ptr<LineNode> mYAxis;
|
||||||
|
std::unique_ptr<LineNode> mZAxis;
|
||||||
|
std::unique_ptr<LineNode> mStateVector;
|
||||||
|
};
|
8
plugins/quantum_computing/test/CMakeLists.txt
Normal file
8
plugins/quantum_computing/test/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
list(APPEND UNIT_TEST_FILES
|
||||||
|
TestBlochSphereNode.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(quantum_computing_unit_tests ${CMAKE_SOURCE_DIR}/test/test_runner.cpp ${UNIT_TEST_FILES})
|
||||||
|
target_link_libraries(quantum_computing_unit_tests PUBLIC test_utils quantum_computing)
|
||||||
|
set_property(TARGET quantum_computing_unit_tests PROPERTY FOLDER plugins)
|
35
plugins/quantum_computing/test/TestBlochSphereNode.cpp
Normal file
35
plugins/quantum_computing/test/TestBlochSphereNode.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include "TestFramework.h"
|
||||||
|
#include "TestUtils.h"
|
||||||
|
|
||||||
|
#include "BlochSphereNode.h"
|
||||||
|
#include "BlochSphere.h"
|
||||||
|
#include "Scene.h"
|
||||||
|
|
||||||
|
#include "SvgConverter.h"
|
||||||
|
#include "SvgWriter.h"
|
||||||
|
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
TEST_CASE(TestBlochSphereNode, "quantum_computing")
|
||||||
|
{
|
||||||
|
auto node = std::make_unique<BlochSphereNode>();
|
||||||
|
|
||||||
|
Qubit state({ 1.0, 0.0 }, { 0.0, 0.0 });
|
||||||
|
|
||||||
|
auto bloch_sphere = std::make_unique<BlochSphere>(state);
|
||||||
|
|
||||||
|
node->setContent(bloch_sphere.get());
|
||||||
|
|
||||||
|
auto scene = std::make_unique<Scene>();
|
||||||
|
scene->addNode(node.get());
|
||||||
|
scene->update();
|
||||||
|
|
||||||
|
SvgConverter converter;
|
||||||
|
auto svg_document = converter.convert(scene.get());
|
||||||
|
|
||||||
|
SvgWriter writer;
|
||||||
|
auto svg_content = writer.toString(svg_document.get());
|
||||||
|
|
||||||
|
File svg_file(TestUtils::getTestOutputDir(__FILE__) / "bloch_sphere.svg");
|
||||||
|
svg_file.writeText(svg_content);
|
||||||
|
}
|
0
plugins/quantum_computing/test/TestBlochSphereNode.h
Normal file
0
plugins/quantum_computing/test/TestBlochSphereNode.h
Normal file
12
src/core/AbstractWebApp.h
Normal file
12
src/core/AbstractWebApp.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AbstractApp.h"
|
||||||
|
|
||||||
|
class HttpRequest;
|
||||||
|
class HttpResponse;
|
||||||
|
|
||||||
|
class AbstractWebApp : public AbstractApp
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual HttpResponse onHttpRequest(const HttpRequest& request) = 0;
|
||||||
|
};
|
|
@ -2,6 +2,7 @@ set(MODULE_NAME core)
|
||||||
|
|
||||||
list(APPEND core_HEADERS
|
list(APPEND core_HEADERS
|
||||||
AbstractApp.h
|
AbstractApp.h
|
||||||
|
AbstractWebApp.h
|
||||||
Dictionary.h
|
Dictionary.h
|
||||||
Event.h
|
Event.h
|
||||||
Color.h
|
Color.h
|
||||||
|
|
|
@ -4,6 +4,23 @@
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
HttpRequest::HttpRequest(Verb verb, const std::string& path)
|
||||||
|
: mVerb(verb),
|
||||||
|
mPath(path)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest::Verb HttpRequest::getVerb() const
|
||||||
|
{
|
||||||
|
return mVerb;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HttpRequest::getPath() const
|
||||||
|
{
|
||||||
|
return mPath;
|
||||||
|
}
|
||||||
|
|
||||||
void HttpRequest::parseMessage(const std::string& message)
|
void HttpRequest::parseMessage(const std::string& message)
|
||||||
{
|
{
|
||||||
std::stringstream ss(message);
|
std::stringstream ss(message);
|
||||||
|
|
|
@ -7,13 +7,31 @@
|
||||||
class HttpRequest
|
class HttpRequest
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum class Verb
|
||||||
|
{
|
||||||
|
GET,
|
||||||
|
PUT,
|
||||||
|
POST,
|
||||||
|
PATCH,
|
||||||
|
_DELETE,
|
||||||
|
UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
HttpRequest() = default;
|
HttpRequest() = default;
|
||||||
|
|
||||||
|
HttpRequest(Verb verb, const std::string& path);
|
||||||
|
|
||||||
|
Verb getVerb() const;
|
||||||
|
|
||||||
|
std::string getPath() const;
|
||||||
|
|
||||||
void parseMessage(const std::string& message);
|
void parseMessage(const std::string& message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseFirstLine(const std::string& line);
|
void parseFirstLine(const std::string& line);
|
||||||
|
|
||||||
|
Verb mVerb = Verb::UNKNOWN;
|
||||||
HttpHeader mHeader;
|
HttpHeader mHeader;
|
||||||
std::string mMethod;
|
std::string mMethod;
|
||||||
std::string mPath;
|
std::string mPath;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#include "HttpResponse.h"
|
#include "HttpResponse.h"
|
||||||
|
|
||||||
HttpResponse::HttpResponse()
|
HttpResponse::HttpResponse()
|
||||||
:mHttpVersion("1.1"),
|
: mHttpVersion("1.1"),
|
||||||
mResponseCode("200 OK"),
|
mStatusCode(200),
|
||||||
|
mResponseReason("OK"),
|
||||||
mContentType("text/plain"),
|
mContentType("text/plain"),
|
||||||
mBody()
|
mBody()
|
||||||
{
|
{
|
||||||
|
@ -14,25 +15,40 @@ HttpResponse::~HttpResponse()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpResponse::SetBody(const std::string& body)
|
unsigned short HttpResponse::getStatusCode() const
|
||||||
|
{
|
||||||
|
return mStatusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& HttpResponse::getBody() const
|
||||||
|
{
|
||||||
|
return mBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpResponse::setBody(const std::string& body)
|
||||||
{
|
{
|
||||||
mBody = body;
|
mBody = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned HttpResponse::GetBodyLength() const
|
unsigned HttpResponse::getBodyLength() const
|
||||||
{
|
{
|
||||||
return unsigned(mBody.length());
|
return unsigned(mBody.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string HttpResponse::GetHeaderString() const
|
std::string HttpResponse::getHeaderString() const
|
||||||
{
|
{
|
||||||
std::string header = "HTTP/" + mHttpVersion + " " + mResponseCode + "\n";
|
std::string header = "HTTP/" + mHttpVersion + " " + std::to_string(mStatusCode) + " " + mResponseReason + "\n";
|
||||||
header += "Content-Type: " + mContentType + "\n";
|
header += "Content-Type: " + mContentType + "\n";
|
||||||
header += "Content-Length: " + std::to_string(GetBodyLength()) + "\n";
|
header += "Content-Length: " + std::to_string(getBodyLength()) + "\n";
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string HttpResponse::ToString() const
|
std::string HttpResponse::getResponseReason() const
|
||||||
{
|
{
|
||||||
return GetHeaderString() + "\n\n" + mBody;
|
return mResponseReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HttpResponse::toString() const
|
||||||
|
{
|
||||||
|
return getHeaderString() + "\n\n" + mBody;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,25 @@ public:
|
||||||
|
|
||||||
~HttpResponse();
|
~HttpResponse();
|
||||||
|
|
||||||
void SetBody(const std::string& body);
|
void setBody(const std::string& body);
|
||||||
|
|
||||||
unsigned GetBodyLength() const;
|
unsigned getBodyLength() const;
|
||||||
|
|
||||||
std::string GetHeaderString() const;
|
const std::string& getBody() const;
|
||||||
|
|
||||||
std::string ToString() const;
|
std::string getHeaderString() const;
|
||||||
|
|
||||||
|
std::string toString() const;
|
||||||
|
|
||||||
|
unsigned short getStatusCode() const;
|
||||||
|
|
||||||
|
std::string getResponseReason() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
unsigned short mStatusCode{ 200 };
|
||||||
|
std::string mResponseReason{ };
|
||||||
|
|
||||||
std::string mHttpVersion;
|
std::string mHttpVersion;
|
||||||
std::string mResponseCode;
|
|
||||||
std::string mContentType;
|
std::string mContentType;
|
||||||
std::string mBody;
|
std::string mBody;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,8 @@ list(APPEND geometry_LIB_INCLUDES
|
||||||
Linalg.cpp
|
Linalg.cpp
|
||||||
Line.cpp
|
Line.cpp
|
||||||
LineSegment.cpp
|
LineSegment.cpp
|
||||||
|
Matrix.h
|
||||||
|
Matrix.cpp
|
||||||
Path.h
|
Path.h
|
||||||
Path.cpp
|
Path.cpp
|
||||||
Point.h
|
Point.h
|
||||||
|
@ -28,8 +30,7 @@ list(APPEND geometry_LIB_INCLUDES
|
||||||
# add the library
|
# add the library
|
||||||
add_library(geometry SHARED ${geometry_LIB_INCLUDES})
|
add_library(geometry SHARED ${geometry_LIB_INCLUDES})
|
||||||
|
|
||||||
target_include_directories(geometry PUBLIC
|
target_include_directories(geometry PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}")
|
|
||||||
|
|
||||||
set_target_properties( geometry PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
set_target_properties( geometry PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||||
set_property(TARGET geometry PROPERTY FOLDER src)
|
set_property(TARGET geometry PROPERTY FOLDER src)
|
||||||
|
|
0
src/geometry/Matrix.cpp
Normal file
0
src/geometry/Matrix.cpp
Normal file
0
src/geometry/Matrix.h
Normal file
0
src/geometry/Matrix.h
Normal file
|
@ -7,7 +7,16 @@ list(APPEND platform_INCLUDES
|
||||||
else()
|
else()
|
||||||
list(APPEND platform_INCLUDES
|
list(APPEND platform_INCLUDES
|
||||||
server/win32/Win32WebServer.h
|
server/win32/Win32WebServer.h
|
||||||
server/win32/Win32WebServer.cpp)
|
server/win32/Win32WebServer.cpp
|
||||||
|
server/win32/Win32TempFile.h
|
||||||
|
server/win32/Win32TempFile.cpp
|
||||||
|
server/win32/Win32WebRequest.h
|
||||||
|
server/win32/Win32WebRequest.cpp
|
||||||
|
server/win32/Win32WebResponse.h
|
||||||
|
server/win32/Win32WebResponse.cpp
|
||||||
|
server/win32/Win32Buffer.h
|
||||||
|
server/win32/Win32Buffer.cpp
|
||||||
|
)
|
||||||
list(APPEND platform_LIBS Httpapi.lib)
|
list(APPEND platform_LIBS Httpapi.lib)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
63
src/network/server/win32/Win32Buffer.cpp
Normal file
63
src/network/server/win32/Win32Buffer.cpp
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#include "Win32Buffer.h"
|
||||||
|
|
||||||
|
#include "FileLogger.h"
|
||||||
|
|
||||||
|
#ifndef UNICODE
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
Win32Buffer::Win32Buffer(unsigned size)
|
||||||
|
{
|
||||||
|
createBuffer(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Win32Buffer::~Win32Buffer()
|
||||||
|
{
|
||||||
|
clearBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
PUCHAR Win32Buffer::getBufferAsUChar() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<PUCHAR>(mBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Win32Buffer::getBuffer() const
|
||||||
|
{
|
||||||
|
return mBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Win32Buffer::isValid() const
|
||||||
|
{
|
||||||
|
return mIsValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Buffer::createBuffer(unsigned size)
|
||||||
|
{
|
||||||
|
mIsValid = false;
|
||||||
|
mBuffer = ::HeapAlloc(::GetProcessHeap(), 0, size);
|
||||||
|
if (mBuffer == nullptr)
|
||||||
|
{
|
||||||
|
MLOG_ERROR("Insufficient resources");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIsValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Buffer::clearBuffer()
|
||||||
|
{
|
||||||
|
if (mBuffer)
|
||||||
|
{
|
||||||
|
::HeapFree(::GetProcessHeap(), 0, mBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32Buffer::reset(unsigned size)
|
||||||
|
{
|
||||||
|
clearBuffer();
|
||||||
|
createBuffer(size);
|
||||||
|
}
|
24
src/network/server/win32/Win32Buffer.h
Normal file
24
src/network/server/win32/Win32Buffer.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class Win32Buffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Win32Buffer(unsigned size);
|
||||||
|
|
||||||
|
~Win32Buffer();
|
||||||
|
|
||||||
|
void* getBuffer() const;
|
||||||
|
|
||||||
|
PUCHAR getBufferAsUChar() const;
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
void reset(unsigned size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createBuffer(unsigned size);
|
||||||
|
void clearBuffer();
|
||||||
|
|
||||||
|
bool mIsValid{ false };
|
||||||
|
void* mBuffer{ nullptr };
|
||||||
|
};
|
53
src/network/server/win32/Win32TempFile.cpp
Normal file
53
src/network/server/win32/Win32TempFile.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#include "Win32TempFile.h"
|
||||||
|
|
||||||
|
#include "FileLogger.h"
|
||||||
|
|
||||||
|
Win32TempFile::Win32TempFile()
|
||||||
|
{
|
||||||
|
if (::GetTempFileName(L".", L"New", 0, &mName[0]) == 0)
|
||||||
|
{
|
||||||
|
auto result = ::GetLastError();
|
||||||
|
MLOG_ERROR("Failed to set up temp file for buffer with: " << result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mHandle = ::CreateFile(&mName[0], GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (mHandle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
auto result = ::GetLastError();
|
||||||
|
MLOG_ERROR("Failed to create temp file for buffer with: " << result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIsValid = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Win32TempFile::~Win32TempFile()
|
||||||
|
{
|
||||||
|
if (INVALID_HANDLE_VALUE != mHandle)
|
||||||
|
{
|
||||||
|
::CloseHandle(mHandle);
|
||||||
|
::DeleteFile(&mName[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32TempFile::write(PUCHAR buffer, ULONG size)
|
||||||
|
{
|
||||||
|
if (!mIsValid)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG temp_file_bytes_written = 0;
|
||||||
|
::WriteFile(mHandle, buffer, size, &temp_file_bytes_written, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE Win32TempFile::getHandle() const
|
||||||
|
{
|
||||||
|
return mHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Win32TempFile::isValid() const
|
||||||
|
{
|
||||||
|
return mIsValid;
|
||||||
|
}
|
31
src/network/server/win32/Win32TempFile.h
Normal file
31
src/network/server/win32/Win32TempFile.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef UNICODE
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Win32TempFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Win32TempFile();
|
||||||
|
|
||||||
|
~Win32TempFile();
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
HANDLE getHandle() const;
|
||||||
|
|
||||||
|
void write(PUCHAR buffer, ULONG size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mIsValid{ false };
|
||||||
|
std::wstring mName;
|
||||||
|
HANDLE mHandle{ 0 };
|
||||||
|
};
|
67
src/network/server/win32/Win32WebRequest.cpp
Normal file
67
src/network/server/win32/Win32WebRequest.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "Win32WebRequest.h"
|
||||||
|
|
||||||
|
#include "StringUtils.h"
|
||||||
|
#include "HttpRequest.h"
|
||||||
|
|
||||||
|
Win32WebRequest::Win32WebRequest()
|
||||||
|
: mBuffer(DEFAULT_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
mIsValid = mBuffer.isValid();
|
||||||
|
mHandle = reinterpret_cast<PHTTP_REQUEST>(mBuffer.getBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Win32WebRequest::isValid() const
|
||||||
|
{
|
||||||
|
return mIsValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32WebRequest::zeroBufferMemory()
|
||||||
|
{
|
||||||
|
::RtlZeroMemory(mHandle, mWorkingBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
PHTTP_REQUEST Win32WebRequest::getHandle() const
|
||||||
|
{
|
||||||
|
return mHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Win32WebRequest::getBufferSize() const
|
||||||
|
{
|
||||||
|
return mWorkingBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32WebRequest::resizeBuffer(unsigned size)
|
||||||
|
{
|
||||||
|
mWorkingBufferSize = size;
|
||||||
|
mBuffer.reset(mWorkingBufferSize);
|
||||||
|
if (!mBuffer.isValid())
|
||||||
|
{
|
||||||
|
mIsValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mHandle = reinterpret_cast<PHTTP_REQUEST>(mBuffer.getBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Win32WebRequest::getUrlFromRequest() const
|
||||||
|
{
|
||||||
|
const std::wstring wide_url = mHandle->CookedUrl.pFullUrl;
|
||||||
|
return StringUtils::convert(wide_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest Win32WebRequest::getRequest() const
|
||||||
|
{
|
||||||
|
HttpRequest::Verb verb;
|
||||||
|
switch (mHandle->Verb)
|
||||||
|
{
|
||||||
|
case HttpVerbGET:
|
||||||
|
verb = HttpRequest::Verb::GET;
|
||||||
|
case HttpVerbPOST:
|
||||||
|
verb = HttpRequest::Verb::POST;
|
||||||
|
default:
|
||||||
|
verb = HttpRequest::Verb::UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest request(verb, getUrlFromRequest());
|
||||||
|
return request;
|
||||||
|
}
|
50
src/network/server/win32/Win32WebRequest.h
Normal file
50
src/network/server/win32/Win32WebRequest.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
#ifndef UNICODE
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0600
|
||||||
|
#endif
|
||||||
|
#include <http.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Win32Buffer.h"
|
||||||
|
|
||||||
|
class HttpRequest;
|
||||||
|
|
||||||
|
class Win32WebRequest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Win32WebRequest();
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
PHTTP_REQUEST getHandle() const;
|
||||||
|
|
||||||
|
unsigned getBufferSize() const;
|
||||||
|
|
||||||
|
void resizeBuffer(unsigned size);
|
||||||
|
|
||||||
|
void zeroBufferMemory();
|
||||||
|
|
||||||
|
HttpRequest getRequest() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string getUrlFromRequest() const;
|
||||||
|
|
||||||
|
|
||||||
|
static const unsigned DEFAULT_BUFFER_SIZE{ sizeof(HTTP_REQUEST) + 2048 };
|
||||||
|
Win32Buffer mBuffer;
|
||||||
|
bool mIsValid{ false };
|
||||||
|
|
||||||
|
unsigned mWorkingBufferSize{ DEFAULT_BUFFER_SIZE };
|
||||||
|
PHTTP_REQUEST mHandle{ nullptr };
|
||||||
|
};
|
||||||
|
|
34
src/network/server/win32/Win32WebResponse.cpp
Normal file
34
src/network/server/win32/Win32WebResponse.cpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#include "Win32WebResponse.h"
|
||||||
|
|
||||||
|
#include "HttpResponse.h"
|
||||||
|
|
||||||
|
Win32WebResponse::Win32WebResponse(const HttpResponse& response)
|
||||||
|
{
|
||||||
|
RtlZeroMemory((&mResponse), sizeof(*(&mResponse)));
|
||||||
|
mResponse.StatusCode = response.getStatusCode();
|
||||||
|
|
||||||
|
std::string reason = response.getResponseReason();
|
||||||
|
mResponse.pReason = reason.c_str();
|
||||||
|
mResponse.ReasonLength = (USHORT)strlen(reason.c_str());
|
||||||
|
|
||||||
|
const std::string content_type = "text / html";
|
||||||
|
mResponse.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = content_type.c_str();
|
||||||
|
mResponse.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)strlen(content_type.c_str());
|
||||||
|
|
||||||
|
auto body = response.getBody();
|
||||||
|
if (!body.empty())
|
||||||
|
{
|
||||||
|
HTTP_DATA_CHUNK dataChunk;
|
||||||
|
dataChunk.DataChunkType = HttpDataChunkFromMemory;
|
||||||
|
dataChunk.FromMemory.pBuffer = body.data();
|
||||||
|
dataChunk.FromMemory.BufferLength = (ULONG)strlen(body.data());
|
||||||
|
|
||||||
|
mResponse.EntityChunkCount = 1;
|
||||||
|
mResponse.pEntityChunks = &dataChunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTP_RESPONSE& Win32WebResponse::getResponse()
|
||||||
|
{
|
||||||
|
return mResponse;
|
||||||
|
}
|
30
src/network/server/win32/Win32WebResponse.h
Normal file
30
src/network/server/win32/Win32WebResponse.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef UNICODE
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0600
|
||||||
|
#endif
|
||||||
|
#include <http.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class HttpResponse;
|
||||||
|
|
||||||
|
class Win32WebResponse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Win32WebResponse(const HttpResponse& response);
|
||||||
|
|
||||||
|
HTTP_RESPONSE& getResponse();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HTTP_RESPONSE mResponse;
|
||||||
|
};
|
|
@ -1,10 +1,19 @@
|
||||||
#include "Win32WebServer.h"
|
#include "Win32WebServer.h"
|
||||||
|
|
||||||
|
#include "Win32TempFile.h"
|
||||||
|
#include "Win32Buffer.h"
|
||||||
|
#include "Win32WebResponse.h"
|
||||||
|
#include "Win32WebRequest.h"
|
||||||
|
|
||||||
|
#include "AbstractWebApp.h"
|
||||||
|
#include "HttpRequest.h"
|
||||||
|
#include "HttpResponse.h"
|
||||||
#include "FileLogger.h"
|
#include "FileLogger.h"
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
Win32WebServer::Win32WebServer()
|
Win32WebServer::Win32WebServer(AbstractWebApp* webApp)
|
||||||
: mListenUrl("http://localhost:80/49152")
|
: mListenUrl("http://localhost:80/49152"),
|
||||||
|
mWebApp(webApp)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,313 +64,45 @@ void Win32WebServer::initialize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32WebServer::onRequest(PHTTP_REQUEST request)
|
DWORD Win32WebServer::onRequest(const Win32WebRequest& request)
|
||||||
{
|
{
|
||||||
const std::wstring wide_url = request->CookedUrl.pFullUrl;
|
auto app_request = request.getRequest();
|
||||||
const auto url = StringUtils::convert(wide_url);
|
auto response = mWebApp->onHttpRequest(app_request);
|
||||||
|
|
||||||
switch (request->Verb)
|
DWORD result;
|
||||||
|
if (app_request.getVerb() == HttpRequest::Verb::POST)
|
||||||
{
|
{
|
||||||
|
result = sendHttpPostResponse(request.getHandle());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = sendHttpResponse(request.getHandle(), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
case HttpVerbGET:
|
case HttpVerbGET:
|
||||||
MLOG_INFO("Got a GET request for: " << url);
|
MLOG_INFO("Got a GET request for: " << url);
|
||||||
auto result = sendHttpResponse(request, 200, "OK", "Hey! You hit the server \r\n");
|
result = sendHttpResponse(request, 200, "OK", "Hey! You hit the server \r\n");
|
||||||
break;
|
break;
|
||||||
case HttpVerbPOST:
|
case HttpVerbPOST:
|
||||||
MLOG_INFO("Got a POST request for: " << url);
|
MLOG_INFO("Got a POST request for: " << url);
|
||||||
result = sendHttpPostResponse(request);
|
result = sendHttpPostResponse(request);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
MLOG_INFO("Got an unknown request for: " << url);
|
MLOG_INFO("Got an unknown request for: " << url);
|
||||||
result = sendHttpResponse(request, 503, "Not Implemented");
|
result = sendHttpResponse(request, 503, "Not Implemented");
|
||||||
break;
|
break;
|
||||||
}
|
*/
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32WebServer::initializeHttpResponse(HTTP_RESPONSE& response, USHORT StatusCode, const std::string& reason)
|
DWORD Win32WebServer::sendHttpResponse(PHTTP_REQUEST pRequest, const HttpResponse& appResponse)
|
||||||
{
|
{
|
||||||
RtlZeroMemory((&response), sizeof(*(&response)));
|
Win32WebResponse response(appResponse);
|
||||||
response.StatusCode = StatusCode;
|
|
||||||
response.pReason = reason.c_str();
|
|
||||||
response.ReasonLength = (USHORT)strlen(reason.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_ULONG_STR ((ULONG) sizeof("4294967295"))
|
|
||||||
|
|
||||||
DWORD Win32WebServer::sendHttpPostResponse(PHTTP_REQUEST pRequest)
|
|
||||||
{
|
|
||||||
DWORD result;
|
|
||||||
auto hTempFile = INVALID_HANDLE_VALUE;
|
|
||||||
|
|
||||||
// Allocate space for an entity buffer. Buffer can be increased on demand.
|
|
||||||
ULONG EntityBufferLength = 2048;
|
|
||||||
PUCHAR pEntityBuffer = reinterpret_cast<PUCHAR>(::HeapAlloc(::GetProcessHeap(), 0, (EntityBufferLength)));
|
|
||||||
if (pEntityBuffer == nullptr)
|
|
||||||
{
|
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
MLOG_ERROR("Insufficient resources");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
HTTP_RESPONSE response;
|
|
||||||
initializeHttpResponse(response, 200, "OK");
|
|
||||||
|
|
||||||
if (pRequest->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS)
|
|
||||||
{
|
|
||||||
// The entity body is sent over multiple calls. Collect these in a file and send back. Create a temporary file.
|
|
||||||
TCHAR szTempName[MAX_PATH + 1];
|
|
||||||
if (::GetTempFileName(L".", L"New", 0, szTempName) == 0)
|
|
||||||
{
|
|
||||||
result = ::GetLastError();
|
|
||||||
MLOG_ERROR("Failed to set up temp file for buffer with: " << result);
|
|
||||||
if (pEntityBuffer)
|
|
||||||
{
|
|
||||||
HeapFree(GetProcessHeap(), 0, (pEntityBuffer));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
hTempFile = CreateFile(szTempName, GENERIC_READ | GENERIC_WRITE,
|
|
||||||
0, // Do not share.
|
|
||||||
NULL, // No security descriptor.
|
|
||||||
CREATE_ALWAYS, // Overrwrite existing.
|
|
||||||
FILE_ATTRIBUTE_NORMAL, // Normal file.
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
if (hTempFile == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
result = GetLastError();
|
|
||||||
MLOG_ERROR("Failed to create temp file for buffer with: " << result);
|
|
||||||
if (pEntityBuffer)
|
|
||||||
{
|
|
||||||
HeapFree(GetProcessHeap(), 0, (pEntityBuffer));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD bytesSent;
|
DWORD bytesSent;
|
||||||
ULONG TempFileBytesWritten;
|
const auto result = ::HttpSendHttpResponse(mWorkingQueue, pRequest->RequestId, 0, &(response.getResponse()), NULL, &bytesSent, NULL, 0, NULL, NULL);
|
||||||
CHAR szContentLength[MAX_ULONG_STR];
|
|
||||||
HTTP_DATA_CHUNK dataChunk;
|
|
||||||
|
|
||||||
ULONG TotalBytesRead = 0;
|
|
||||||
ULONG BytesRead = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// Read the entity chunk from the request.
|
|
||||||
BytesRead = 0;
|
|
||||||
result = ::HttpReceiveRequestEntityBody(mWorkingQueue, pRequest->RequestId, 0,
|
|
||||||
pEntityBuffer, EntityBufferLength, &BytesRead, NULL);
|
|
||||||
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
case NO_ERROR:
|
|
||||||
if (BytesRead != 0)
|
|
||||||
{
|
|
||||||
TotalBytesRead += BytesRead;
|
|
||||||
::WriteFile(hTempFile, pEntityBuffer, BytesRead, &TempFileBytesWritten, NULL);
|
|
||||||
}
|
|
||||||
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 (BytesRead != 0)
|
|
||||||
{
|
|
||||||
TotalBytesRead += BytesRead;
|
|
||||||
WriteFile(
|
|
||||||
hTempFile,
|
|
||||||
pEntityBuffer,
|
|
||||||
BytesRead,
|
|
||||||
&TempFileBytesWritten,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
sprintf_s(szContentLength, MAX_ULONG_STR, "%lu", TotalBytesRead);
|
|
||||||
|
|
||||||
ADD_KNOWN_HEADER(
|
|
||||||
response,
|
|
||||||
HttpHeaderContentLength,
|
|
||||||
szContentLength
|
|
||||||
);
|
|
||||||
|
|
||||||
result =
|
|
||||||
HttpSendHttpResponse(
|
|
||||||
hReqQueue, // ReqQueueHandle
|
|
||||||
pRequest->RequestId, // Request ID
|
|
||||||
HTTP_SEND_RESPONSE_FLAG_MORE_DATA,
|
|
||||||
&response, // HTTP response
|
|
||||||
NULL, // pReserved1
|
|
||||||
&bytesSent, // bytes sent-optional
|
|
||||||
NULL, // pReserved2
|
|
||||||
0, // Reserved3
|
|
||||||
NULL, // LPOVERLAPPED
|
|
||||||
NULL // pReserved4
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result != NO_ERROR)
|
|
||||||
{
|
|
||||||
wprintf(
|
|
||||||
L"HttpSendHttpResponse failed with %lu \n",
|
|
||||||
result
|
|
||||||
);
|
|
||||||
goto Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Send entity body from a file handle.
|
|
||||||
//
|
|
||||||
dataChunk.DataChunkType =
|
|
||||||
HttpDataChunkFromFileHandle;
|
|
||||||
|
|
||||||
dataChunk.FromFileHandle.
|
|
||||||
ByteRange.StartingOffset.QuadPart = 0;
|
|
||||||
|
|
||||||
dataChunk.FromFileHandle.
|
|
||||||
ByteRange.Length.QuadPart =
|
|
||||||
HTTP_BYTE_RANGE_TO_EOF;
|
|
||||||
|
|
||||||
dataChunk.FromFileHandle.FileHandle = hTempFile;
|
|
||||||
|
|
||||||
result = HttpSendResponseEntityBody(
|
|
||||||
hReqQueue,
|
|
||||||
pRequest->RequestId,
|
|
||||||
0, // This is the last send.
|
|
||||||
1, // Entity Chunk Count.
|
|
||||||
&dataChunk,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result != NO_ERROR)
|
|
||||||
{
|
|
||||||
wprintf(
|
|
||||||
L"HttpSendResponseEntityBody failed %lu\n",
|
|
||||||
result
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
goto Done;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
|
||||||
wprintf(
|
|
||||||
L"HttpReceiveRequestEntityBody failed with %lu \n",
|
|
||||||
result);
|
|
||||||
goto Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (TRUE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This request does not have an entity body.
|
|
||||||
//
|
|
||||||
|
|
||||||
result = HttpSendHttpResponse(
|
|
||||||
hReqQueue, // ReqQueueHandle
|
|
||||||
pRequest->RequestId, // Request ID
|
|
||||||
0,
|
|
||||||
&response, // HTTP response
|
|
||||||
NULL, // pReserved1
|
|
||||||
&bytesSent, // bytes sent (optional)
|
|
||||||
NULL, // pReserved2
|
|
||||||
0, // Reserved3
|
|
||||||
NULL, // LPOVERLAPPED
|
|
||||||
NULL // pReserved4
|
|
||||||
);
|
|
||||||
if (result != NO_ERROR)
|
|
||||||
{
|
|
||||||
wprintf(L"HttpSendHttpResponse failed with %lu \n",
|
|
||||||
result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Done:
|
|
||||||
|
|
||||||
if (pEntityBuffer)
|
|
||||||
{
|
|
||||||
FREE_MEM(pEntityBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (INVALID_HANDLE_VALUE != hTempFile)
|
|
||||||
{
|
|
||||||
CloseHandle(hTempFile);
|
|
||||||
DeleteFile(szTempName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD Win32WebServer::sendHttpResponse(PHTTP_REQUEST pRequest, USHORT StatusCode, const std::string& reason, const std::string& message)
|
|
||||||
{
|
|
||||||
HTTP_RESPONSE response;
|
|
||||||
RtlZeroMemory((&response), sizeof(*(&response)));
|
|
||||||
response.StatusCode = StatusCode;
|
|
||||||
response.pReason = reason.c_str();
|
|
||||||
response.ReasonLength = (USHORT)strlen(reason.c_str());
|
|
||||||
|
|
||||||
const std::string content_type = "text / html";
|
|
||||||
response.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = content_type.c_str();
|
|
||||||
response.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)strlen(content_type.c_str());
|
|
||||||
|
|
||||||
if (!message.empty())
|
|
||||||
{
|
|
||||||
auto entity_string = message;
|
|
||||||
HTTP_DATA_CHUNK dataChunk;
|
|
||||||
dataChunk.DataChunkType = HttpDataChunkFromMemory;
|
|
||||||
dataChunk.FromMemory.pBuffer = entity_string.data();
|
|
||||||
dataChunk.FromMemory.BufferLength = (ULONG)strlen(entity_string.data());
|
|
||||||
|
|
||||||
response.EntityChunkCount = 1;
|
|
||||||
response.pEntityChunks = &dataChunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD bytesSent;
|
|
||||||
DWORD result = ::HttpSendHttpResponse(
|
|
||||||
mWorkingQueue, // ReqQueueHandle
|
|
||||||
pRequest->RequestId, // Request ID
|
|
||||||
0, // Flags
|
|
||||||
&response, // HTTP response
|
|
||||||
NULL, // pReserved1
|
|
||||||
&bytesSent, // bytes sent (OPTIONAL)
|
|
||||||
NULL, // pReserved2 (must be NULL)
|
|
||||||
0, // Reserved3 (must be 0)
|
|
||||||
NULL, // LPOVERLAPPED(OPTIONAL)
|
|
||||||
NULL // pReserved4 (must be 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);
|
||||||
|
@ -369,136 +110,155 @@ DWORD Win32WebServer::sendHttpResponse(PHTTP_REQUEST pRequest, USHORT StatusCode
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_ULONG_STR ((ULONG) sizeof("4294967295"))
|
||||||
|
|
||||||
|
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 };
|
||||||
|
if (pRequest->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS)
|
||||||
|
{
|
||||||
|
Win32TempFile temp_file;
|
||||||
|
if (!temp_file.isValid())
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
result = ::HttpSendHttpResponse(mWorkingQueue, pRequest->RequestId, 0, &response, NULL, &bytesSent, NULL, 0, NULL, NULL );
|
||||||
|
if (result != NO_ERROR)
|
||||||
|
{
|
||||||
|
MLOG_ERROR("HttpSendHttpResponse failed with: " << result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Win32WebServer::run()
|
void Win32WebServer::run()
|
||||||
{
|
{
|
||||||
// Allocate a 2 KB buffer. This size should work for most
|
Win32WebRequest request;
|
||||||
// requests. The buffer size can be increased if required. Space
|
if (!request.isValid())
|
||||||
// is also required for an HTTP_REQUEST structure.
|
|
||||||
ULONG RequestBufferLength = sizeof(HTTP_REQUEST) + 2048;
|
|
||||||
PCHAR pRequestBuffer = reinterpret_cast<PCHAR>(::HeapAlloc(::GetProcessHeap(), 0, (RequestBufferLength)));
|
|
||||||
if (pRequestBuffer == nullptr)
|
|
||||||
{
|
{
|
||||||
MLOG_ERROR("Failed to allocate http request buffer");
|
MLOG_ERROR("Failed to allocate http request buffer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PHTTP_REQUEST pRequest = (PHTTP_REQUEST)pRequestBuffer;
|
|
||||||
|
|
||||||
// Wait for a new request. This is indicated by a NULL
|
HTTP_REQUEST_ID request_id;
|
||||||
// request ID.
|
HTTP_SET_NULL_ID(&request_id);
|
||||||
HTTP_REQUEST_ID requestId;
|
|
||||||
HTTP_SET_NULL_ID(&requestId);
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
RtlZeroMemory(pRequest, RequestBufferLength);
|
request.zeroBufferMemory();
|
||||||
|
|
||||||
DWORD bytesRead;
|
|
||||||
ULONG result = ::HttpReceiveHttpRequest(
|
|
||||||
mWorkingQueue, // Req Queue
|
|
||||||
requestId, // Req ID
|
|
||||||
0, // Flags
|
|
||||||
pRequest, // HTTP request buffer
|
|
||||||
RequestBufferLength,// req buffer length
|
|
||||||
&bytesRead, // bytes received
|
|
||||||
nullptr // LPOVERLAPPED
|
|
||||||
);
|
|
||||||
|
|
||||||
|
DWORD bytes_read;
|
||||||
|
auto result = ::HttpReceiveHttpRequest(mWorkingQueue, request_id, 0, request.getHandle(), request.getBufferSize(), &bytes_read, nullptr);
|
||||||
if (NO_ERROR == result)
|
if (NO_ERROR == result)
|
||||||
{
|
{
|
||||||
switch (pRequest->Verb)
|
result = onRequest(request);
|
||||||
{
|
|
||||||
case HttpVerbGET:
|
|
||||||
wprintf(L"Got a GET request for %ws \n",
|
|
||||||
pRequest->CookedUrl.pFullUrl);
|
|
||||||
|
|
||||||
result = SendHttpResponse(
|
|
||||||
hReqQueue,
|
|
||||||
pRequest,
|
|
||||||
200,
|
|
||||||
"OK",
|
|
||||||
"Hey! You hit the server \r\n"
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HttpVerbPOST:
|
|
||||||
|
|
||||||
wprintf(L"Got a POST request for %ws \n",
|
|
||||||
pRequest->CookedUrl.pFullUrl);
|
|
||||||
|
|
||||||
result = SendHttpPostResponse(hReqQueue, pRequest);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
wprintf(L"Got a unknown request for %ws \n",
|
|
||||||
pRequest->CookedUrl.pFullUrl);
|
|
||||||
|
|
||||||
result = SendHttpResponse(
|
|
||||||
hReqQueue,
|
|
||||||
pRequest,
|
|
||||||
503,
|
|
||||||
"Not Implemented",
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != NO_ERROR)
|
if (result != NO_ERROR)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
HTTP_SET_NULL_ID(&request_id);
|
||||||
//
|
|
||||||
// Reset the Request ID to handle the next request.
|
|
||||||
//
|
|
||||||
HTTP_SET_NULL_ID(&requestId);
|
|
||||||
}
|
}
|
||||||
else if (result == ERROR_MORE_DATA)
|
else if (result == ERROR_MORE_DATA)
|
||||||
{
|
{
|
||||||
//
|
// The input buffer was too small to hold the request headers. Increase the buffer size and call the API again.
|
||||||
// The input buffer was too small to hold the request
|
request_id = request.getHandle()->RequestId;
|
||||||
// headers. Increase the buffer size and call the
|
|
||||||
// API again.
|
|
||||||
//
|
|
||||||
// When calling the API again, handle the request
|
|
||||||
// that failed by passing a RequestID.
|
|
||||||
//
|
|
||||||
// This RequestID is read from the old buffer.
|
|
||||||
//
|
|
||||||
requestId = pRequest->RequestId;
|
|
||||||
|
|
||||||
//
|
request.resizeBuffer(bytes_read);
|
||||||
// Free the old buffer and allocate a new buffer.
|
if (!request.isValid())
|
||||||
//
|
|
||||||
RequestBufferLength = bytesRead;
|
|
||||||
FREE_MEM(pRequestBuffer);
|
|
||||||
pRequestBuffer = (PCHAR)ALLOC_MEM(RequestBufferLength);
|
|
||||||
|
|
||||||
if (pRequestBuffer == NULL)
|
|
||||||
{
|
{
|
||||||
result = ERROR_NOT_ENOUGH_MEMORY;
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pRequest = (PHTTP_REQUEST)pRequestBuffer;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (ERROR_CONNECTION_INVALID == result &&
|
else if (ERROR_CONNECTION_INVALID == result && !HTTP_IS_NULL_ID(&request_id))
|
||||||
!HTTP_IS_NULL_ID(&requestId))
|
|
||||||
{
|
{
|
||||||
// The TCP connection was corrupted by the peer when
|
// The TCP connection was corrupted by the peer when attempting to handle a request with more buffer. Continue to the next request.
|
||||||
// attempting to handle a request with more buffer.
|
HTTP_SET_NULL_ID(&request_id);
|
||||||
// Continue to the next request.
|
|
||||||
|
|
||||||
HTTP_SET_NULL_ID(&requestId);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pRequestBuffer)
|
|
||||||
{
|
|
||||||
FREE_MEM(pRequestBuffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,26 +16,31 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
class AbstractWebApp;
|
||||||
|
class Win32WebRequest;
|
||||||
|
|
||||||
|
class HttpResponse;
|
||||||
|
|
||||||
class Win32WebServer
|
class Win32WebServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Win32WebServer();
|
Win32WebServer(AbstractWebApp* webApp);
|
||||||
|
|
||||||
~Win32WebServer();
|
~Win32WebServer();
|
||||||
|
|
||||||
void initialize();
|
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
void initialize();
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onRequest(PHTTP_REQUEST request);
|
DWORD onRequest(const Win32WebRequest& request);
|
||||||
|
|
||||||
DWORD sendHttpResponse(PHTTP_REQUEST pRequest, USHORT StatusCode, const std::string& reason, const std::string& message = {});
|
DWORD sendHttpResponse(PHTTP_REQUEST pRequest, const HttpResponse& response);
|
||||||
DWORD sendHttpPostResponse(PHTTP_REQUEST pRequest);
|
DWORD sendHttpPostResponse(PHTTP_REQUEST pRequest);
|
||||||
|
|
||||||
void initializeHttpResponse(HTTP_RESPONSE& response, USHORT StatusCode, const std::string& reason);
|
AbstractWebApp* mWebApp{ nullptr };
|
||||||
|
|
||||||
HANDLE mWorkingQueue{ 0 };
|
HANDLE mWorkingQueue{ 0 };
|
||||||
std::string mListenUrl;
|
std::string mListenUrl;
|
||||||
|
|
|
@ -44,7 +44,6 @@ const std::vector<AbstractVisualNode*>& AbstractVisualNode::getChildren() const
|
||||||
|
|
||||||
void AbstractVisualNode::setIsVisible(bool isVisible)
|
void AbstractVisualNode::setIsVisible(bool isVisible)
|
||||||
{
|
{
|
||||||
//std::cout << "Setting " << mName << " visibility to " << isVisible << std::endl;
|
|
||||||
mIsVisible = isVisible;
|
mIsVisible = isVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,11 @@ set(MODULE_NAME visual_elements)
|
||||||
|
|
||||||
list(APPEND visual_elements_LIB_INCLUDES
|
list(APPEND visual_elements_LIB_INCLUDES
|
||||||
GeometryNode.cpp
|
GeometryNode.cpp
|
||||||
|
basic_shapes/RectangleNode.h
|
||||||
basic_shapes/RectangleNode.cpp
|
basic_shapes/RectangleNode.cpp
|
||||||
|
basic_shapes/CircleNode.h
|
||||||
basic_shapes/CircleNode.cpp
|
basic_shapes/CircleNode.cpp
|
||||||
|
basic_shapes/LineNode.h
|
||||||
basic_shapes/LineNode.cpp
|
basic_shapes/LineNode.cpp
|
||||||
MaterialNode.cpp
|
MaterialNode.cpp
|
||||||
MeshNode.cpp
|
MeshNode.cpp
|
||||||
|
@ -14,6 +17,7 @@ list(APPEND visual_elements_LIB_INCLUDES
|
||||||
SceneText.cpp
|
SceneText.cpp
|
||||||
Texture.cpp
|
Texture.cpp
|
||||||
GridNode.cpp
|
GridNode.cpp
|
||||||
|
AbstractVisualNode.h
|
||||||
AbstractVisualNode.cpp
|
AbstractVisualNode.cpp
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue