OpenSSL 偶尔打印随机垃圾

OpenSSL occasionally printing random garbage

我刚开始使用 OpenSSL 来发出 HTTPS 请求。我正在使用 C++。有时,我会得到一个看起来像这样的正确响应:

HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Sun, 09 Aug 2020 12:14:03 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 159
Connection: keep-alive
Access-Control-Allow-Credentials: true
Vary: Origin

{"status":"success","symbol":"AAPL","last":{"price":446.71,"size":200,"exchange":2,"cond1":14,"cond2":12,"cond3":41,"cond4":0,"timestamp":1596835355456000000}}

有时我会收到如下所示的有问题的响应:(向右滚动)

HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Sun, 09 Aug 2020 12:14:06 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 159
Connection: keep-alive
Access-Control-Allow-Credentials: true
Vary: Origin

{"status":"success","symbol":"AAPL","last":{"price":446.71,"size":200,"exchange":2,"cond1":14,"cond2":12,"cond3":41,"cond4":0,"timestamp":15968353554560000?????`9??????p???????p?#???????`???????u???????@???????U?????? ??????5??????

认为 这个问题与 SSL_read 函数向缓冲区添加东西有关,但我不确定。我知道此问题并非特定于该网站,因为我已尝试向其他网站发出请求并且得到了相同的结果。这是请求方法的代码:

Response* Requests::get(const char* ip_addr, std::string& route, datastructures::hash::HashTable& headers, datastructures::hash::HashTable& parameters){
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server;
    server.sin_port = htons(443);
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(ip_addr);
    connect(sock, (struct sockaddr*)&server, sizeof(server));
    cout<<SSL_load_error_strings()<<endl;  
    cout<<SSL_library_init()<<endl; 
    SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method()); 
    SSL* conn = SSL_new(ctx);
    cout<<SSL_set_fd(conn, sock)<<endl; 
    cout<<SSL_connect(conn)<<endl; 
    std::vector<datastructures::hash::Key> params = parameters.getTable();
    std::vector<datastructures::hash::Key> heads = headers.getTable();
    std::ostringstream os;
    os << "GET " << route <<"?";
    std::string request = os.str();
    os.str("");
    {
      int i;
      for(i=0;i<params.size();i++){
        os << params[i].key << "="<< *(std::string*)(params[i].value) << "&";
        request+=os.str();
        os.str("");
      }
      request += " HTTP/1.1 \r\n";
      request+=os.str();
      for(i=0;i<heads.size();i++){
        os << heads[i].key << ": " << *(std::string*)(heads[i].value) << "\r\n";
        request+=os.str();
        os.str("");
      }
      request += "\r\n";
    }
    SSL_write(conn, (const char*)request.c_str(), request.size());
    std::string ret;
    const char* retc = (const char*)malloc(10240*sizeof(char));
    int recv = SSL_read(conn, (void *)retc, 10240);
    while(true){
      ret+=retc;
      free((char*)retc);
      if(recv < 10240){
        break;
      } else{
        recv = SSL_read(conn, (void *)retc, 10240);
        retc = (const char*)malloc(10240*sizeof(char));
      }
    }
    SSL_free(conn);
    close(sock);
    return new Response(ret);

下面是我在主函数中调用方法的方式:

  std::cout << requests::Requests::get("35.186.171.205", route, headers, parameters)->getRawResponse() << std::endl; 
//Get raw response is a method in my response class that just returns the raw http response

显示的代码中存在多个错误。

ret+=retc;

这仅在 retc 是普通 char * 时有效,当它指向的字符串以 '[=14=]' 结尾时。 SSL_read 不会做任何类似的事情。您应该使用 std::stringappend() 重载,它接受一个指针和要添加到此字符串的确切字符数。

  free((char*)retc);

  // ...

    recv = SSL_read(conn, (void *)retc, 10240);
    retc = (const char*)malloc(10240*sizeof(char));

这段代码序列:

  1. 取消分配 retc。该指针现在无效。

  2. 尝试将某些内容读入 retc,这不再有效。

  3. 分配一个新的 retc 指针。

在读取内容之前应该分配一个新缓冲区。此外,甚至没有必要首先完成所有这些工作。以前用于 SSL_read 某些东西的缓冲区完全可以用于 SSL_read 其他东西。它完全适合这份工作。 free 缓冲区,只是为了再次 malloc 它,绝对没有任何用处。

最后,如果您真的打算编写现代 C++ 代码,则无需 mallocfree 任何东西。只需使用 std::vector<char> 并让向量本身为您处理所有内存分配和释放。你很少在现代 C++ 代码中看到手动内存分配和释放,它使用容器正确处理和跟踪所有内存,并自动为你清理它以避免内存泄漏。

只需将所有手动分配内存的实例替换为 std::vector<char>