Added processFormData and reorganised the files
This commit is contained in:
58
src/HTTP/HTTP.cpp
Normal file
58
src/HTTP/HTTP.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "../Helpers.hpp"
|
||||
#include "../Main.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
void HTTPrequest::start() {
|
||||
// Possible Logging here
|
||||
processHTTPHeader();
|
||||
}
|
||||
|
||||
void HTTPrequest::processRequest() {
|
||||
try {
|
||||
Webserver::responseMethods[requestType].at(requestPath)(this);
|
||||
} catch (std::out_of_range &e) {
|
||||
sendResponse("404 Not Found", "text/html",
|
||||
Helpers::ReadFile("www/error.html"));
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPrequest::sendResponse(std::string status, std::string mime,
|
||||
std::string data) {
|
||||
// Logging here perhaps
|
||||
std::stringstream output;
|
||||
output << "HTTP/1.1 " << status << "\r\n"
|
||||
<< "Content-Type: " << mime << "\r\nContent-Length: " << data.size()
|
||||
<< "\r\nConnection: close\r\n\r\n"
|
||||
<< data;
|
||||
|
||||
// Idea here is that in TCP oncee you sent a shutdown you should read until
|
||||
// EOF. When that happens, you know that the package is fully recieved
|
||||
responseText = output.str();
|
||||
asio::async_write(
|
||||
sock, asio::buffer(responseText),
|
||||
[this, self = shared_from_this()](std::error_code, std::size_t) {
|
||||
sock.shutdown(asio::ip::tcp::socket::shutdown_send);
|
||||
waitForClientClose();
|
||||
});
|
||||
}
|
||||
|
||||
// I'm not happy with this
|
||||
void HTTPrequest::waitForClientClose() {
|
||||
auto buf = std::array<char, 1>(); // I don't think there is a smaller possible
|
||||
// constructor :(
|
||||
sock.async_read_some(asio::buffer(buf),
|
||||
[this, self = shared_from_this()](
|
||||
const std::error_code &error, std::size_t) {
|
||||
if (error) {
|
||||
sock.close(); // This triggers when EOF
|
||||
}
|
||||
waitForClientClose(); // Ew recursion. Must fix.
|
||||
});
|
||||
}
|
||||
// ================= CLASS HANDLING SPECIFIC =================
|
||||
|
||||
HTTPrequest::HTTPrequest(asio::io_context &context) : sock(context) {}
|
||||
asio::ip::tcp::socket &HTTPrequest::socket() { return sock; }
|
||||
HTTPrequest::HTTPrequest_ptr HTTPrequest::create(asio::io_context &context) {
|
||||
return HTTPrequest_ptr(new HTTPrequest(context));
|
||||
}
|
97
src/HTTP/HTTPRequestProcess.cpp
Normal file
97
src/HTTP/HTTPRequestProcess.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "../Helpers.hpp"
|
||||
#include "../Main.hpp"
|
||||
#include <asio/socket_base.hpp>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
|
||||
// TODO: Remove boundary from the body. Do keep other stuff like
|
||||
// file type and name
|
||||
|
||||
void HTTPrequest::processHTTPHeader() {
|
||||
std::shared_ptr<HTTPrequest> self(shared_from_this());
|
||||
|
||||
// HEADER read
|
||||
asio::async_read_until(
|
||||
sock, buffer, "\r\n\r\n", // its not the other way bud
|
||||
[this, self](std::error_code error, std::size_t packageSize) {
|
||||
if (!error) {
|
||||
buffer.commit(packageSize);
|
||||
std::istream stream(&buffer);
|
||||
std::size_t octetCount = 0;
|
||||
|
||||
// This is HTTP main request
|
||||
std::string rq;
|
||||
Helpers::getlineAndCount(stream, octetCount, requestType,
|
||||
' '); // HTTP request type
|
||||
Helpers::getlineAndCount(stream, octetCount, requestPath,
|
||||
' '); // HTTP path
|
||||
Helpers::getlineAndCount(stream, octetCount,
|
||||
rq); // Version, omitting for now
|
||||
|
||||
// Get arguments and other header stuff out of the way
|
||||
processArgs();
|
||||
processHeaderValues(stream, octetCount, packageSize);
|
||||
processBody();
|
||||
|
||||
// RESPOND
|
||||
processRequest();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ===================
|
||||
// Inline Helpers
|
||||
// ===================
|
||||
|
||||
void inline HTTPrequest::processArgs() {
|
||||
std::string key, value;
|
||||
if (requestPath.find('?') != std::string::npos) {
|
||||
std::stringstream pathStream(requestPath);
|
||||
std::getline(pathStream, requestPath, '?'); // Keeping the path pure
|
||||
|
||||
while (!pathStream.eof()) {
|
||||
std::getline(pathStream, key, '=');
|
||||
std::getline(pathStream, value, '&');
|
||||
args.insert({key, value});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void inline HTTPrequest::processHeaderValues(std::basic_istream<char> &stream,
|
||||
std::size_t &octetCount,
|
||||
std::size_t headerSize) {
|
||||
std::string key, value, empty;
|
||||
while (octetCount < headerSize - 2) { // -2 is due to last two \r\n\r\n combo
|
||||
Helpers::getlineAndCount(stream, octetCount, key, ':');
|
||||
Helpers::getlineAndCount(stream, octetCount, empty,
|
||||
' '); // trim start some gangster shit right here
|
||||
Helpers::getlineAndCount(stream, octetCount, value);
|
||||
headers.insert({key, value});
|
||||
}
|
||||
}
|
||||
|
||||
// ===================
|
||||
// BODY OF THE REQUEST
|
||||
// ===================
|
||||
|
||||
void inline HTTPrequest::processBody() {
|
||||
if (headers.find("Content-Length") != headers.end()) {
|
||||
std::size_t uploadSize =
|
||||
std::stoull(headers.at("Content-Length")) - buffer.size(),
|
||||
octetCount = 0;
|
||||
|
||||
// This part needs to be sync since we want this specific instance
|
||||
// execution to pause
|
||||
while (octetCount < uploadSize) {
|
||||
octetCount += asio::read(sock, buffer.prepare(uploadSize));
|
||||
}
|
||||
|
||||
buffer.commit(octetCount);
|
||||
std::istream bodyStream(&buffer);
|
||||
bodyContent.resize(buffer.size());
|
||||
bodyStream.read(bodyContent.data(), buffer.size());
|
||||
|
||||
buffer.consume(buffer.size()); // Just so the buffer is nice and clean
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user