当前位置: 代码迷 >> 综合 >> 从零开始自制实现WebServer(二十)---- C++ High-Performance WebServer源码实现(Http核心代码部分)
  详细解决方案

从零开始自制实现WebServer(二十)---- C++ High-Performance WebServer源码实现(Http核心代码部分)

热度:101   发布时间:2023-11-17 16:14:13.0

文章目录

    • 全流程实现博客链接
    • 前引
    • (二十)---- C++ High-Performance WebServer源码实现(Http核心代码部分)
      • 1、httpcontent.h
      • 1、httpcontent.cc
      • 2、httprequest.h
      • 2、httprequest.cc
      • 3、httpparsestate.h
      • 4、httpresponse.h
      • 4、httpresponse.cc
      • 5、httpresponsefile.h
      • 6、httpserver.h
      • 6、httpserver.cc


全流程实现博客链接


从零开始自制实现C++ High-Performance WebServer 全流程记录(基于muduo网络库)


前引


继续贴贴HTTP部分


(二十)---- C++ High-Performance WebServer源码实现(Http核心代码部分)


1、httpcontent.h


#ifndef TINY_MUDUO_HTTPCONTENT_H_
#define TINY_MUDUO_HTTPCONTENT_H_#include <utility>
#include <algorithm>#include "buffer.h"
#include "httprequest.h"
#include "httpparsestate.h"namespace tiny_muduo {
    class HttpContent {
    public:HttpContent();~HttpContent();void ParseLine(Buffer* buffer);bool ParseContent(Buffer* buffer);bool GetCompleteRequest() {
     return parse_state_ == kParseGotCompleteRequest; } const HttpRequest& request() const {
     return request_; }void ResetContentState() {
     HttpRequest tmp;request_.Swap(tmp);parse_state_ = kParseRequestLine;}private:HttpRequest request_;HttpRequestParseState parse_state_;
};}
#endif

1、httpcontent.cc


#include "httpcontent.h"#include <algorithm>#include "httprequest.h"
#include "httpparsestate.h"using namespace tiny_muduo;HttpContent::HttpContent() : parse_state_(kParseRequestLine) {
    
}HttpContent::~HttpContent() {
    }bool HttpContent::ParseContent(Buffer* buffer) {
    bool linemore = true;bool parseok = true;const char* CRLF = nullptr;while (linemore) {
    CRLF = nullptr;if (parse_state_ == kParseRequestLine) {
     CRLF = buffer->FindCRLF(); if (CRLF) {
    parseok = request_.ParseRequestLine(buffer->Peek(), CRLF);if (parseok) {
    parse_state_ = kParseHeaders;} else {
    linemore = false;}} else {
    linemore = false;}} else if (parse_state_ == kParseHeaders) {
    CRLF = buffer->FindCRLF(); if (CRLF) {
    const char* colon = std::find((const char*)buffer->Peek(), CRLF, ':');if (colon == CRLF) {
    parse_state_ = kParseGotCompleteRequest;linemore = false;} else {
    parseok = request_.ParseHeaders(buffer->Peek(), colon, CRLF);if (!parseok) linemore = false;}} else {
    linemore = false;}} else if (parse_state_ == kParseGotCompleteRequest) {
    linemore = false;} else if (parse_state_ == kParseBody) {
    }if (CRLF) {
     buffer->RetrieveUntilIndex(CRLF + 2);}}return parseok;
}

2、httprequest.h


#include "httprequest.h"#include <utility>
#include <algorithm>
#include <string>#include "httpparsestate.h"using namespace tiny_muduo;
using tiny_muduo::Method;
using tiny_muduo::HttpRequestParseState;HttpRequest::HttpRequest() {
    }HttpRequest::~HttpRequest() {
    }bool HttpRequest::ParseRequestMethod(const char* start, const char* end) {
    string method(start, end);bool has_method = true;if (method == "GET") {
    method_ = kGet;} else if (method == "POST") {
    method_ = kPost;} else if (method == "PUT") {
    method_ = kPut;} else if (method == "DELETE") {
    method_ = kDelete;} else if (method == "TRACE") {
    method_ = kTrace;} else if (method == "OPTIONS") {
    method_ = kOptions;} else if (method == "CONNECT") {
    method_ = kConnect;} else if (method == "PATCH") {
    method_ = kPatch;} else {
    has_method = false;}return has_method;
}bool HttpRequest::ParseRequestLine(const char* start, const char* end) {
    const char* space = nullptr;     space = std::find(start, end, ' ');if (space == end) {
    return false;}if (!ParseRequestMethod(start, space)) {
    return false;}start = space + 1; space = std::find(start, end, ' ');if (space == end) {
    return false;}const char* query = std::find(start, end, '?'); if (query != end) {
    path_.assign(start, query);query_.assign(query + 1, space);} else {
    path_.assign(start, space);}        start = space + 1;bool parsehttp = (start + 8 == end) && std::equal(start, end - 1, http);if (!parsehttp || (*(end - 1) != '0' && *(end - 1) != '1')) {
    version_ = kUnknown;return false;}if (*(end - 1) == '0') {
    version_ = kHttp10;} else {
    version_ = kHttp11; }return true;
}bool HttpRequest::ParseBody(const char* start, const char* end) {
     (void)start;(void)end;return true; 
}bool HttpRequest::ParseHeaders(const char* start, const char* colon, const char* end) {
    const char* vaildstart = colon + 1; while(*vaildstart == ' ') {
     ++vaildstart; }headers_[std::move(string(start, colon))] = std::move(string(vaildstart, end));return true;
}void HttpRequest::Swap(HttpRequest& req) {
    method_ = req.method_;version_ = req.version_;path_.swap(req.path_);query_.swap(req.query_);headers_.swap(req.headers_);
}

2、httprequest.cc


#include "httprequest.h"#include <utility>
#include <algorithm>
#include <string>#include "httpparsestate.h"using namespace tiny_muduo;
using tiny_muduo::Method;
using tiny_muduo::HttpRequestParseState;HttpRequest::HttpRequest() {
    }HttpRequest::~HttpRequest() {
    }bool HttpRequest::ParseRequestMethod(const char* start, const char* end) {
    string request_method(start, end);bool has_method = true;if (request_method == "GET") {
    method_ = kGet;} else if (request_method == "POST") {
    method_ = kPost;} else if (request_method == "PUT") {
    method_ = kPut;} else if (request_method == "DELETE") {
    method_ = kDelete;} else if (request_method == "TRACE") {
    method_ = kTrace;} else if (request_method == "OPTIONS") {
    method_ = kOptions;} else if (request_method == "CONNECT") {
    method_ = kConnect;} else if (request_method == "PATCH") {
    method_ = kPatch;} else {
    has_method = false;}return has_method;
}bool HttpRequest::ParseRequestLine(const char* start, const char* end) {
    const char* space = nullptr;     space = std::find(start, end, ' ');if (space == end) {
    return false;}if (!ParseRequestMethod(start, space)) {
    return false;}start = space + 1; space = std::find(start, end, ' ');if (space == end) {
    return false;}const char* query_ptr = std::find(start, end, '?'); if (query_ptr != end) {
    path_.assign(start, query_ptr);query_.assign(query_ptr + 1, space);} else {
    path_.assign(start, space);}        start = space + 1;bool parsehttp = (start + 8 == end) && std::equal(start, end - 1, http);if (!parsehttp || (*(end - 1) != '0' && *(end - 1) != '1')) {
    version_ = kUnknown;return false;}if (*(end - 1) == '0') {
    version_ = kHttp10;} else {
    version_ = kHttp11; }return true;
}bool HttpRequest::ParseBody(const char* start, const char* end) {
     (void)start;(void)end;return true; 
}bool HttpRequest::ParseHeaders(const char* start, const char* colon, const char* end) {
    const char* vaildstart = colon + 1; while(*vaildstart == ' ') {
     ++vaildstart; }headers_[std::move(string(start, colon))] = std::move(string(vaildstart, end));return true;
}void HttpRequest::Swap(HttpRequest& req) {
    method_ = req.method_;version_ = req.version_;path_.swap(req.path_);query_.swap(req.query_);headers_.swap(req.headers_);
}

3、httpparsestate.h


#ifndef TINY_MUDUO_HTTPSTATE_H_
#define TINY_MUDUO_HTTPSTATE_H_namespace tiny_muduo {
    enum HttpRequestParseState {
    kParseRequestLine,kParseHeaders,kParseBody,kParseGotCompleteRequest,kParseErrno,
};}#endif

4、httpresponse.h


#ifndef TINY_MUDUO_HTTPRESPONSE_H_
#define TINY_MUDUO_HTTPRESPONSE_H_#include <string>
#include <utility>#include "httprequest.h"using std::string;namespace tiny_muduo {
    static const string CRLF = "\r\n";enum HttpStatusCode {
    k100Continue = 100,k200OK = 200,k400BadRequest = 400,k403Forbidden = 403,k404NotFound = 404,k500InternalServerErrno = 500
};class Buffer;class HttpResponse {
    public:HttpResponse(bool close_connection) : type_("text/plain"),close_connection_(close_connection) {
    }~HttpResponse() {
    }void SetStatusCode(HttpStatusCode status_code) {
     status_code_ = status_code; }void SetStatusMessage(const string& status_message) {
     status_message_ = std::move(status_message); }void SetCloseConnection(bool close_connection) {
     close_connection_ = close_connection; }void SetBodyType(const string& type) {
     type_ = type; }void SetBody(const string& body) {
     body_ = body; }void AppendToBuffer(Buffer* buffer);bool CloseConnection() {
     return close_connection_; }private:static const string server_name_;HttpStatusCode status_code_;string status_message_;string body_;string type_;bool close_connection_;
};}#endif

4、httpresponse.cc


#include "httpresponse.h"#include <stdio.h>#include <string>#include "buffer.h"using namespace tiny_muduo;
using std::string;const string HttpResponse::server_name_ = "Tiny_muduo";void HttpResponse::AppendToBuffer(Buffer* buffer) {
    char buf[32] = {
    0};snprintf(buf, sizeof(buf), "HTTP/1.1 %d ",status_code_);buffer->Append(buf);buffer->Append(status_message_);buffer->Append(CRLF);if (close_connection_) {
    buffer->Append("Connection: close\r\n");} else {
    snprintf(buf, sizeof(buf), "Content-Length: %zd\r\n", body_.size()); // no need to memset this is longer than HTTP... onebuffer->Append(buf);buffer->Append("Connection: Keep-Alive\r\n");}buffer->Append("Content-Type: ");buffer->Append(type_);buffer->Append(CRLF);buffer->Append("Server: ");buffer->Append(server_name_);buffer->Append(CRLF);buffer->Append(CRLF);buffer->Append(body_);return;
}

5、httpresponsefile.h


#ifndef TINY_MUDUO_HTTPRESPONSEFILE_H_
#define TINY_MUDUO_HTTPRESPONSEFILE_H_namespace tiny_muduo {
    const char favicon[555] = {
    '\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA','\x0', '\x0', '\x0', '\xD', 'I', 'H', 'D', 'R','\x0', '\x0', '\x0', '\x10', '\x0', '\x0', '\x0', '\x10','\x8', '\x6', '\x0', '\x0', '\x0', '\x1F', '\xF3', '\xFF','a', '\x0', '\x0', '\x0', '\x19', 't', 'E', 'X','t', 'S', 'o', 'f', 't', 'w', 'a', 'r','e', '\x0', 'A', 'd', 'o', 'b', 'e', '\x20','I', 'm', 'a', 'g', 'e', 'R', 'e', 'a','d', 'y', 'q', '\xC9', 'e', '\x3C', '\x0', '\x0','\x1', '\xCD', 'I', 'D', 'A', 'T', 'x', '\xDA','\x94', '\x93', '9', 'H', '\x3', 'A', '\x14', '\x86','\xFF', '\x5D', 'b', '\xA7', '\x4', 'R', '\xC4', 'm','\x22', '\x1E', '\xA0', 'F', '\x24', '\x8', '\x16', '\x16','v', '\xA', '6', '\xBA', 'J', '\x9A', '\x80', '\x8','A', '\xB4', 'q', '\x85', 'X', '\x89', 'G', '\xB0','I', '\xA9', 'Q', '\x24', '\xCD', '\xA6', '\x8', '\xA4','H', 'c', '\x91', 'B', '\xB', '\xAF', 'V', '\xC1','F', '\xB4', '\x15', '\xCF', '\x22', 'X', '\x98', '\xB','T', 'H', '\x8A', 'd', '\x93', '\x8D', '\xFB', 'F','g', '\xC9', '\x1A', '\x14', '\x7D', '\xF0', 'f', 'v','f', '\xDF', '\x7C', '\xEF', '\xE7', 'g', 'F', '\xA8','\xD5', 'j', 'H', '\x24', '\x12', '\x2A', '\x0', '\x5','\xBF', 'G', '\xD4', '\xEF', '\xF7', '\x2F', '6', '\xEC','\x12', '\x20', '\x1E', '\x8F', '\xD7', '\xAA', '\xD5', '\xEA','\xAF', 'I', '5', 'F', '\xAA', 'T', '\x5F', '\x9F','\x22', 'A', '\x2A', '\x95', '\xA', '\x83', '\xE5', 'r','9', 'd', '\xB3', 'Y', '\x96', '\x99', 'L', '\x6','\xE9', 't', '\x9A', '\x25', '\x85', '\x2C', '\xCB', 'T','\xA7', '\xC4', 'b', '1', '\xB5', '\x5E', '\x0', '\x3','h', '\x9A', '\xC6', '\x16', '\x82', '\x20', 'X', 'R','\x14', 'E', '6', 'S', '\x94', '\xCB', 'e', 'x','\xBD', '\x5E', '\xAA', 'U', 'T', '\x23', 'L', '\xC0','\xE0', '\xE2', '\xC1', '\x8F', '\x0', '\x9E', '\xBC', '\x9','A', '\x7C', '\x3E', '\x1F', '\x83', 'D', '\x22', '\x11','\xD5', 'T', '\x40', '\x3F', '8', '\x80', 'w', '\xE5','3', '\x7', '\xB8', '\x5C', '\x2E', 'H', '\x92', '\x4','\x87', '\xC3', '\x81', '\x40', '\x20', '\x40', 'g', '\x98','\xE9', '6', '\x1A', '\xA6', 'g', '\x15', '\x4', '\xE3','\xD7', '\xC8', '\xBD', '\x15', '\xE1', 'i', '\xB7', 'C','\xAB', '\xEA', 'x', '\x2F', 'j', 'X', '\x92', '\xBB','\x18', '\x20', '\x9F', '\xCF', '3', '\xC3', '\xB8', '\xE9','N', '\xA7', '\xD3', 'l', 'J', '\x0', 'i', '6','\x7C', '\x8E', '\xE1', '\xFE', 'V', '\x84', '\xE7', '\x3C','\x9F', 'r', '\x2B', '\x3A', 'B', '\x7B', '7', 'f','w', '\xAE', '\x8E', '\xE', '\xF3', '\xBD', 'R', '\xA9','d', '\x2', 'B', '\xAF', '\x85', '2', 'f', 'F','\xBA', '\xC', '\xD9', '\x9F', '\x1D', '\x9A', 'l', '\x22','\xE6', '\xC7', '\x3A', '\x2C', '\x80', '\xEF', '\xC1', '\x15','\x90', '\x7', '\x93', '\xA2', '\x28', '\xA0', 'S', 'j','\xB1', '\xB8', '\xDF', '\x29', '5', 'C', '\xE', '\x3F','X', '\xFC', '\x98', '\xDA', 'y', 'j', 'P', '\x40','\x0', '\x87', '\xAE', '\x1B', '\x17', 'B', '\xB4', '\x3A','\x3F', '\xBE', 'y', '\xC7', '\xA', '\x26', '\xB6', '\xEE','\xD9', '\x9A', '\x60', '\x14', '\x93', '\xDB', '\x8F', '\xD','\xA', '\x2E', '\xE9', '\x23', '\x95', '\x29', 'X', '\x0','\x27', '\xEB', 'n', 'V', 'p', '\xBC', '\xD6', '\xCB','\xD6', 'G', '\xAB', '\x3D', 'l', '\x7D', '\xB8', '\xD2','\xDD', '\xA0', '\x60', '\x83', '\xBA', '\xEF', '\x5F', '\xA4','\xEA', '\xCC', '\x2', 'N', '\xAE', '\x5E', 'p', '\x1A','\xEC', '\xB3', '\x40', '9', '\xAC', '\xFE', '\xF2', '\x91','\x89', 'g', '\x91', '\x85', '\x21', '\xA8', '\x87', '\xB7','X', '\x7E', '\x7E', '\x85', '\xBB', '\xCD', 'N', 'N','b', 't', '\x40', '\xFA', '\x93', '\x89', '\xEC', '\x1E','\xEC', '\x86', '\x2', 'H', '\x26', '\x93', '\xD0', 'u','\x1D', '\x7F', '\x9', '2', '\x95', '\xBF', '\x1F', '\xDB','\xD7', 'c', '\x8A', '\x1A', '\xF7', '\x5C', '\xC1', '\xFF','\x22', 'J', '\xC3', '\x87', '\x0', '\x3', '\x0', 'K','\xBB', '\xF8', '\xD6', '\x2A', 'v', '\x98', 'I', '\x0','\x0', '\x0', '\x0', 'I', 'E', 'N', 'D', '\xAE','B', '\x60', '\x82',
};const string love6_website = "<p align = \"middle\"><strong> <font color=\"#84C1FF\">Sharing And Geting. I'm Always Here</font> </strong> </p><hr />\ <p align = \"middle\"><strong> <font color=\"#84C1FF\">Love 6's Info</font> </strong> <br />\ <strong><font color=\"#AAAAFF\">Love 6's School: Hogwarts School </font></strong> <br />\ <strong><font color=\"#C1FFE4\">Love 6's Year In Univ: Sophomore </font></strong> <br />\ <strong><font color=\"#FFBFFF\">Love 6's Interests: Gaming Coding </font></strong> <br />\ <strong><font color=\"#A3D1D1\">Love 6's Occupation: Sorcerer </font></strong> <br /> \ <strong><font color=\"#A6FFA6\">Love 6's QQ Wechat: Personal Secret </font></strong> <br /> </p>\ <hr />\ <p align = \"middle\"><strong><font color=\"#84C1FF\"> Cat </font><br /> </strong> </p>\ <p align = \"middle\"><img src=\"https://img-blog.csdnimg.cn/6d28d9f8ad2b4c79be7a90a33e552caf.GIF\" alt=\"Cat\" width=\"200\" height=\"200\"></p>\ <hr />\ <p align = \"middle\"><strong><font color=\"#84C1FF\"> Love 6's Some Blogs - Keep Updating </font><br /> </strong></p></hr >\ <strong><font color=\"#AAAAFF\"> Touch Here -> </font></strong><a href=\"https://love6.blog.csdn.net/article/details/119133589\"> Operating system truth restore self-made operating system whole process records from scratch </a><br />\ <strong><font color=\"#FFBFFF\"> Touch Here -> </font></strong><a href=\"https://love6.blog.csdn.net/article/details/117517529\"> Harbin Institute of technology operating system lab full experiment blog link </a><br />\ <strong><font color=\"#C1FFE4\"> Touch Here -> </font></strong><a href=\"https://love6.blog.csdn.net/article/details/120071337\"> Computer network top-down lab full experiment blog link </a><br />\ <strong><font color=\"#A3D1D1\"> Touch Here -> </font></strong><a href=\"https://love6.blog.csdn.net/article/details/116152266\"> CSAPP Labs 1-6 Blog Link</a><hr />\ <p align = \"middle\"><strong><font color=\"#84C1FF\"> Do good deeds Don't ask future </font><br /> </strong></p>"; }#endif

6、httpserver.h


#ifndef TINY_MUDUO_HTTPSERVER_H_
#define TINY_MUDUO_HTTPSERVER_H_#include <stdio.h>#include <functional>
#include <utility>
#include <memory>#include "callback.h"
#include "eventloop.h"
#include "tcpserver.h"
#include "tcpconnection.h"
#include "buffer.h"
#include "httpcontent.h"
#include "httprequest.h"
#include "httpresponse.h"
#include "timestamp.h"
#include "logging.h"using tiny_muduo::HttpStatusCode;namespace tiny_muduo {
    static const double kIdleConnectionTimeOuts = 8.0;class HttpServer {
    typedef std::function<void (const HttpRequest&, HttpResponse&)> HttpResponseCallback;public:HttpServer(EventLoop* loop, const Address& address, bool auto_close_idleconnection = false);~HttpServer();void Start() {
    server_.Start();}void HttpDefaultCallback(const HttpRequest& request, HttpResponse& response) {
    response.SetStatusCode(k404NotFound);response.SetStatusMessage("Not Found");response.SetCloseConnection(true);(void)request;}void HandleIdleConnection(std::weak_ptr<TcpConnection>& connection) {
    TcpConnectionPtr conn(connection.lock());if (conn) {
    if (Timestamp::AddTime(conn->timestamp(), kIdleConnectionTimeOuts) < Timestamp::Now()) {
    conn->Shutdown();} else {
        loop_->RunAfter(kIdleConnectionTimeOuts, std::move(std::bind(&HttpServer::HandleIdleConnection,this, connection))); }}}void ConnectionCallback(const TcpConnectionPtr& connection) {
    if (auto_close_idleconnection_) {
    loop_->RunAfter(kIdleConnectionTimeOuts, std::bind(&HttpServer::HandleIdleConnection, this, std::weak_ptr<TcpConnection>(connection))); }}void MessageCallback(const TcpConnectionPtr& connection, Buffer* buffer);void SetHttpResponseCallback(const HttpResponseCallback& response_callback) {
     response_callback_ = response_callback; }void SetHttpResponseCallback(HttpResponseCallback&& response_callback) {
     response_callback_ = std::move(response_callback); } void SetThreadNums(int thread_nums) {
    server_.SetThreadNums(thread_nums);}void DealWithRequest(const HttpRequest& request, const TcpConnectionPtr& connection);private:EventLoop* loop_;TcpServer server_;bool auto_close_idleconnection_;HttpResponseCallback response_callback_;
};}#endif

6、httpserver.cc


#include "httpserver.h"#include <functional>#include "address.h"using namespace tiny_muduo;using tiny_muduo::Version;HttpServer::HttpServer(EventLoop* loop, const Address& address,bool auto_close_idleconnection) : loop_(loop),server_(loop, address),auto_close_idleconnection_(auto_close_idleconnection) {
    server_.SetConnectionCallback(std::bind(&HttpServer::ConnectionCallback, this, _1));server_.SetMessageCallback(std::bind(&HttpServer::MessageCallback, this, _1, _2));SetHttpResponseCallback(std::bind(&HttpServer::HttpDefaultCallback, this, _1, _2));LOG_INFO << "Httpserver listening on " << address.ip() << ':' << address.port();
}HttpServer::~HttpServer() {
    
}void HttpServer::MessageCallback(const TcpConnectionPtr& connection, Buffer* buffer) {
    HttpContent* content = connection->GetHttpContent();if (auto_close_idleconnection_) connection->UpdateTimestamp(Timestamp::Now());if (connection->IsShutdown()) return;if (!content->ParseContent(buffer)) {
    connection->Send("HTTP/1.1 400 Bad Request\r\n\r\n");connection->Shutdown();}   if (content->GetCompleteRequest()) {
    DealWithRequest(content->request(), connection);content->ResetContentState();}   
}void HttpServer::DealWithRequest(const HttpRequest& request, const TcpConnectionPtr& connection) {
    string connection_state = std::move(request.GetHeader("Connection"));bool close = (connection_state == "Close" || (request.version() == kHttp10 &&connection_state != "Keep-Alive"));HttpResponse response(close); response_callback_(request, response);Buffer buffer;response.AppendToBuffer(&buffer);connection->Send(&buffer);if (response.CloseConnection()) {
    connection->Shutdown();}   
}
  相关解决方案