feat: 初步封装了 HTTP 协议请求和响应体

This commit is contained in:
2025-09-27 14:49:22 +00:00
parent b6438fc69d
commit 3433ccf467
9 changed files with 330 additions and 15 deletions
+11
View File
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
file(GLOB_RECURSE HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/*/*.cpp)
file(GLOB_RECURSE SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/*/*.cpp)
add_library(ouc_server_lib ${SOURCE_FILE} ${HEADER_FILE})
target_include_directories(ouc_server_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
@@ -0,0 +1,53 @@
#include <http/http_method_type.hpp>
namespace ouc_server
{
namespace http
{
HttpMethodType str2type(const std::string &str)
{
if (str == "GET")
return HttpMethodType::Get;
else if (str == "HEAD")
return HttpMethodType::Head;
else if (str == "POST")
return HttpMethodType::Post;
else if (str == "PUT")
return HttpMethodType::Put;
else if (str == "DELETE")
return HttpMethodType::Delete;
else if (str == "CONNECT")
return HttpMethodType::Connect;
else if (str == "OPTIONS")
return HttpMethodType::Options;
else if (str == "TRACE")
return HttpMethodType::Trace;
else
return HttpMethodType::Get;
}
std::string type2str(HttpMethodType type)
{
switch (type)
{
case HttpMethodType::Get:
default:
return "GET";
case HttpMethodType::Head:
return "HEAD";
case HttpMethodType::Post:
return "POST";
case HttpMethodType::Put:
return "PUT";
case HttpMethodType::Delete:
return "DELETE";
case HttpMethodType::Connect:
return "CONNECT";
case HttpMethodType::Options:
return "OPTIONS";
case HttpMethodType::Trace:
return "TRACE";
}
}
}
}
@@ -0,0 +1,28 @@
#ifndef INCLUDE_OUC_SERVER_HTTP_METHOD_TYPE
#define INCLUDE_OUC_SERVER_HTTP_METHOD_TYPE
#include <string>
namespace ouc_server
{
namespace http
{
enum class HttpMethodType
{
Get,
Head,
Post,
Put,
Delete,
Connect,
Options,
Trace
};
HttpMethodType str2type(const std::string &);
std::string type2str(HttpMethodType);
}
}
#endif // INCLUDE_OUC_SERVER_HTTP_METHOD_TYPE
+91
View File
@@ -0,0 +1,91 @@
#include <http/http_request.hpp>
namespace ouc_server
{
namespace http
{
HttpRequest HttpRequest::from_string(const std::string &raw_str)
{
std::istringstream iss(raw_str);
HttpRequest req;
parse_top_line(req, iss);
switch (req.method)
{
case HttpMethodType::Get:
default:
parse_get_request(req, iss);
break;
case HttpMethodType::Head:
break;
case HttpMethodType::Post:
break;
case HttpMethodType::Put:
break;
case HttpMethodType::Delete:
break;
case HttpMethodType::Connect:
break;
case HttpMethodType::Options:
break;
case HttpMethodType::Trace:
break;
}
return req;
}
void HttpRequest::parse_top_line(HttpRequest &req, std::istringstream &iss)
{
std::string line, type_str;
std::getline(iss, line);
while ((!line.empty()) && line.back() != '\r')
line.pop_back();
std::istringstream req_iss(line);
req_iss >> type_str >> req.path >> req.version;
req.method = str2type(type_str);
}
void HttpRequest::parse_get_request(HttpRequest &req, std::istringstream &iss)
{
std::string line;
// parse top line
std::getline(iss, line);
while ((!line.empty()) && line.back() != '\r')
line.pop_back();
std::istringstream req_iss(line);
std::string type_str;
req_iss >> type_str >> req.path >> req.version;
req.method = str2type(type_str);
// parse headers
while (std::getline(iss, line) && line != "\r")
{
while ((!line.empty()) && line.back() == '\r')
line.pop_back();
auto pos = line.find(": ");
if (pos == std::string::npos)
pos = line.find(":");
if (pos != std::string::npos)
{
std::string key = line.substr(0, pos);
std::string val = line.substr(pos + 2);
req.headers[key] = val;
}
}
// parse body (not finish)
std::string body;
while (std::getline(iss, line))
body += line + "\n";
req.body = body;
}
}
}
+18 -13
View File
@@ -2,28 +2,33 @@
#define INCLUDE_OUC_SERVER_HTTP_REQUEST
#include <string>
#include <unordered_map>
#include <sstream>
#include <http/http_method_type.hpp>
namespace ouc_server
{
namespace http
{
enum class HttpMethodType
{
Get,
Head,
Post,
Put,
Delete,
Connect,
Options,
Trace
};
struct HttpRequest
{
HttpMethodType method;
HttpMethodType method = HttpMethodType::Get;
std::string path;
std::string version;
std::unordered_map<std::string, std::string> headers;
std::string body;
static HttpRequest from_string(const std::string &);
private:
static void parse_top_line(HttpRequest &, std::istringstream &);
static void parse_get_request(HttpRequest &, std::istringstream &);
};
}
}
#endif
#endif // INCLUDE_OUC_SERVER_HTTP_REQUEST
+27
View File
@@ -0,0 +1,27 @@
#include <http/http_response.hpp>
#include <sstream>
namespace ouc_server
{
namespace http
{
std::string HttpResponse::to_string() const
{
std::ostringstream oss;
oss << version << " "
<< stus_code << " "
<< stus_msg << "\r\n";
for (auto &[k, v] : headers)
oss << k << ": " << v << "\r\n";
oss << "\r\n"
<< body;
return oss.str();
}
HttpResponseBuilder HttpResponse::create() { return {}; }
}
}
+79
View File
@@ -0,0 +1,79 @@
#ifndef INCLUDE_OUC_SERVER_HTTP_RESPONSE
#define INCLUDE_OUC_SERVER_HTTP_RESPONSE
#include <string>
#include <unordered_map>
#include <http/http_method_type.hpp>
namespace ouc_server
{
namespace http
{
class HttpResponseBuilder;
struct HttpResponse
{
std::string version = "HTTP/1.1";
int stus_code = 200;
std::string stus_msg = "OK";
std::unordered_map<std::string, std::string> headers;
std::string body;
std::string to_string() const;
static HttpResponseBuilder create();
};
class HttpResponseBuilder
{
private:
HttpResponse res;
public:
HttpResponseBuilder() = default;
~HttpResponseBuilder() = default;
HttpResponse build() { return res; }
public:
HttpResponseBuilder &version(const std::string &p_version)
{
res.version = p_version;
return *this;
}
HttpResponseBuilder &stus_code(int p_stus_code)
{
res.stus_code = p_stus_code;
return *this;
}
HttpResponseBuilder &stus_msg(const std::string &p_stus_msg)
{
res.stus_msg = p_stus_msg;
return *this;
}
HttpResponseBuilder &header(const std::pair<const std::string &, const std::string &> p_header)
{
res.headers.insert(p_header);
return *this;
}
HttpResponseBuilder &header(const std::string &p_key, const std::string &p_value)
{
return header({p_key, p_value});
}
HttpResponseBuilder &body(const std::string &p_body)
{
res.body = p_body;
return *this;
}
};
}
}
#endif // INCLUDE_OUC_SERVER_HTTP_RESPONSE