首页 > 解决方案 > OpenSSL 偶尔会打印随机垃圾

问题描述

我刚刚开始使用 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

标签: c++chttpsopenssl

解决方案


显示的代码中有多个错误。

ret+=retc;

只有当它指向的字符串由 a 终止时,retc这才有效。不做任何事情。您应该使用'重载,它需要一个指针和一个确切数量的字符来添加到这个字符串中。char *'\0'SSL_readstd::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任何事情。只需使用 astd::vector<char>并让向量本身为您处理所有内存分配和释放。您很少在现代 C++ 代码中看到手动内存分配和释放,它使用容器来正确处理和正确跟踪所有内存,并自动清理它以避免内存泄漏。

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


推荐阅读