WebServer项目——HTTPrequest详解
HTTPrequest简介
这个类主要的功能是解析HTTP的请求信息。
HTTP的请求包括:请求行(request line)、请求头部(header)、空行 和 请求数据 四个部分组成。
抓包的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汇总起来:
主要的解析函数
主要的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); //解析数据体
|
在解析请求行的时候,会解析出路径信息,之后还需要对路径信息做一个处理:
在处理数据体的时候,如果格式是post,那么还需要解析post报文,用函数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; };
|