v-1.0.4
Код: Выделить всё
#include <iostream>
#include <string>
#include <cstring>
#include <sstream> // Required for std::istringstream
#include <unistd.h>
#include <arpa/inet.h>
#include <map>
const int PORT = 8070;
const int BACKLOG = 10;
const int BUFFER_SIZE = 1024;
std::map<std::string, std::string> parseData(const std::string& data) {
std::map<std::string, std::string> result;
std::string keyValuePair;
std::istringstream stream(data);
while (std::getline(stream, keyValuePair, '&')) {
size_t pos = keyValuePair.find('=');
if (pos != std::string::npos) {
std::string key = keyValuePair.substr(0, pos);
std::string value = keyValuePair.substr(pos + 1);
result[key] = value;
}
}
return result;
}
std::string handleGET(const std::string& path) {
std::string body = "<!DOCTYPE html>"
"<html lang='en'>"
"<head>"
"<meta charset='UTF-8'>"
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>"
"<title>Простой C++ Веб-сервер</title>"
"</head>"
"<body>"
"<h1>Вы сделали GET запрос на путь: " + path + "</h1>"
"<form action='/' method='POST'>"
"<input type='text' name='send_text'>"
"<br>"
"<input type='text' name='send_text222'>"
"<input type='submit' value='Submit'>"
"</form>"
"</body>"
"</html>";
return "HTTP/1.1 200 OK\n"
"Content-Type: text/html; charset=utf-8\n"
"Content-Length: " + std::to_string(body.size()) + "\n"
"Connection: close\n"
"\n" + body;
}
std::string handlePOST(const std::string& data) {
std::string body = "<!DOCTYPE html>"
"<html lang='en'>"
"<head>"
"<meta charset='UTF-8'>"
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>"
"<title>Простой C++ Веб-сервер</title>"
"</head>"
"<body>"
"<h1>Вы сделали POST запрос с данными:</h1>"
"<pre>" + data + "</pre>"
"</body>"
"</html>";
return "HTTP/1.1 200 OK\n"
"Content-Type: text/html; charset=utf-8\n"
"Content-Length: " + std::to_string(body.size()) + "\n"
"Connection: close\n"
"\n" + body;
}
std::string parseRequest(const std::string& request) {
std::string method, path, data;
std::istringstream request_stream(request);
request_stream >> method >> path; // Получаем метод и путь
std::string line;
while (std::getline(request_stream, line) && line != "") {
// Собираем заголовки, но они нам не нужны в этом примере
}
// Если это POST запрос, то нужно получить данные
if (method == "POST") {
// Получаем длину содержимого
while (std::getline(request_stream, line)) {
if (line.find("Content-Length: ") != std::string::npos) {
int content_length = std::stoi(line.substr(16));
data.resize(content_length);
request_stream.read(&data[0], content_length);
break;
}
}
std::ostringstream oss; // Создаем ostringstream для форматирования строки
//Begin Парсинг POST данных на: ключ = значение
std::map<std::string, std::string> parsedData = parseData(line);
for (const auto& pair : parsedData) {
oss << pair.first << " = " << pair.second << " <br> "<< std::endl;
}
//End Парсинг POST данных на: ключ = значение
return handlePOST(oss.str());
} else if (method == "GET") {
return handleGET(path);
}
return "HTTP/1.1 405 Method Not Allowed\n"
"Connection: close\n"
"\n";
}
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("Socket failed");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, BACKLOG) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
std::cout << "Server is listening on port " << PORT << std::endl;
while (true) {
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}
char buffer[BUFFER_SIZE] = {0};
read(new_socket, buffer, BUFFER_SIZE);
std::string request(buffer);
std::cout << "Received request:\n" << request << std::endl;
std::string response = parseRequest(request);
send(new_socket, response.c_str(), response.size(), 0);
close(new_socket);
}
return 0;
}
Добавлен парсинг POST-запроса
тоже самое, но с применением шаблона проектированя mvc:
Код: Выделить всё
#include <iostream>
#include <string>
#include <cstring>
#include <sstream>
#include <unistd.h>
#include <arpa/inet.h>
#include <map>
const int PORT = 8070;
const int BACKLOG = 10;
const int BUFFER_SIZE = 1024;
// Model
class Model {
public:
std::map<std::string, std::string> parseData(const std::string& data) {
std::map<std::string, std::string> result;
std::string keyValuePair;
std::istringstream stream(data);
while (std::getline(stream, keyValuePair, '&')) {
size_t pos = keyValuePair.find('=');
if (pos != std::string::npos) {
std::string key = keyValuePair.substr(0, pos);
std::string value = keyValuePair.substr(pos + 1);
result[key] = value;
}
}
return result;
}
};
// View
class View {
public:
std::string generateGETResponse(const std::string& path) {
std::string body = "<!DOCTYPE html>"
"<html lang='en'>"
"<head>"
"<meta charset='UTF-8'>"
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>"
"<title>Простой C++ Веб-сервер</title>"
"</head>"
"<body>"
"<h1>Вы сделали GET запрос на путь: " + path + "</h1>"
"<form action='/' method='POST'>"
"<input type='text' name='send_text'>"
"<br>"
"<input type='text' name='send_text222'>"
"<input type='submit' value='Submit'>"
"</form>"
"</body>"
"</html>";
return buildResponse(body);
}
std::string generatePOSTResponse(const std::string& data) {
std::string body = "<!DOCTYPE html>"
"<html lang='en'>"
"<head>"
"<meta charset='UTF-8'>"
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>"
"<title>Простой C++ Веб-сервер</title>"
"</head>"
"<body>"
"<h1>Вы сделали POST запрос с данными:</h1>"
"<pre>" + data + "</pre>"
"</body>"
"</html>";
return buildResponse(body);
}
private:
std::string buildResponse(const std::string& body) {
return "HTTP/1.1 200 OK
"
"Content-Type: text/html; charset=utf-8
"
"Content-Length: " + std::to_string(body.size()) + "\n"
"Connection: close
"
"\n" + body;
}
};
// Controller
class Controller {
public:
Controller(Model& model, View& view) : model(model), view(view) {}
std::string handleRequest(const std::string& request) {
std::string method, path, data;
std::istringstream request_stream(request);
request_stream >> method >> path;
std::string line;
while (std::getline(request_stream, line) && !line.empty()) {
// Skip headers
}
if (method == "POST") {
while (std::getline(request_stream, line)) {
if (line.find("Content-Length: ") != std::string::npos) {
int content_length = std::stoi(line.substr(16));
data.resize(content_length);
request_stream.read(&data[0], content_length);
break;
}
}
// Parse POST data
std::map<std::string, std::string> parsedData = model.parseData(data);
std::ostringstream oss;
for (const auto& pair : parsedData) {
oss << pair.first << " = " << pair.second << " <br> " << std::endl;
}
return view.generatePOSTResponse(oss.str());
} else if (method == "GET") {
return view.generateGETResponse(path);
}
return "HTTP/1.1 405 Method Not Allowed
Connection: close
";
}
private:
Model& model;
View& view;
};
// Main function
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("Socket failed");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, BACKLOG) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
std::cout << "Server is listening on port " << PORT << std::endl;
Model model;
View view;
Controller controller(model, view);
while (true) {
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}
char buffer[BUFFER_SIZE] = {0};
read(new_socket, buffer, BUFFER_SIZE);
std::string request(buffer);
std::cout << "Received request:\n" << request << std::endl;
std::string response = controller.handleRequest(request);
send(new_socket, response.c_str(), response.size(), 0);
close(new_socket);
}
return 0;
}