目录
模块设计思想
HttpRequest模块是存储 Http请求要素的模块,同时他也需要提供接口用于外部进行设置要素。
那么Http请求中有哪些要素呢?
首先请求行中,有请求方法,url ,协议版本,而uel中又分为资源路径和参数,参数是kv的形式,所以我们需要使用一个map来保存
而头部字段中,都是一些kv格式的属性,我们也是使用一个map来保存
最后就是正文部分,正文部分是交给上层业务逻辑去处理的,我们只需要按照头部字段中的Content-Length提取出来就行了。
那么我们需要保存的就是 : 请求方法,资源路径,参数,协议版本,头部字段,正文 ,当然,由于可能会存在中间的处理过程,比如对请求行的解析,我们会使用正则表达式来进行,我们可以再存储一个 std::smatch 来保存正则提取出来的结果。
由于HttpRequest后续我们是交给 上下文模块来进行设置的,为了方便,我们就直接将成员设置为公有的了,便于直接访问。
同时,对于参数和头部字段,我们可以提供结构,用来插入kv形式的参数和头部字段,以及查询是否有某个参数或者头部字段。
再HttpRequest的头部字段中,有一个很重要的信息就是正文长度,我们可以提供一个接口用来获取正文长度。
最后再提供一个接口用于判断长短连接,长短连接后续我们会用到。
模块代码实现
按照上面的逻辑,我们的接口其实都很简单,所以我们也不一一讲解了。
//保存http请求的各个要素
class HttpRequest
{
public:
std::string _method; //请求方法
std::string _path; //资源路径
std::unordered_map<std::string,std::string> _params; //参数
std::string _version; //协议版本
std::unordered_map<std::string,std::string> _headers; //头部字段
std::string _body; //正文
std::smatch _matches; //请求行的正则匹配结果
uint64_t _length; //正文长度
public:
//添加参数
void AddParam(const std::string& key , const std::string& val)
{
//如果已经存在该key,那么也直接更新
_params[key] = val;
}
//判断是否有该参数
bool HasParam(const std::string& key)const
{
auto it = _params.find(key);
return it != _params.end();
}
//获取参数
std::string GetParam(const std::string& key)const
{
auto it = _params.find(key);
if(it == _params.end()) return ""; //返回空串
return it->second;
}
//添加头部字段
void AddHeader(const std::string& key , const std::string& val)
{
_headers[key]=val;
}
//判断是否有某个头部字段
bool HasHeader(const std::string& key)const
{
auto it = _headers.find(key);
return it != _headers.end();
}
//判断是不是短连接,如果是短连接那么返回一个响应之后就关闭连接了
bool Close()const
{
//长短连接: Connection: close/keep-alive
auto it = _headers.find("Connection");
if(it == _headers.end() || it->second == "close") return true;
return false;
}
//获取正文长度
size_t ContentLength()const
{
auto it = _headers.find("Content-Length");
if(it == _headers.end()) return 0;
return std::stol(it->second);
}
};
最后,我们会注意到,如果是长连接,那么意味着可能会收到第二个报文,那么我们需要将HttpRequest的内容先清空,再去解析第二个报文。(后续我们的HttpRequest是作为HttpContext的一部分的)。
所以我们再提供一个Reset接口用于重置内容。
void Reset()
{
_method.clear();
_path.clear();
_params.clear();
_version.clear();
_headers.clear();
_body.clear();
std::smatch tmp;
_matches.swap(tmp); //由于smatch没有提供clear接口,所以我们使用swap来进行重置
_body.clear();
}
那么HttpRequest也就设计完了。这个模块主要还是用于保存请求中的要素,所以他的设计十分简单。