fixes
This commit is contained in:
parent
9bdf133d0f
commit
c49f947a9b
6 changed files with 123 additions and 21 deletions
|
|
@ -55,7 +55,8 @@ HTTPResponse ClientHTTP::Send(const char* request, std::uint32_t length) {
|
||||||
try {
|
try {
|
||||||
buffer = client.RecieveSync();
|
buffer = client.RecieveSync();
|
||||||
} catch(const SocketClosedException& e) {
|
} catch(const SocketClosedException& e) {
|
||||||
client = ClientTCP(host.c_str(), port);
|
client.Stop();
|
||||||
|
client.Connect();
|
||||||
client.Send(request, length);
|
client.Send(request, length);
|
||||||
buffer = client.RecieveSync();
|
buffer = client.RecieveSync();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,22 +48,13 @@ ClientTCP::ClientTCP(int socketid) : socketid(socketid)
|
||||||
|
|
||||||
ClientTCP::ClientTCP(const char* hostName, std::uint16_t port)
|
ClientTCP::ClientTCP(const char* hostName, std::uint16_t port)
|
||||||
{
|
{
|
||||||
hostent *host;
|
host = gethostbyname(hostName);
|
||||||
sockaddr_in serv_addr;
|
|
||||||
|
|
||||||
host=gethostbyname(hostName);
|
|
||||||
if((socketid = socket(AF_INET, SOCK_STREAM, 0)) == -1){
|
|
||||||
std::cerr << "Could not open socket" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
serv_addr.sin_family = AF_INET;
|
serv_addr.sin_family = AF_INET;
|
||||||
serv_addr.sin_port = htons(port);
|
serv_addr.sin_port = htons(port);
|
||||||
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
|
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
|
||||||
bzero(&(serv_addr.sin_zero),8);
|
bzero(&(serv_addr.sin_zero),8);
|
||||||
|
|
||||||
if(connect(socketid,(sockaddr*)&serv_addr, sizeof(sockaddr)) == -1){
|
Connect();
|
||||||
std::cerr << "Could not connect to server" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientTCP::ClientTCP(std::string hostName, std::uint16_t port): ClientTCP(hostName.c_str(), port)
|
ClientTCP::ClientTCP(std::string hostName, std::uint16_t port): ClientTCP(hostName.c_str(), port)
|
||||||
|
|
@ -71,6 +62,14 @@ ClientTCP::ClientTCP(std::string hostName, std::uint16_t port): ClientTCP(hostNa
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClientTCP::ClientTCP(ClientTCP&& other) noexcept : socketid(other.socketid) {
|
||||||
|
if(socketid != 1) {
|
||||||
|
shutdown(socketid, SHUT_RDWR);
|
||||||
|
close(socketid);
|
||||||
|
}
|
||||||
|
other.socketid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
ClientTCP::~ClientTCP()
|
ClientTCP::~ClientTCP()
|
||||||
{
|
{
|
||||||
if(socketid != 1) {
|
if(socketid != 1) {
|
||||||
|
|
@ -79,6 +78,16 @@ ClientTCP::~ClientTCP()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientTCP::Connect() {
|
||||||
|
if((socketid = socket(AF_INET, SOCK_STREAM, 0)) == -1){
|
||||||
|
std::cerr << "Could not open socket" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(connect(socketid,(sockaddr*)&serv_addr, sizeof(sockaddr)) == -1){
|
||||||
|
std::cerr << "Could not connect to server" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClientTCP::Stop() {
|
void ClientTCP::Stop() {
|
||||||
shutdown(socketid, SHUT_RDWR);
|
shutdown(socketid, SHUT_RDWR);
|
||||||
close(socketid);
|
close(socketid);
|
||||||
|
|
@ -86,9 +95,23 @@ void ClientTCP::Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientTCP::Send(const void* buffer, std::uint32_t size) const {
|
void ClientTCP::Send(const void* buffer, std::uint32_t size) const {
|
||||||
send(socketid, reinterpret_cast<const char*>(buffer), size, 0);
|
const char* data = reinterpret_cast<const char*>(buffer);
|
||||||
}
|
std::uint_fast32_t totalSent = 0;
|
||||||
|
const std::uint_fast32_t chunkSize = 1024;
|
||||||
|
|
||||||
|
while (totalSent < size) {
|
||||||
|
std::uint_fast32_t bytesToSend = std::min(chunkSize, size - totalSent);
|
||||||
|
int status = send(socketid, data + totalSent, bytesToSend, 0);
|
||||||
|
|
||||||
|
if (status == 0) {
|
||||||
|
throw SocketClosedException();
|
||||||
|
} else if (status < 0) {
|
||||||
|
throw std::runtime_error(std::strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
totalSent += status;
|
||||||
|
}
|
||||||
|
}
|
||||||
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);
|
||||||
|
|
@ -159,9 +182,9 @@ 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(read < 0) {
|
if(newRead < 0) {
|
||||||
throw std::runtime_error(std::strerror(errno));
|
throw std::runtime_error(std::strerror(errno));
|
||||||
} else if(read == 0) {
|
} else if(newRead == 0) {
|
||||||
throw SocketClosedException();
|
throw SocketClosedException();
|
||||||
}
|
}
|
||||||
read+=newRead;
|
read+=newRead;
|
||||||
|
|
|
||||||
|
|
@ -123,8 +123,8 @@ void ListenerHTTPClient::ListenRoutes() {
|
||||||
std::uint32_t i = 0;
|
std::uint32_t i = 0;
|
||||||
std::uint32_t routeStart = 0;
|
std::uint32_t routeStart = 0;
|
||||||
while(true) {
|
while(true) {
|
||||||
|
buffer = client.RecieveSync();
|
||||||
while(true) {
|
while(true) {
|
||||||
buffer = client.RecieveSync();
|
|
||||||
std::string str(buffer.begin(), buffer.end());
|
std::string str(buffer.begin(), buffer.end());
|
||||||
for(; i < buffer.size(); i++) {
|
for(; i < buffer.size(); i++) {
|
||||||
if(buffer[i] == ' ') {
|
if(buffer[i] == ' ') {
|
||||||
|
|
@ -184,7 +184,7 @@ void ListenerHTTPClient::ListenRoutes() {
|
||||||
const int lenght = std::stoi(it->second);
|
const int lenght = std::stoi(it->second);
|
||||||
request.body.resize(lenght, 0);
|
request.body.resize(lenght, 0);
|
||||||
if(lenght > 0 ){
|
if(lenght > 0 ){
|
||||||
std::int_fast32_t remaining = lenght+i-buffer.size();
|
std::int_fast32_t remaining = lenght-(buffer.size()-i);
|
||||||
if(remaining < 0) {
|
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);
|
std::string response = server->routes.at(route)(request);
|
||||||
|
|
@ -196,9 +196,9 @@ void ListenerHTTPClient::ListenRoutes() {
|
||||||
client.Send(&response[0], response.size());
|
client.Send(&response[0], response.size());
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
std::memcpy(&request.body[0], buffer.data()+i, lenght-remaining);
|
std::memcpy(&request.body[0], buffer.data()+i, buffer.size()-i);
|
||||||
std::vector<char> bodyBuffer = client.RecieveUntilFullSync(remaining);
|
std::vector<char> bodyBuffer = client.RecieveUntilFullSync(remaining);
|
||||||
std::memcpy(&request.body[remaining], bodyBuffer.data(), remaining);
|
std::memcpy(&request.body[buffer.size()-i], bodyBuffer.data(), remaining);
|
||||||
std::string response = server->routes.at(route)(request);
|
std::string response = server->routes.at(route)(request);
|
||||||
client.Send(&response[0], response.size());
|
client.Send(&response[0], response.size());
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,20 @@ 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
|
||||||
*/
|
*/
|
||||||
|
module;
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <cerrno>
|
||||||
export module Crafter.Network:ClientTCP;
|
export module Crafter.Network:ClientTCP;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
|
@ -36,6 +49,9 @@ namespace Crafter {
|
||||||
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();
|
||||||
|
ClientTCP(const ClientTCP&) = delete;
|
||||||
|
ClientTCP(ClientTCP&& other) noexcept;
|
||||||
|
void Connect();
|
||||||
void Stop();
|
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;
|
||||||
|
|
@ -48,5 +64,8 @@ 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:
|
||||||
|
hostent* host;
|
||||||
|
sockaddr_in serv_addr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
10
project.json
10
project.json
|
|
@ -84,6 +84,16 @@
|
||||||
"configuration":"lib-shared"
|
"configuration":"lib-shared"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "should-send-recieve-large-http",
|
||||||
|
"implementations": ["tests/ShouldSendRecieveLargeHTTP"],
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"path":"./project.json",
|
||||||
|
"configuration":"lib-shared"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
49
tests/ShouldSendRecieveLargeHTTP.cpp
Normal file
49
tests/ShouldSendRecieveLargeHTTP.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) {
|
||||||
|
if (request.body.size() > 1'000'000) {
|
||||||
|
return CreateResponseHTTP("200 OK", "Large request received: " + std::to_string(request.body.size()) + " bytes");
|
||||||
|
}
|
||||||
|
return CreateResponseHTTP("200 OK", "Small request received");
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
|
||||||
|
try {
|
||||||
|
ClientHTTP client("localhost", 8080);
|
||||||
|
std::string large_body(10 * 1024 * 1024, 'A');
|
||||||
|
HTTPResponse response = client.Send(CreateRequestHTTP("POST", "/", "localhost", large_body));
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
if (response.status == "200 OK" && response.body.find("Large request received") != std::string::npos) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return new std::string("Unexpected response: " + response.status + " " + response.body);
|
||||||
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return new std::string(e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue