WebServer项目——HTTPrequest详解

HTTPrequest简介

这个类主要的功能是解析HTTP的请求信息。

HTTP的请求包括:请求行(request line)、请求头部(header)、空行 和 请求数据 四个部分组成。

20230221095743

抓包的request结构如下:

1
2
3
4
5
6
7
GET /mix/76.html?name=kelvin&password=123456 HTTP/1.1
Host: www.baidu.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6

1.请求行

GET为请求类型,/mix/76.html?name=kelvin&password=123456为要访问的资源,HTTP/1.1是协议版本

2.请求头部

从第二行起为请求头部,Host指出请求的目的地(主机域名);User-Agent是客户端的信息,它是检测浏览器类型的重要信息,由浏览器定义,并且在每个请求中自动发送。

3.空行

请求头后面必须有一个空行

4.请求数据

请求的数据也叫请求体,可以添加任意的其它数据。这个例子的请求体为空。

由上述的简单描述可以看出来,我们的主要任务就是解析传进来的buffer里面的请求信息,也就是把各个有用信息分割开来。

HTTPrequest的组成

所需变量和自定义数据结构

首先就是各个有意义的字段变量,比如必须用字符串类型的变量存储HTTP方式、路径、版本和数据体,以及需要用两个哈希表分别存储请求头和post已经解析出来的信息。

为了访问方便,先用一个集合存储了默认的网页名称。除此之外,还需要一个用来实现自动机的state变量。

1
2
3
4
5
6
PARSE_STATE state_;
std::string method_,path_,version_,body_;
std::unordered_map<std::string,std::string>header_;
std::unordered_map<std::string,std::string>post_;

static const std::unordered_set<std::string>DEFAULT_HTML;

构造和析构函数

这个类的析构函数默认就可以了,但是构造的时候需要初始化上述的变量,这些可以用一个方法init汇总起来:

1
void init();

主要的解析函数

主要的HTTP请求信息的解析可以用下述的有限状态自动机实现:

自动状态机

主流程由函数parse完成:

1
bool parse(Buffer& buff); //解析HTTP请求

这个函数在实现过程中,根据HTTP请求报文的格式,用"\r\n"作为分隔符将报文分割成行,然后运用自动机来进行解析。在这个过程中,需要分别实现解析请求行、请求头和数据体的函数:

1
2
3
bool parseRequestLine_(const std::string& line);//解析请求行
void parseRequestHeader_(const std::string& line); //解析请求头
void parseDataBody_(const std::string& line); //解析数据体

在解析请求行的时候,会解析出路径信息,之后还需要对路径信息做一个处理:

1
void parsePath_();

在处理数据体的时候,如果格式是post,那么还需要解析post报文,用函数parsePost实现:

1
void parsePost_();

暴露给外界的接口

这个类最后需要向上层提供解析后的信息,所以需要各种获取HTTP信息的接口。

获取路径、HTTP方式、版本的函数如下:

1
2
3
4
std::string path() const;
std::string& path();
std::string method() const;
std::string version() const;

以及在post方式下获取信息的接口:

1
2
std::string getPost(const std::string& key) const;
std::string getPost(const char* key) const;

获取HTTP连接是否KeepAlive的函数:

1
bool isKeepAlive() const;

其他方法函数

还有一些其他的方法函数,比如转换Hex格式的函数:

1
static int convertHex(char ch);

HTTPrequest的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class HTTPrequest
{
public:
enum PARSE_STATE{
REQUEST_LINE,
HEADERS,
BODY,
FINISH,
};

HTTPrequest() {init();};
~HTTPrequest()=default;

void init();
bool parse(Buffer& buff); //解析HTTP请求

//获取HTTP信息
std::string path() const;
std::string& path();
std::string method() const;
std::string version() const;
std::string getPost(const std::string& key) const;
std::string getPost(const char* key) const;

bool isKeepAlive() const;

private:
bool parseRequestLine_(const std::string& line);//解析请求行
void parseRequestHeader_(const std::string& line); //解析请求头
void parseDataBody_(const std::string& line); //解析数据体


void parsePath_();
void parsePost_();

static int convertHex(char ch);

PARSE_STATE state_;
std::string method_,path_,version_,body_;
std::unordered_map<std::string,std::string>header_;

std::unordered_map<std::string,std::string>post_;

static const std::unordered_set<std::string>DEFAULT_HTML;
};