文章目录
-
- 全流程实现博客链接
- 前引
- (二十)---- 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源码实现(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... one
buffer->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\"><label> <font color=\"#84C1FF\">Sharing And Geting. I'm Always Here</font> </label> </p><hr />\ <p align = \"middle\"><label> <font color=\"#84C1FF\">Love 6's Info</font> </label> <br />\ <label><font color=\"#AAAAFF\">Love 6's School: Hogwarts School </font></label> <br />\ <label><font color=\"#C1FFE4\">Love 6's Year In Univ: Sophomore </font></label> <br />\ <label><font color=\"#FFBFFF\">Love 6's Interests: Gaming Coding </font></label> <br />\ <label><font color=\"#A3D1D1\">Love 6's Occupation: Sorcerer </font></label> <br /> \ <label><font color=\"#A6FFA6\">Love 6's QQ Wechat: Personal Secret </font></label> <br /> </p>\ <hr />\ <p align = \"middle\"><label><font color=\"#84C1FF\"> Cat </font><br /> </label> </p>\ <p align = \"middle\"><img src=\"https://img-blog.csdnimg.cn/6d28d9f8ad2b4c79be7a90a33e552caf.GIF\" alt=\"Cat\" width=\"200\" height=\"200\"></p>\ <hr />\ <p align = \"middle\"><label><font color=\"#84C1FF\"> Love 6's Some Blogs - Keep Updating </font><br /> </label></p></hr >\ <label><font color=\"#AAAAFF\"> Touch Here -> </font></label><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 />\ <label><font color=\"#FFBFFF\"> Touch Here -> </font></label><a href=\"https://love6.blog.csdn.net/article/details/117517529\"> Harbin Institute of technology operating system lab full experiment blog link </a><br />\ <label><font color=\"#C1FFE4\"> Touch Here -> </font></label><a href=\"https://love6.blog.csdn.net/article/details/120071337\"> Computer network top-down lab full experiment blog link </a><br />\ <label><font color=\"#A3D1D1\"> Touch Here -> </font></label><a href=\"https://love6.blog.csdn.net/article/details/116152266\"> CSAPP Labs 1-6 Blog Link</a><hr />\ <p align = \"middle\"><label><font color=\"#84C1FF\"> Do good deeds Don't ask future </font><br /> </label></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();
}
}