用c++验证http get请求



我正在编写自己的http服务器。我需要检查每个头从给定的列表(如果它被赋予一个无效的值)。我也不能使用任何第三方库。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
是的,我正在寻找一个解决方案,我已经看到了这些和其他问题:
在c++中解析HTTP头
如何正确解析传入的HTTP请求
如何使用c++解析HTTP响应
我也试图找到在libcurl中实现的源文件示例,但我不能。
https://curl.se/libcurl/c/example.html
我自己的作品根据这篇文章:
https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header

void HttpServer::ParseQuery(HttpServer::Connection socket_) noexcept{
std::vector<std::string> elems_ = split(socket_.data,"rn");
std::vector<std::string> request_line_ = split( elems_[0]+=" " ," ");
std::map<std::string,HttpServer::HeaderValue> header_fields_;
//if( (request_line_.size()< 3) || !strcmp(request_line_[0].c_str(),"GET") || !strcmp(request_line_[2].c_str(),"HTTP/1.1")) return;
std::size_t index = 1,pos;
while(index < elems_.size()){
if ((pos = elems_[index].find(":")) == std::string::npos){
}
else{
std::string first = elems_[index].substr(0,pos), second = elems_[index].substr(pos,elems_[index].length()-pos);
std::transform(first.begin(), first.end(), first.begin(),
[](unsigned char c){ 
return std::tolower(c); 
});
if( second[0] == ' ') 
second.erase(0,1);
if( second[second.length()-1] == ' ') 
second.erase(second.length()-1,1);
header_fields_[first] = {second , 1 };
}   
++index;
}
for( auto &a : header_fields_){
//For any header: the value’s length can't be greater than 128.
//For Accept-Language and Content-Language: can only have values consisting of 0-9, A-Z, a-z, space or *,-.;=.
if(!strcmp(a.first.c_str(),"accept-language")|| !strcmp(a.first.c_str(),"content-language"))
{
if( (a.second.field_name.length() > 128) || ((pos = a.second.field_name.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM*,-.;=") )!= std::string::npos))
a.second.correct = 0;
}
//For Accept and Content-Type: can't contain a CORS-unsafe request header byte: 0x00-0x1F (except for 0x09 (HT), which is allowed), "():<>?@[]{}, and 0x7F (DEL).
else if ((a.second.field_name.length() > 128) || (!strcmp(a.first.c_str(),"accept")|| !strcmp(a.first.c_str(),"content-type"))){
if( (pos = a.second.field_name.find_first_of("x01x02x03x04x05x06x07x08x0ax0bx0cx0dx0ex0fx10x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1fx7f():<>?@[\]{}") )!= std::string::npos)
a.second.correct = 0;
}
}
}

,其中数据类型为:

struct Connection
{
Connection(const int &socket,const std::chrono::time_point<std::chrono::system_clock> &tp);
int socket;
std::chrono::time_point<std::chrono::system_clock> tp;
std::string data;
std::string respons;
};
struct HeaderValue
{
std::string field_name;
bool correct = 1;
};

上面的函数将通过网络接收的请求分成行,请求的第一行再分成3个部分,并将其存储在vector中。接下来,我删除值之前和之后的OWS(如果有的话)。在形成映射后,我检查,例如,这两个标题。我的代码测试如下所示:

wget http://localhost:8080/server.cpp
--2021-02-22 18:07:33--  http://localhost:8080/server.cpp
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:8080... connected.
HTTP request sent, awaiting response... 200 No headers, assuming HTTP/0.9
Length: unspecified
Saving to: ‘server.cpp.6’
server.cpp.6                  [                          <=>      ]  16,39K  --.-KB/s

我的编译器:

g++ --version
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

我的问题是,有一个更好的方法来做到这一点比大量的其他-如果每一个可能的头?

我的问题是,是否有更好的方法来做到这一点,而不是大量的其他-如果每一个可能的头?

这个答案和其他硬编码大量魔法值的情况完全一样:停止它。

将所有硬编码的魔法值集中在一个地方,这样至少它们不会污染您的逻辑:构建头名称字符串到验证器的映射。如果您需要更大的灵活性,验证器可以是正则表达式或实际的函子(例如,std::function<bool(std::string)>)。

你的代码变成了类似于 的东西
for (auto &a : header_fields_) {
auto v = header_validators_.find(a.first);
if (v == header_validators_.end()) {
// error, unknown header
} else {
if (!v->second(a.first, a.second)) {
// error, invalid header
}
}
}

从文件中加载魔法值通常比硬编码更好,但除非能够编辑该文件而无需重新编译,否则实现成本不一定是合理的。

最新更新