Add makefile and split request and response to header files

This commit is contained in:
Pablu23
2024-07-08 03:07:46 +02:00
parent a32934d4bc
commit 752cb229c3
6 changed files with 200 additions and 165 deletions

5
Makefile Normal file
View File

@@ -0,0 +1,5 @@
run: build
./server
build:
g++ -std=c++20 server.cpp request.cpp response.cpp -g -o server

91
request.cpp Normal file
View File

@@ -0,0 +1,91 @@
#include "request.hpp"
#include <iostream>
bool Request::protocol(std::stringstream *ss, int *procPart, char c) {
if (c == ' ' || c == '\n') {
switch (*procPart) {
case 0:
m_method = ss->str();
break;
case 1:
m_path = ss->str();
break;
case 2:
m_protocol = ss->str();
break;
}
(*procPart)++;
ss->str("");
if (c == '\n')
return false;
} else {
ss->put(c);
}
return true;
}
Request::Request(std::vector<std::byte> buf) {
std::string name;
std::stringstream ss;
bool header = true;
int procPart = 0;
bool data = false;
bool skipNext = false;
bool p = true;
for (auto &byte : buf) {
if (data) {
m_payload.push_back(byte);
continue;
}
char c = static_cast<char>(byte);
if (c == '\r')
continue;
if (p) {
p = protocol(&ss, &procPart, c);
continue;
}
if (skipNext && c == ' ') {
skipNext = false;
continue;
}
skipNext = false;
if (c == ':' && header) {
skipNext = true;
header = false;
name = ss.str();
ss.str("");
} else if (c == '\n' && !name.empty()) {
m_headers.insert_or_assign(name, ss.str());
ss.str("");
name.clear();
header = true;
} else if (c == '\n' && name.empty()) {
data = true;
} else {
ss << c;
}
}
}
void Request::Print() {
std::cout << "Protocol: " << m_protocol << "\n"
<< "Req: " << m_method << " " << m_path << std::endl;
for (const auto &[key, value] : m_headers) {
std::cout << "[" << key << "]: [" << value << "]\n";
}
if (HasData()) {
std::cout << "Payload: " << std::endl;
for (auto &byte : m_payload) {
std::cout << static_cast<char>(byte);
}
std::cout << std::endl;
}
}
bool Request::HasData() { return m_payload.size() != 0; }
std::vector<std::byte> Request::Data() { return m_payload; }

25
request.hpp Normal file
View File

@@ -0,0 +1,25 @@
#ifndef REQUEST_HEADER_H
#define REQUEST_HEADER_H
#include <map>
#include <sstream>
#include <string>
#include <vector>
class Request {
private:
std::map<std::string, std::string> m_headers;
std::string m_method;
std::string m_path;
std::vector<std::byte> m_payload;
std::string m_protocol;
private:
bool protocol(std::stringstream *ss, int *procPart, char c);
public:
Request(std::vector<std::byte> buf);
void Print();
bool HasData();
std::vector<std::byte> Data();
};
#endif // !REQUEST_HEADER_H

58
response.cpp Normal file
View File

@@ -0,0 +1,58 @@
#include "response.hpp"
#include <algorithm>
#include <cstring>
#include <iostream>
#include <netinet/in.h>
#include <sstream>
#include <string>
#include <vector>
Response::Response(std::vector<std::byte> data) {
m_headers.insert(std::pair<std::string, std::string>(
"content-length", std::to_string(data.size())));
m_payload = data;
}
Response::Response(std::string data) {
m_headers.insert(std::pair<std::string, std::string>(
"content-length", std::to_string(std::strlen(data.data()))));
m_payload = std::vector<std::byte>(data.size() + 1);
std::transform(data.begin(), data.end(), m_payload.begin(),
[](char c) { return std::byte(c); });
}
void Response::SetContentType(const std::string type) {
m_headers.insert_or_assign("content-type", type);
}
void Response::Send(int clientSocket) {
std::stringstream ss;
ss << "HTTP/1.1 200 OK\n";
for (const auto &[key, value] : m_headers) {
ss << key << ": " << value << "\n";
}
if (m_payload.size() >= 0) {
ss << "\n";
for (auto &byte : m_payload) {
char c = static_cast<char>(byte);
ss << c;
}
}
std::string p = ss.str();
send(clientSocket, p.data(), p.size(), 0);
}
void Response::Print() {
for (const auto &[key, value] : m_headers) {
std::cout << "[" << key << "]: [" << value << "]\n";
}
if (m_payload.size() != 0) {
std::cout << "Payload: " << std::endl;
for (auto &byte : m_payload) {
std::cout << static_cast<char>(byte);
}
std::cout << std::endl;
}
}

19
response.hpp Normal file
View File

@@ -0,0 +1,19 @@
#ifndef RESPONSE_H
#include <map>
#include <string>
#include <vector>
class Response {
private:
std::map<std::string, std::string> m_headers;
std::vector<std::byte> m_payload;
public:
Response(std::vector<std::byte> data);
Response(std::string data);
void SetContentType(const std::string type);
void Send(int clientSocket);
void Print();
};
#endif // !RESPONSE_H

View File

@@ -1,176 +1,16 @@
#include <algorithm> #include "request.hpp"
#include "response.hpp"
#include <cstddef> #include <cstddef>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <map>
#include <netinet/in.h> #include <netinet/in.h>
#include <ostream> #include <ostream>
#include <sstream>
#include <string>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include <vector> #include <vector>
class Request {
private:
std::map<std::string, std::string> m_headers;
std::string m_method;
std::string m_path;
std::vector<std::byte> m_payload;
std::string m_protocol;
private:
bool protocol(std::stringstream *ss, int *procPart, char c) {
if (c == ' ' || c == '\n') {
switch (*procPart) {
case 0:
m_method = ss->str();
break;
case 1:
m_path = ss->str();
break;
case 2:
m_protocol = ss->str();
break;
}
(*procPart)++;
ss->str("");
if (c == '\n')
return false;
} else {
ss->put(c);
}
return true;
}
public:
Request(std::vector<std::byte> buf) {
std::string name;
std::stringstream ss;
bool header = true;
int procPart = 0;
bool data = false;
bool skipNext = false;
bool p = true;
for (auto &byte : buf) {
if (data) {
m_payload.push_back(byte);
continue;
}
char c = static_cast<char>(byte);
if (c == '\r')
continue;
if (p) {
p = protocol(&ss, &procPart, c);
continue;
}
if (skipNext && c == ' ') {
skipNext = false;
continue;
}
skipNext = false;
if (c == ':' && header) {
skipNext = true;
header = false;
name = ss.str();
ss.str("");
} else if (c == '\n' && !name.empty()) {
m_headers.insert_or_assign(name, ss.str());
ss.str("");
name.clear();
header = true;
} else if (c == '\n' && name.empty()) {
data = true;
} else {
ss << c;
}
}
}
void Print() {
std::cout << "Protocol: " << m_protocol << "\n"
<< "Req: " << m_method << " " << m_path << std::endl;
for (const auto &[key, value] : m_headers) {
std::cout << "[" << key << "]: [" << value << "]\n";
}
if (HasData()) {
std::cout << "Payload: " << std::endl;
for (auto &byte : m_payload) {
std::cout << static_cast<char>(byte);
}
std::cout << std::endl;
}
}
bool HasData() { return m_payload.size() != 0; }
std::vector<std::byte> Data() { return m_payload; }
};
class Response {
private:
std::map<std::string, std::string> m_headers;
std::vector<std::byte> m_payload;
public:
Response(std::vector<std::byte> data) {
m_headers.insert(std::pair<std::string, std::string>(
"content-length", std::to_string(data.size())));
m_payload = data;
}
Response(std::string data) {
m_headers.insert(std::pair<std::string, std::string>(
"content-length", std::to_string(std::strlen(data.data()))));
m_payload = std::vector<std::byte>(data.size() + 1);
std::transform(data.begin(), data.end(), m_payload.begin(),
[](char c) { return std::byte(c); });
}
void SetContentType(const std::string type) {
m_headers.insert_or_assign("content-type", type);
}
void Send(int clientSocket) {
std::stringstream ss;
ss << "HTTP/1.1 200 OK\n";
for (const auto &[key, value] : m_headers) {
ss << key << ": " << value << "\n";
}
if (m_payload.size() >= 0) {
ss << "\n";
for (auto &byte : m_payload) {
std::cout << int(byte) << ' ';
char c = static_cast<char>(byte);
ss << c;
}
std::cout << std::endl;
}
std::string p = ss.str();
send(clientSocket, p.data(), p.size(), 0);
}
void Print() {
for (const auto &[key, value] : m_headers) {
std::cout << "[" << key << "]: [" << value << "]\n";
}
if (m_payload.size() != 0) {
std::cout << "Payload: " << std::endl;
for (auto &byte : m_payload) {
std::cout << static_cast<char>(byte);
}
std::cout << std::endl;
}
}
};
int main() { int main() {
int serverSocket = socket(AF_INET, SOCK_STREAM, 0); int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serverAddress; sockaddr_in serverAddress;
@@ -197,7 +37,6 @@ int main() {
int read = recv(clientSocket, buffer.data(), buffer.size(), 0); int read = recv(clientSocket, buffer.data(), buffer.size(), 0);
buffer.resize(read); buffer.resize(read);
Request req(buffer); Request req(buffer);
// req.Print();
Response res = Response("Hello world!"); Response res = Response("Hello world!");
if (req.HasData()) { if (req.HasData()) {
auto data = req.Data(); auto data = req.Data();
@@ -205,8 +44,6 @@ int main() {
} }
res.SetContentType("text/plain"); res.SetContentType("text/plain");
// std::cout << "RESPONSE: " << std::endl;
// res.Print();
res.Send(clientSocket); res.Send(clientSocket);
close(clientSocket); close(clientSocket);
} }