fixes
This commit is contained in:
parent
64739c39d8
commit
9bdf133d0f
12 changed files with 301 additions and 168 deletions
|
|
@ -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) {
|
||||||
buffer = client.RecieveSync();
|
try {
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientTCP::Stop() {
|
||||||
|
shutdown(socketid, SHUT_RDWR);
|
||||||
close(socketid);
|
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;
|
||||||
|
|
|
||||||
|
|
@ -68,150 +68,170 @@ 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 {
|
ListenerHTTPClient::ListenerHTTPClient(ListenerHTTP* server, int s) : server(server), client(s), thread(&ListenerHTTPClient::ListenRoutes, this), disconnected(false) {
|
||||||
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 {
|
void ListenerHTTPClient::ListenRoutes() {
|
||||||
ThreadPool::Enqueue([this]() {
|
try {
|
||||||
while(running) {
|
while(true) {
|
||||||
sockaddr_in newSockAddr;
|
std::vector<char> buffer;
|
||||||
socklen_t newSockAddrSize = sizeof(newSockAddr);
|
HTTPRequest request;
|
||||||
int client = accept(s, (sockaddr*)&newSockAddr, &newSockAddrSize);
|
std::string route;
|
||||||
if (client > 0) {
|
std::uint32_t i = 0;
|
||||||
CallRoute(client);
|
std::uint32_t routeStart = 0;
|
||||||
}
|
while(true) {
|
||||||
else if(running) {
|
while(true) {
|
||||||
std::cerr << "Error accepting request from client: "<< strerror(errno) << " (errno: " << errno << ")"<< std::endl;
|
buffer = client.RecieveSync();
|
||||||
}
|
std::string str(buffer.begin(), buffer.end());
|
||||||
}
|
for(; i < buffer.size(); i++) {
|
||||||
});
|
if(buffer[i] == ' ') {
|
||||||
}
|
request.method.assign(buffer.data(), i);
|
||||||
|
break;
|
||||||
void ListenerHTTP::ListenAsyncAsync() const {
|
}
|
||||||
ThreadPool::Enqueue([this]() {
|
}
|
||||||
while(running) {
|
for(; i < buffer.size(); i++) {
|
||||||
sockaddr_in newSockAddr;
|
if(buffer[i] == '/') {
|
||||||
socklen_t newSockAddrSize = sizeof(newSockAddr);
|
routeStart = i;
|
||||||
int client = accept(s, (sockaddr*)&newSockAddr, &newSockAddrSize);
|
break;
|
||||||
if (client > 0) {
|
}
|
||||||
ThreadPool::Enqueue([this, client]() {CallRoute(client); });
|
}
|
||||||
}
|
for(; i < buffer.size(); i++) {
|
||||||
else {
|
if(buffer[i] == ' ') {
|
||||||
std::cerr << "Error accepting request from client!" << std::endl;
|
route.assign(buffer.data()+routeStart, i-routeStart);
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
for(; i < buffer.size(); i++) {
|
||||||
|
if(buffer[i] == '\r' && buffer[i+1] == '\n') {
|
||||||
void ListenerHTTP::CallRoute(int clientid) const {
|
break;
|
||||||
ClientTCP client(clientid);
|
}
|
||||||
std::vector<char> buffer = client.RecieveSync(1024);
|
}
|
||||||
HTTPRequest request;
|
|
||||||
std::string route;
|
|
||||||
std::uint32_t i = 0;
|
|
||||||
std::uint32_t routeStart = 0;
|
|
||||||
for(; i < 1024; i++) {
|
|
||||||
if(buffer[i] == ' ') {
|
|
||||||
request.method.assign(buffer.data(), i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(; i < 1024; i++) {
|
|
||||||
if(buffer[i] == '/') {
|
|
||||||
routeStart = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(; i < 1024; i++) {
|
|
||||||
if(buffer[i] == ' ') {
|
|
||||||
route.assign(buffer.data()+routeStart, i-routeStart);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(; i < 1024; i++) {
|
|
||||||
if(buffer[i] == '\r' && buffer[i+1] == '\n') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i+=2;
|
|
||||||
while(i < 1024) {
|
|
||||||
std::uint32_t headerStart = i;
|
|
||||||
std::string headerName;
|
|
||||||
for(; i < 1024-i; i++) {
|
|
||||||
if(buffer[i] == ':') {
|
|
||||||
headerName.assign(buffer.data()+headerStart, i-headerStart);
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
headerStart = i;
|
|
||||||
std::string headerValue;
|
|
||||||
for(; i < 1024; i++) {
|
|
||||||
if(buffer[i] == '\r' && buffer[i+1] == '\n') {
|
|
||||||
headerValue.assign(buffer.data()+headerStart, i-headerStart);
|
|
||||||
request.headers.insert({headerName, headerValue});
|
|
||||||
if(buffer[i+2] == '\r'){
|
|
||||||
goto headersComplete;
|
|
||||||
} else{
|
|
||||||
i+=2;
|
i+=2;
|
||||||
break;
|
while(i < buffer.size()) {
|
||||||
|
std::uint32_t headerStart = i;
|
||||||
|
std::string headerName;
|
||||||
|
for(; i < buffer.size()-i; i++) {
|
||||||
|
if(buffer[i] == ':') {
|
||||||
|
headerName.assign(buffer.data()+headerStart, i-headerStart);
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
headerStart = i;
|
||||||
|
std::string headerValue;
|
||||||
|
for(; i < buffer.size(); i++) {
|
||||||
|
if(buffer[i] == '\r' && buffer[i+1] == '\n') {
|
||||||
|
headerValue.assign(buffer.data()+headerStart, i-headerStart);
|
||||||
|
request.headers.insert({headerName, headerValue});
|
||||||
|
if(buffer[i+2] == '\r'){
|
||||||
|
goto headersComplete;
|
||||||
|
} else{
|
||||||
|
i+=2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
headersComplete:;
|
||||||
|
i+=4;
|
||||||
|
std::unordered_map<std::string, std::string>::iterator it = request.headers.find("Content-Length");
|
||||||
|
if(it != request.headers.end()) {
|
||||||
|
const int lenght = std::stoi(it->second);
|
||||||
|
request.body.resize(lenght, 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::string response = server->routes.at(route)(request);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
headersComplete:;
|
|
||||||
i+=4;
|
|
||||||
std::unordered_map<std::string, std::string>::iterator it = request.headers.find("Content-Length");
|
|
||||||
if(it != request.headers.end())
|
|
||||||
{
|
|
||||||
const int lenght = std::stoi(it->second);
|
|
||||||
const int remaining = 1024-lenght-i;
|
|
||||||
request.body.resize(lenght, 0);
|
|
||||||
if(remaining > 0){
|
|
||||||
std::memcpy(&request.body[0], buffer.data()+i, lenght);
|
|
||||||
}
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
project.json
10
project.json
|
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
49
tests/ShouldSendRecieveKeepaliveHTTP.cpp
Normal file
49
tests/ShouldSendRecieveKeepaliveHTTP.cpp
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue