Crafter.Network/implementations/Crafter.Network-ClientHTTP.cpp

208 lines
8 KiB
C++
Raw Normal View History

2025-11-02 15:00:53 +01:00
/*
Crafter®.Network
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 as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
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
*/
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>
module Crafter.Network:ClientHTTP_impl;
import :ClientHTTP;
import Crafter.Thread;
import std;
using namespace Crafter;
2025-11-03 14:25:51 +01:00
ClientHTTP::ClientHTTP(const char* host, std::uint16_t port): host(host), port(port), client(host, port) {
2025-11-02 15:00:53 +01:00
}
ClientHTTP::ClientHTTP(std::string host, std::uint16_t port): ClientHTTP(host.c_str(), port) {
}
2025-11-03 14:25:51 +01:00
HTTPResponse ClientHTTP::Send(const char* request, std::uint32_t length) {
2025-11-03 17:52:45 +01:00
std::cout << "Send started" << std::endl;
2025-11-02 15:00:53 +01:00
client.Send(request, length);
2025-11-03 17:52:45 +01:00
std::cout << "Send Complete" << std::endl;
2025-11-02 16:04:32 +01:00
std::vector<char> buffer;
2025-11-02 15:00:53 +01:00
HTTPResponse response;
2025-11-02 16:04:32 +01:00
std::uint32_t i = 0;
std::uint32_t statusStart = 0;
while(true) {
2025-11-03 14:25:51 +01:00
try {
buffer = client.RecieveSync();
2025-11-03 17:52:45 +01:00
std::cout << "Recieved: " << buffer.size() << std::endl;
2025-11-03 14:25:51 +01:00
} catch(const SocketClosedException& e) {
2025-11-03 17:52:45 +01:00
std::cout << "Retry" << std::endl;
2025-11-03 15:51:13 +01:00
client.Stop();
client.Connect();
2025-11-03 14:25:51 +01:00
client.Send(request, length);
buffer = client.RecieveSync();
2025-11-03 17:52:45 +01:00
std::cout << "Recieved: " << buffer.size() << std::endl;
2025-11-03 14:25:51 +01:00
}
2025-11-02 16:04:32 +01:00
for(; i < buffer.size(); i++) {
if(buffer[i] == ' ') {
statusStart = i;
break;
}
}
for(; i < buffer.size(); i++) {
if(buffer[i] == '\r') {
response.status.assign(buffer.data()+statusStart+1, i-statusStart-1);
break;
}
}
i+=2;
while(i < buffer.size()) {
std::uint32_t headerStart = i;
std::string headerName;
for(; i < buffer.size(); i++) {
if(buffer[i] == ':') {
headerName.assign(buffer.data()+headerStart, i-headerStart);
std::transform(headerName.begin(), headerName.end(), headerName.begin(), [](unsigned char c){ return std::tolower(c); });
i+=2;
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);
response.headers.insert({headerName, headerValue});
if(buffer[i+2] == '\r'){
goto headersComplete;
} else{
i+=2;
break;
}
}
}
}
i = 0;
}
2025-11-02 15:00:53 +01:00
headersComplete:;
2025-11-03 17:52:45 +01:00
std::cout << "Header complete" << std::endl;
2025-11-02 15:00:53 +01:00
i+=4;
2025-11-02 16:04:32 +01:00
std::unordered_map<std::string, std::string>::iterator it = response.headers.find("content-length");
2025-11-02 15:00:53 +01:00
if(it != response.headers.end())
{
const int lenght = std::stoi(it->second);
2025-11-03 17:52:45 +01:00
std::cout << "Content lenght: " << lenght << std::endl;
2025-11-02 15:00:53 +01:00
response.body.resize(lenght, 0);
if(i < buffer.size()){
std::memcpy(&response.body[0], buffer.data()+i, buffer.size()-i);
}
const int remaining = lenght-(buffer.size()-i);
2025-11-03 17:52:45 +01:00
std::cout << "Remain: " << remaining << std::endl;
2025-11-02 15:00:53 +01:00
if(remaining > 0){
2025-11-03 17:52:45 +01:00
std::vector<char> bodyBuffer = client.RecieveUntilFullSync(remaining);
std::memcpy(&response.body[ buffer.size()-i], bodyBuffer.data(), bodyBuffer.size());
std::cout << "Recieved: " << bodyBuffer.size() << std::endl;
2025-11-02 15:00:53 +01:00
}
} else {
2025-11-03 17:52:45 +01:00
std::cout << "No Content Lenght" << std::endl;
2025-11-02 16:04:32 +01:00
std::unordered_map<std::string, std::string>::iterator it = response.headers.find("transfer-encoding");
2025-11-02 15:00:53 +01:00
if(it != response.headers.end() && it->second == "chunked") {
2025-11-03 17:52:45 +01:00
std::cout << "Chunked" << std::endl;
2025-11-02 15:00:53 +01:00
while(i < buffer.size()){
std::string lenght;
int lenghtStart = i;
for(; i < buffer.size(); i++) {
if(buffer[i] == '\r') {
lenght.assign(buffer.data()+lenghtStart, i-lenghtStart);
break;
}
}
i+=2;
int lenghtInt = stoi(lenght, 0, 8);
if(lenghtInt != 0){
int oldSize = response.body.size();
response.body.resize(oldSize+lenghtInt, 0);
if(buffer.size() < lenghtInt) {
std::memcpy(&response.body[oldSize], buffer.data()+i, buffer.size()-i);
std::vector<char> bodyBuffer2 = client.RecieveUntilFullSync(lenghtInt-buffer.size());
std::memcpy(&response.body[oldSize+(buffer.size()-i)], buffer.data(), buffer.size());
} else {
std::memcpy(&response.body[oldSize], buffer.data()+i, lenghtInt);
i+=lenghtInt;
}
} else{
goto bodyFinished;
}
}
while(true) {
std::vector<char> bodyBuffer = client.RecieveSync();
int i2 = 0;
while(i2 < bodyBuffer.size()){
std::string lenght;
int lenghtStart = i2;
for(; i2 < bodyBuffer.size(); i2++) {
if(buffer[i2] == '\r') {
lenght.assign(bodyBuffer.data()+lenghtStart, i2-lenghtStart);
break;
}
}
i2+=2;
int lenghtInt = stoi(lenght, 0, 8);
if(lenghtInt != 0){
int oldSize = response.body.size();
response.body.resize(oldSize+lenghtInt, 0);
if(bodyBuffer.size() < lenghtInt) {
std::memcpy(&response.body[oldSize], bodyBuffer.data()+i2, bodyBuffer.size()-i2);
std::vector<char> bodyBuffer2 = client.RecieveUntilFullSync(lenghtInt-bodyBuffer.size());
std::memcpy(&response.body[oldSize+(bodyBuffer.size()-i2)], bodyBuffer2.data(), bodyBuffer2.size());
} else {
std::memcpy(&response.body[oldSize], bodyBuffer.data()+i2, lenghtInt);
i2+=lenghtInt;
}
} else{
goto bodyFinished;
}
}
}
bodyFinished:;
} else {
2025-11-03 17:52:45 +01:00
std::cout << "Recv until close" << std::endl;
2025-11-02 15:00:53 +01:00
std::vector<char> bodyBuffer = client.RecieveUntilCloseSync();
response.body.resize((buffer.size()-i)+(bodyBuffer.size()), 0);
if(i < buffer.size()){
std::memcpy(&response.body[0], buffer.data()+i, buffer.size()-i);
}
std::memcpy(&response.body[buffer.size()-i], bodyBuffer.data(), bodyBuffer.size());
2025-11-03 17:52:45 +01:00
std::cout << "Closed" << std::endl;
2025-11-02 15:00:53 +01:00
}
}
2025-11-03 17:52:45 +01:00
std::cout << "Response recieved" << std::endl;
2025-11-02 15:00:53 +01:00
return response;
}
2025-11-03 14:25:51 +01:00
HTTPResponse ClientHTTP::Send(std::string request) {
2025-11-02 15:00:53 +01:00
return Send(request.c_str(), request.size());
}