Add makefile and split request and response to header files
This commit is contained in:
5
Makefile
Normal file
5
Makefile
Normal 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
91
request.cpp
Normal 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
25
request.hpp
Normal 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
58
response.cpp
Normal 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
19
response.hpp
Normal 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
|
||||||
167
server.cpp
167
server.cpp
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user