使用 c++

时间:2021-02-23 09:50:22

标签: c++ http http-headers

我正在编写自己的 http 服务器。我需要检查给定列表中的每个标题(如果给出的值无效)。我也不能使用任何第三方库。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
是的,我正在寻找解决方案,我已经看到了以下问题和其他问题:
Parse HTTP headers in C++
How to correctly parse incoming HTTP requests
How to parse HTTP response using c++
我还试图在这里找到在 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,"\r\n");
    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("\x01\x02\x03\x04\x05\x06\x07\x08\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\0x7f():<>?@[\\]{}") )!= 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 部分并将其存储在向量中。接下来,我删除该值前后的 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

我的问题是,对于每个可能的标题,是否有比大量 else-if 更好的方法呢?

1 个答案:

答案 0 :(得分:1)

<块引用>

我的问题是,对于每个可能的标题,是否有比大量 else-if 更好的方法呢?

对于任何其他硬编码大量魔法值的情况,答案完全相同:停止它。

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

从文件中加载魔法值而不是硬编码它们通常更好,但是实现成本不一定合理,除非能够在不重新编译的情况下编辑该文件是一个实际的好处.