This commit is contained in:
Jorijn van der Graaf 2025-11-03 14:25:51 +01:00
commit 9bdf133d0f
12 changed files with 301 additions and 168 deletions

View file

@ -37,7 +37,7 @@ import std;
using namespace Crafter; using namespace Crafter;
ClientHTTP::ClientHTTP(const char* host, std::uint16_t port): client(host, port) { ClientHTTP::ClientHTTP(const char* host, std::uint16_t port): host(host), port(port), client(host, port) {
} }
@ -45,14 +45,21 @@ ClientHTTP::ClientHTTP(std::string host, std::uint16_t port): ClientHTTP(host.c_
} }
HTTPResponse ClientHTTP::Send(const char* request, std::uint32_t length) const { HTTPResponse ClientHTTP::Send(const char* request, std::uint32_t length) {
client.Send(request, length); client.Send(request, length);
std::vector<char> buffer; std::vector<char> buffer;
HTTPResponse response; HTTPResponse response;
std::uint32_t i = 0; std::uint32_t i = 0;
std::uint32_t statusStart = 0; std::uint32_t statusStart = 0;
while(true) { while(true) {
try {
buffer = client.RecieveSync(); buffer = client.RecieveSync();
} catch(const SocketClosedException& e) {
client = ClientTCP(host.c_str(), port);
client.Send(request, length);
buffer = client.RecieveSync();
}
for(; i < buffer.size(); i++) { for(; i < buffer.size(); i++) {
if(buffer[i] == ' ') { if(buffer[i] == ' ') {
statusStart = i; statusStart = i;
@ -185,6 +192,6 @@ HTTPResponse ClientHTTP::Send(const char* request, std::uint32_t length) const {
} }
return response; return response;
} }
HTTPResponse ClientHTTP::Send(std::string request) const { HTTPResponse ClientHTTP::Send(std::string request) {
return Send(request.c_str(), request.size()); return Send(request.c_str(), request.size());
} }

View file

@ -32,6 +32,7 @@ module;
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <netdb.h> #include <netdb.h>
#include <strings.h> #include <strings.h>
#include <cerrno>
module Crafter.Network:ClientTCP_impl; module Crafter.Network:ClientTCP_impl;
import :ClientTCP; import :ClientTCP;
@ -72,7 +73,16 @@ ClientTCP::ClientTCP(std::string hostName, std::uint16_t port): ClientTCP(hostNa
ClientTCP::~ClientTCP() ClientTCP::~ClientTCP()
{ {
if(socketid != 1) {
shutdown(socketid, SHUT_RDWR);
close(socketid); close(socketid);
}
}
void ClientTCP::Stop() {
shutdown(socketid, SHUT_RDWR);
close(socketid);
socketid = -1;
} }
void ClientTCP::Send(const void* buffer, std::uint32_t size) const { void ClientTCP::Send(const void* buffer, std::uint32_t size) const {
@ -82,8 +92,10 @@ void ClientTCP::Send(const void* buffer, std::uint32_t size) const {
std::vector<char> ClientTCP::RecieveSync(std::uint32_t bufferSize) const { std::vector<char> ClientTCP::RecieveSync(std::uint32_t bufferSize) const {
std::vector<char> totalBuffer(bufferSize); std::vector<char> totalBuffer(bufferSize);
int read = recv(socketid, totalBuffer.data(), bufferSize, 0); int read = recv(socketid, totalBuffer.data(), bufferSize, 0);
if(read < bufferSize){ if(read < 0) {
totalBuffer.resize(read); throw std::runtime_error(std::strerror(errno));
} else if(read == 0) {
throw SocketClosedException();
} }
return totalBuffer; return totalBuffer;
} }
@ -94,22 +106,49 @@ int ClientTCP::RecieveSync(std::uint32_t bufferSize, void* buffer) const {
std::vector<char> ClientTCP::RecieveSync() const { std::vector<char> ClientTCP::RecieveSync() const {
int count; int count;
ioctl(socketid, FIONREAD, &count); ioctl(socketid, FIONREAD, &count);
if(count == 0){
count = 1024;
}
std::vector<char> buffer(count); std::vector<char> buffer(count);
recv(socketid, buffer.data(), count, 0); int read = recv(socketid, buffer.data(), count, 0);
if(read < 0) {
throw std::runtime_error(std::strerror(errno));
} else if(read == 0) {
throw SocketClosedException();
} else if(count != read) {
buffer.resize(read);
}
return buffer; return buffer;
} }
std::vector<char> ClientTCP::RecieveUntilCloseSync() const { std::vector<char> ClientTCP::RecieveUntilCloseSync() const {
int count; int count;
ioctl(socketid, FIONREAD, &count); ioctl(socketid, FIONREAD, &count);
if(count == 0){
count = 1024;
}
std::vector<char> buffer(count); std::vector<char> buffer(count);
recv(socketid, buffer.data(), count, 0); int read = recv(socketid, buffer.data(), count, 0);
if(read < 0) {
throw std::runtime_error(std::strerror(errno));
} else if(read == 0) {
throw SocketClosedException();
}
while(true) { while(true) {
ioctl(socketid, FIONREAD, &count); ioctl(socketid, FIONREAD, &count);
if(count == 0){
count = 1024;
}
unsigned int oldSize = buffer.size(); unsigned int oldSize = buffer.size();
buffer.resize(buffer.size()+count); buffer.resize(buffer.size()+count);
if(recv(socketid, buffer.data()+oldSize, count, 0) == -1) { int read = recv(socketid, buffer.data()+oldSize, count, 0);
break; if(read < 0) {
throw std::runtime_error(std::strerror(errno));
} else if(read == 0) {
return buffer;
} else if(count != read) {
buffer.resize(read);
} }
} }
return buffer; return buffer;
@ -120,11 +159,12 @@ std::vector<char> ClientTCP::RecieveUntilFullSync(std::uint32_t bufferSize) cons
int read = 0; int read = 0;
while(read < bufferSize) { while(read < bufferSize) {
int newRead = recv(socketid, buffer.data()+read, bufferSize-read, 0); int newRead = recv(socketid, buffer.data()+read, bufferSize-read, 0);
if(newRead == -1) { if(read < 0) {
break; throw std::runtime_error(std::strerror(errno));
} else{ } else if(read == 0) {
read+=newRead; throw SocketClosedException();
} }
read+=newRead;
} }
buffer.resize(read); buffer.resize(read);
return buffer; return buffer;

View file

@ -68,107 +68,92 @@ ListenerHTTP::ListenerHTTP(std::uint16_t port, std::unordered_map<std::string, s
} }
} }
ListenerHTTP::~ListenerHTTP() {
if(s != -1) {
Stop();
}
}
void ListenerHTTP::Stop() { void ListenerHTTP::Stop() {
running = false; running = false;
shutdown(s, SHUT_RDWR); shutdown(s, SHUT_RDWR);
close(s); close(s);
s = -1; s = -1;
for(ListenerHTTPClient* client : clients) {
client->client.Stop();
client->thread.join();
delete client;
}
} }
void ListenerHTTP::ListenSyncSync() const { void ListenerHTTP::Listen() {
while(running) { while(running) {
sockaddr_in newSockAddr; sockaddr_in newSockAddr;
socklen_t newSockAddrSize = sizeof(newSockAddr); socklen_t newSockAddrSize = sizeof(newSockAddr);
int client = accept(s, (sockaddr*)&newSockAddr, &newSockAddrSize); int client = accept(s, (sockaddr*)&newSockAddr, &newSockAddrSize);
if(!running) {
return;
}
if (client > 0) { if (client > 0) {
CallRoute(client); clients.push_back(new ListenerHTTPClient(this, client));
} else { } else {
std::cerr << "Error accepting request from client!" << std::endl; std::cerr << "Error accepting request from client!" << std::endl;
} }
std::erase_if(clients, [](ListenerHTTPClient* client) {
if (client->disconnected.load()) {
client->thread.join();
delete client;
return true;
} }
} return false;
void ListenerHTTP::ListenSyncAsync() const {
while(running) {
sockaddr_in newSockAddr;
socklen_t newSockAddrSize = sizeof(newSockAddr);
int client = accept(s, (sockaddr*)&newSockAddr, &newSockAddrSize);
if (client > 0) {
ThreadPool::Enqueue([this, client]() {CallRoute(client); });
}
else {
std::cerr << "Error accepting request from client!" << std::endl;
}
}
}
void ListenerHTTP::ListenAsyncSync() const {
ThreadPool::Enqueue([this]() {
while(running) {
sockaddr_in newSockAddr;
socklen_t newSockAddrSize = sizeof(newSockAddr);
int client = accept(s, (sockaddr*)&newSockAddr, &newSockAddrSize);
if (client > 0) {
CallRoute(client);
}
else if(running) {
std::cerr << "Error accepting request from client: "<< strerror(errno) << " (errno: " << errno << ")"<< std::endl;
}
}
}); });
}
} }
void ListenerHTTP::ListenAsyncAsync() const { ListenerHTTPClient::ListenerHTTPClient(ListenerHTTP* server, int s) : server(server), client(s), thread(&ListenerHTTPClient::ListenRoutes, this), disconnected(false) {
ThreadPool::Enqueue([this]() {
while(running) {
sockaddr_in newSockAddr;
socklen_t newSockAddrSize = sizeof(newSockAddr);
int client = accept(s, (sockaddr*)&newSockAddr, &newSockAddrSize);
if (client > 0) {
ThreadPool::Enqueue([this, client]() {CallRoute(client); });
}
else {
std::cerr << "Error accepting request from client!" << std::endl;
}
}
});
} }
void ListenerHTTP::CallRoute(int clientid) const { void ListenerHTTPClient::ListenRoutes() {
ClientTCP client(clientid); try {
std::vector<char> buffer = client.RecieveSync(1024); while(true) {
std::vector<char> buffer;
HTTPRequest request; HTTPRequest request;
std::string route; std::string route;
std::uint32_t i = 0; std::uint32_t i = 0;
std::uint32_t routeStart = 0; std::uint32_t routeStart = 0;
for(; i < 1024; i++) { while(true) {
while(true) {
buffer = client.RecieveSync();
std::string str(buffer.begin(), buffer.end());
for(; i < buffer.size(); i++) {
if(buffer[i] == ' ') { if(buffer[i] == ' ') {
request.method.assign(buffer.data(), i); request.method.assign(buffer.data(), i);
break; break;
} }
} }
for(; i < 1024; i++) { for(; i < buffer.size(); i++) {
if(buffer[i] == '/') { if(buffer[i] == '/') {
routeStart = i; routeStart = i;
break; break;
} }
} }
for(; i < 1024; i++) { for(; i < buffer.size(); i++) {
if(buffer[i] == ' ') { if(buffer[i] == ' ') {
route.assign(buffer.data()+routeStart, i-routeStart); route.assign(buffer.data()+routeStart, i-routeStart);
break; break;
} }
} }
for(; i < 1024; i++) { for(; i < buffer.size(); i++) {
if(buffer[i] == '\r' && buffer[i+1] == '\n') { if(buffer[i] == '\r' && buffer[i+1] == '\n') {
break; break;
} }
} }
i+=2; i+=2;
while(i < 1024) { while(i < buffer.size()) {
std::uint32_t headerStart = i; std::uint32_t headerStart = i;
std::string headerName; std::string headerName;
for(; i < 1024-i; i++) { for(; i < buffer.size()-i; i++) {
if(buffer[i] == ':') { if(buffer[i] == ':') {
headerName.assign(buffer.data()+headerStart, i-headerStart); headerName.assign(buffer.data()+headerStart, i-headerStart);
i++; i++;
@ -177,7 +162,7 @@ void ListenerHTTP::CallRoute(int clientid) const {
} }
headerStart = i; headerStart = i;
std::string headerValue; std::string headerValue;
for(; i < 1024; i++) { for(; i < buffer.size(); i++) {
if(buffer[i] == '\r' && buffer[i+1] == '\n') { if(buffer[i] == '\r' && buffer[i+1] == '\n') {
headerValue.assign(buffer.data()+headerStart, i-headerStart); headerValue.assign(buffer.data()+headerStart, i-headerStart);
request.headers.insert({headerName, headerValue}); request.headers.insert({headerName, headerValue});
@ -190,28 +175,63 @@ void ListenerHTTP::CallRoute(int clientid) const {
} }
} }
} }
i = 0;
}
headersComplete:; headersComplete:;
i+=4; i+=4;
std::unordered_map<std::string, std::string>::iterator it = request.headers.find("Content-Length"); std::unordered_map<std::string, std::string>::iterator it = request.headers.find("Content-Length");
if(it != request.headers.end()) if(it != request.headers.end()) {
{
const int lenght = std::stoi(it->second); const int lenght = std::stoi(it->second);
const int remaining = 1024-lenght-i;
request.body.resize(lenght, 0); request.body.resize(lenght, 0);
if(remaining > 0){ if(lenght > 0 ){
std::int_fast32_t remaining = lenght+i-buffer.size();
if(remaining < 0) {
std::memcpy(&request.body[0], buffer.data()+i, lenght); std::memcpy(&request.body[0], buffer.data()+i, lenght);
} std::string response = server->routes.at(route)(request);
if(remaining < lenght){
std::vector<char> bodyBuffer = client.RecieveSync(lenght-remaining);
std::memcpy(&request.body[remaining], bodyBuffer.data(), lenght-remaining);
}
}
std::string response = routes.at(route)(request);
client.Send(&response[0], response.size()); client.Send(&response[0], response.size());
i+=lenght;
} else if(remaining == 0){
std::memcpy(&request.body[0], buffer.data()+i, lenght);
std::string response = server->routes.at(route)(request);
client.Send(&response[0], response.size());
break;
} else {
std::memcpy(&request.body[0], buffer.data()+i, lenght-remaining);
std::vector<char> bodyBuffer = client.RecieveUntilFullSync(remaining);
std::memcpy(&request.body[remaining], bodyBuffer.data(), remaining);
std::string response = server->routes.at(route)(request);
client.Send(&response[0], response.size());
break;
}
} else {
break;
}
} else {
std::string response = server->routes.at(route)(request);
client.Send(&response[0], response.size());
if(i == buffer.size()) {
break;
}
}
}
}
} catch(SocketClosedException& e) {
disconnected.store(true);
}
} }
ListenerHTTP::~ListenerHTTP() {
if(s != -1) { ListenerAsyncHTTP::ListenerAsyncHTTP(std::uint16_t port, std::unordered_map<std::string, std::function<std::string(const HTTPRequest&)>> routes): listener(port, routes), thread(&ListenerHTTP::Listen, &listener) {
close(s);
}
ListenerAsyncHTTP::~ListenerAsyncHTTP() {
if(listener.s != -1) {
Stop();
} }
} }
void ListenerAsyncHTTP::Stop() {
listener.Stop();
thread.join();
}

View file

@ -26,10 +26,12 @@ import :HTTP;
namespace Crafter { namespace Crafter {
export class ClientHTTP { export class ClientHTTP {
public: public:
std::string host;
std::uint16_t port;
ClientHTTP(const char* host, std::uint16_t port); ClientHTTP(const char* host, std::uint16_t port);
ClientHTTP(std::string host, std::uint16_t port); ClientHTTP(std::string host, std::uint16_t port);
HTTPResponse Send(const char* request, std::uint32_t length) const; HTTPResponse Send(const char* request, std::uint32_t length);
HTTPResponse Send(std::string request) const; HTTPResponse Send(std::string request);
private: private:
ClientTCP client; ClientTCP client;
}; };

View file

@ -22,12 +22,21 @@ export module Crafter.Network:ClientTCP;
import std; import std;
namespace Crafter { namespace Crafter {
export class SocketClosedException : public std::exception {
public:
const char* what() const noexcept override {
return "Socket closed";
}
};
export class ClientTCP { export class ClientTCP {
public: public:
int socketid;
ClientTCP(int socket); ClientTCP(int socket);
ClientTCP(const char* host, std::uint16_t port); ClientTCP(const char* host, std::uint16_t port);
ClientTCP(std::string host, std::uint16_t port); ClientTCP(std::string host, std::uint16_t port);
~ClientTCP(); ~ClientTCP();
void Stop();
void Send(const void* buffer, std::uint32_t size) const; void Send(const void* buffer, std::uint32_t size) const;
std::vector<char> RecieveSync() const; std::vector<char> RecieveSync() const;
std::vector<char> RecieveUntilCloseSync() const; std::vector<char> RecieveUntilCloseSync() const;
@ -39,7 +48,5 @@ namespace Crafter {
void RecieveAsync(std::uint32_t bufferSize, std::function<void(std::vector<char>)> recieveCallback) const; void RecieveAsync(std::uint32_t bufferSize, std::function<void(std::vector<char>)> recieveCallback) const;
void RecieveUntilFullAsync(std::uint32_t bufferSize, std::function<void(std::vector<char>)> recieveCallback) const; void RecieveUntilFullAsync(std::uint32_t bufferSize, std::function<void(std::vector<char>)> recieveCallback) const;
void RecieveAsync(std::uint32_t bufferSize, std::function<void(int)> recieveCallback, char* buffer) const; void RecieveAsync(std::uint32_t bufferSize, std::function<void(int)> recieveCallback, char* buffer) const;
private:
int socketid;
}; };
} }

View file

@ -35,7 +35,7 @@ namespace Crafter {
}; };
export constexpr std::string CreateResponseHTTP(std::string status) { export constexpr std::string CreateResponseHTTP(std::string status) {
return std::format("HTTP/1.1 {}\r\nConnection: keep-alive\r\n\r\n", status); return std::format("HTTP/1.1 {}\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n", status);
} }
export constexpr std::string CreateResponseHTTP(std::string status, std::unordered_map<std::string, std::string> headers) { export constexpr std::string CreateResponseHTTP(std::string status, std::unordered_map<std::string, std::string> headers) {
@ -43,7 +43,7 @@ namespace Crafter {
for (auto const& [key, val] : headers) { for (auto const& [key, val] : headers) {
headersString+=std::format("{}: {}\r\n", key, val); headersString+=std::format("{}: {}\r\n", key, val);
} }
return std::format("HTTP/1.1 {}\r\nConnection: keep-alive\r\n{}\r\n", status, headersString); return std::format("HTTP/1.1 {}\r\nConnection: keep-alive\r\nContent-Length: 0\r\n{}\r\n", status, headersString);
} }
export constexpr std::string CreateResponseHTTP(std::string status, std::string body) { export constexpr std::string CreateResponseHTTP(std::string status, std::string body) {

View file

@ -21,21 +21,38 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
export module Crafter.Network:ListenerHTTP; export module Crafter.Network:ListenerHTTP;
import std; import std;
import :HTTP; import :HTTP;
import :ClientTCP;
namespace Crafter { namespace Crafter {
export class ListenerHTTP;
class ListenerHTTPClient {
public:
std::atomic<bool> disconnected;
ClientTCP client;
std::thread thread;
ListenerHTTP* server;
ListenerHTTPClient(ListenerHTTP* server, int s);
void ListenRoutes();
};
export class ListenerHTTP { export class ListenerHTTP {
public: public:
int s;
std::vector<ListenerHTTPClient*> clients;
bool running = true; bool running = true;
std::unordered_map<std::string, std::function<std::string(const HTTPRequest&)>> routes; const std::unordered_map<std::string, std::function<std::string(const HTTPRequest&)>> routes;
ListenerHTTP(std::uint16_t port, std::unordered_map<std::string, std::function<std::string(const HTTPRequest&)>> routes); ListenerHTTP(std::uint16_t port, std::unordered_map<std::string, std::function<std::string(const HTTPRequest&)>> routes);
~ListenerHTTP(); ~ListenerHTTP();
void Listen();
void Stop();
};
export class ListenerAsyncHTTP {
public:
ListenerHTTP listener;
std::thread thread;
ListenerAsyncHTTP(std::uint16_t port, std::unordered_map<std::string, std::function<std::string(const HTTPRequest&)>> routes);
~ListenerAsyncHTTP();
void Stop(); void Stop();
void ListenSyncSync() const;
void ListenSyncAsync() const;
void ListenAsyncSync() const;
void ListenAsyncAsync() const;
private:
void CallRoute(int client) const;
int s;
}; };
} }

View file

@ -74,6 +74,16 @@
"configuration":"lib-shared" "configuration":"lib-shared"
} }
] ]
},
{
"name": "should-send-recieve-keepalive-http",
"implementations": ["tests/ShouldSendRecieveKeepaliveHTTP"],
"dependencies": [
{
"path":"./project.json",
"configuration":"lib-shared"
}
]
} }
] ]
} }

View file

@ -18,7 +18,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
import Crafter.Thread;
import Crafter.Network; import Crafter.Network;
import std; import std;
using namespace Crafter; using namespace Crafter;
@ -26,27 +25,19 @@ using namespace Crafter;
extern "C" { extern "C" {
std::string* RunTest() { std::string* RunTest() {
bool success = false; bool success = false;
ThreadPool::Start(2); ListenerAsyncHTTP listener(8080, {{"/", [&](const HTTPRequest& request) {
ListenerHTTP listener(8080, {{"/", [&](const HTTPRequest& request) {
success = true; success = true;
return CreateResponseHTTP("200 OK", "Hello World!"); return CreateResponseHTTP("200 OK", "Hello World!");
}}}); }}});
try { try {
listener.ListenAsyncSync();
system("curl http://localhost:8080 > /dev/null 2>&1"); system("curl http://localhost:8080 > /dev/null 2>&1");
std::this_thread::sleep_for(std::chrono::seconds(1));
if (success) { if (success) {
listener.Stop();
ThreadPool::Stop();
return nullptr; return nullptr;
} else { } else {
listener.Stop();
ThreadPool::Stop();
return new std::string("Did not receive"); return new std::string("Did not receive");
} }
} catch(std::exception& e) { } catch(std::exception& e) {
listener.Stop();
ThreadPool::Stop();
return new std::string(e.what()); return new std::string(e.what());
} }
} }

View file

@ -16,7 +16,6 @@ You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
import Crafter.Thread;
import Crafter.Network; import Crafter.Network;
import std; import std;
using namespace Crafter; using namespace Crafter;

View file

@ -18,7 +18,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
import Crafter.Thread;
import Crafter.Network; import Crafter.Network;
import std; import std;
using namespace Crafter; using namespace Crafter;
@ -26,26 +25,18 @@ using namespace Crafter;
extern "C" { extern "C" {
std::string* RunTest() { std::string* RunTest() {
bool success = false; bool success = false;
ThreadPool::Start(2); ListenerAsyncHTTP listener(8080, {{"/", [&](const HTTPRequest& request) {
ListenerHTTP listener(8080, {{"/", [&](const HTTPRequest& request) {
return CreateResponseHTTP("200 OK", "Hello World!"); return CreateResponseHTTP("200 OK", "Hello World!");
}}}); }}});
try { try {
listener.ListenAsyncSync();
ClientHTTP client("localhost", 8080); ClientHTTP client("localhost", 8080);
HTTPResponse response = client.Send(CreateRequestHTTP("GET", "/", "localhost")); HTTPResponse response = client.Send(CreateRequestHTTP("GET", "/", "localhost"));
if(response.status == "200 OK" && response.body == "Hello World!") { if(response.status == "200 OK" && response.body == "Hello World!") {
listener.Stop();
ThreadPool::Stop();
return nullptr; return nullptr;
} else { } else {
listener.Stop();
ThreadPool::Stop();
return new std::string(response.status +response.body); return new std::string(response.status +response.body);
} }
} catch(std::exception& e) { } catch(std::exception& e) {
listener.Stop();
ThreadPool::Stop();
return new std::string(e.what()); return new std::string(e.what());
} }
} }

View file

@ -0,0 +1,49 @@
/*
Crafter® Build
Copyright (C) 2025 Catcrafts®
Catcrafts.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 3.0 as published by the Free Software Foundation;
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <unistd.h>
import Crafter.Network;
import std;
using namespace Crafter;
extern "C" {
std::string* RunTest() {
ListenerAsyncHTTP listener(8080, {{"/", [&](const HTTPRequest& request) {
return CreateResponseHTTP("200 OK", "Hello World!");
}}});
try {
ClientHTTP client("localhost", 8080);
HTTPResponse response = client.Send(CreateRequestHTTP("GET", "/", "localhost"));
std::this_thread::sleep_for(std::chrono::seconds(1));
if(response.status == "200 OK" && response.body == "Hello World!") {
response = client.Send(CreateRequestHTTP("GET", "/", "localhost"));
std::this_thread::sleep_for(std::chrono::seconds(1));
if(response.status == "200 OK" && response.body == "Hello World!") {
return nullptr;
} else {
return new std::string(response.status +response.body);
}
} else {
return new std::string(response.status +response.body);
}
} catch(std::exception& e) {
return new std::string(e.what());
}
}
}