[sylar]C++高性能服务器框架——Http模块

608 阅读3分钟

Http模块概述

主要封装HTTP请求(class HttpRequest)和HTTP响应报文(class HttpResponse

使用状态机解析报文格式,保存到请求和响应报文对象中。

请求报文格式

GET / HTTP/1.1  #请求行
Host: www.baidu.com   #主机地址
Connection: keep-alive   #表示TCP未断开
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64;x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36   #产生请求的浏览器类型
Sec-Fetch-Dest: document
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: ......    #用户安全凭证
URI: http://www.sylar.top:80/page/xxx?id=10&v=20#fr
http  协议
www.sylar.top  host主机
80  post端口
/page/xxx 路径path
id=10&v=20 参数query
#fr fragment

应答报文格式

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Date: Mon, 05 Jun 2023 06:53:13 GMT
Link: <http://www.sylar.top/blog/index.php?rest_route=/>; rel="https://api.w.org/"
Server: nginx/1.12.2
Transfer-Encoding: chunked
X-Powered-By: PHP/7.0.33
Connection: close
Content-length: 45383
​
<!DOCTYPE html>
<html lang="zh-CN" class="no-js">
<head>
<meta charset="UTF-8">

Http封装详解

enum class HttpMethod

使用宏将所有请求方法转为枚举类的成员

enum class HttpMethod {
#define XX(num, name, string) name = num,
    HTTP_METHOD_MAP(XX)
#undef XX
    INVALID_METHOD
};

enum class HttpStatus

使用宏将所有响应码转为枚举类的成员

enum class HttpStatus {
#define XX(code, name, desc) name = code,
    HTTP_STATUS_MAP(XX)
#undef XX
};

checkGetAs(获取Map中的key值,并转成对应类型,返回是否成功)

模板类

template<class MapType, class T>
bool checkGetAs(const MapType& m, const std::string& key, T& val, const T& def = T()) {
    auto it = m.find(key);
    if(it == m.end()) {
        val = def;
        return false;
    }
    try {
        val = boost::lexical_cast<T>(it->second);
        return true;
    } catch (...) {
        val = def;
    }
    return false;
}

模板类

getAs(获取Map中的key值,并转成对应类型)

template<class MapType, class T>
T getAs(const MapType& m, const std::string& key, const T& def = T()) {
    auto it = m.find(key);
    if (it == m.end()) {
        return def;
    }
    try {
        return boost::lexical_cast<T>(it->second);
    }
    catch (...) {
​
    }
    return def;
}

class HttpRequest

主要提供方法赋值和取值。

mumber(成员变量)

typedef std::map<std::string, std::string, CaseInsensitiveLess> MapType;

map的键与大小无关。

// HTTP方法
HttpMethod m_method;
// HTTP版本
uint8_t m_version;
// http/1.1支持长连接
// 是否自动关闭
bool m_close;
​
// 请求路径
std::string m_path;
// 请求参数
std::string m_query;
// 请求fragment
std::string m_fragment;
// 请求消息体
std::string m_body;
​
// 请求头部MAP
MapType m_headers;
// 请求参数MAP
MapType m_params;
// 请求Cookie MAP
MapType m_cookies;

HttpRequest(构造函数)

默认请求方法为GET,默认为close,默认路径为根目录``

HttpRequest::HttpRequest(uint8_t version, bool close)
    :m_method(HttpMethod::GET)
    ,m_version(version)
    ,m_close(close)
    ,m_path("/") {
}

class HttpResponse

主要提供方法赋值和取值。

mumber(成员变量)

// 响应状态
HttpStatus m_status;
// 版本
uint8_t m_version;
// 是否自动关闭
bool m_close;
// 是否为websocket
bool m_websocket;
// 响应消息体
std::string m_body;
// 响应原因
std::string m_reason;
// 响应头部MAP
MapType m_headers;
// cookies
std::vector<std::string> m_cookies;

HttpResponse(构造函数)

HttpResponse::HttpResponse(uint8_t version, bool close)
    :m_status(HttpStatus::OK)
    ,m_version(version)
    ,m_close(close) {
}

Http解析详解

class HttpRequestParser

mumber(成员变量)

// http_parser
http_parser m_parser;
// 请求报文
HttpRequest::ptr m_data;
// 错误代码
// 1000: invalid method
// 1001: invalid version
// 1002: invalid filed
int m_error;

HttpRequestParser(构造函数)

当解析到时调用回调函数,将对应的数据保存到报文中。

HttpRequestParser::HttpRequestParser()
    :m_error(0) {
    m_data.reset(new sylar::http::HttpRequest);
    
    http_parser_init(&m_parser);
    m_parser.request_method = on_request_method;
    m_parser.request_uri = on_request_uri;
    m_parser.fragment = on_request_fragment;
    m_parser.request_path = on_request_path;
    m_parser.query_string = on_request_query;
    m_parser.http_version = on_request_version;
    m_parser.header_done = on_request_header_done;
    m_parser.http_field = on_request_http_field;
    m_parser.data = this;
}

execute执行函数

size_t HttpRequestParser::execute(char* data, size_t len) {
    size_t offset = http_parser_execute(&m_parser, data, len, 0);
    // 解析完将剩余数据移动到起始地址
    memmove(data, data + offset, (len - offset));
    return offset;
}

class HttpResponseParser

mumber(成员变量)

// httpclient_parser
httpclient_parser m_parser;
// 响应报文
HttpResponse::ptr m_data;
// 错误代码
// 1001: invalid version
// 1002: invalid filed
int m_error;

HttpRequestParser(构造函数)

当解析到时调用回调函数,将对应的数据保存到报文中。

HttpResponseParser::HttpResponseParser()
    :m_error(0) {
    m_data.reset(new sylar::http::HttpResponse);

    httpclient_parser_init(&m_parser);
    m_parser.reason_phrase = on_response_reason;
    m_parser.status_code = on_response_status;
    m_parser.chunk_size = on_response_chunk;
    m_parser.http_version = on_response_version;
    m_parser.header_done = on_response_header_done;
    m_parser.last_chunk = on_response_last_chunk;
    m_parser.http_field = on_response_http_field;
    m_parser.data = this;
}

execute执行函数

size_t HttpResponseParser::execute(char* data, size_t len, bool chunck) {
    if (chunck) {
        httpclient_parser_init(&m_parser);
    }
    size_t offset = httpclient_parser_execute(&m_parser, data, len, 0);
    memmove(data, data + offset, len - offset);
    return offset;
}