feat: 初步封装了 HTTP 协议请求和响应体
This commit is contained in:
+3
-2
@@ -8,6 +8,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
|||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -g -O2")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -g -O2")
|
||||||
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
add_subdirectory(${PROJECT_SOURCE_DIR}/include/ouc_server)
|
||||||
|
|
||||||
add_executable(test "${PROJECT_SOURCE_DIR}/example/epoll_tcp_loop.cpp")
|
add_executable(test "${PROJECT_SOURCE_DIR}/example/test_http_request.cpp")
|
||||||
|
target_link_libraries(test PRIVATE ouc_server_lib)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include <http/http_response.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::string body = "Hello HTTP!";
|
||||||
|
|
||||||
|
auto builder = ouc_server::http::HttpResponse::create();
|
||||||
|
auto res =
|
||||||
|
builder.body(body)
|
||||||
|
.header("Content-Length", std::to_string(body.size()))
|
||||||
|
.header("Content-Type", "text/plain")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
printf("%s\n", res.to_string().c_str());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,28 +2,33 @@
|
|||||||
#define INCLUDE_OUC_SERVER_HTTP_REQUEST
|
#define INCLUDE_OUC_SERVER_HTTP_REQUEST
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <http/http_method_type.hpp>
|
||||||
|
|
||||||
namespace ouc_server
|
namespace ouc_server
|
||||||
{
|
{
|
||||||
namespace http
|
namespace http
|
||||||
{
|
{
|
||||||
enum class HttpMethodType
|
|
||||||
{
|
|
||||||
Get,
|
|
||||||
Head,
|
|
||||||
Post,
|
|
||||||
Put,
|
|
||||||
Delete,
|
|
||||||
Connect,
|
|
||||||
Options,
|
|
||||||
Trace
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HttpRequest
|
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
|
||||||
@@ -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 {}; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user