代码之家  ›  专栏  ›  技术社区  ›  Bill Richard

简单boost asio https不返回正文

  •  1
  • Bill Richard  · 技术社区  · 6 年前

    我试图使用boost示例https客户端,但是,一个简单的get请求到google.com,路径/返回没有正文。

    输出:

    Verifying /OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
    Verifying /C=US/O=Google Trust Services/CN=Google Internet Authority G3
    Verifying /C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com
    Handshake OK
    Request:
    GET / HTTP/1.1
    Host: www.google.com
    Accept: */*
    Connection: close
    
    
    Reply: HTTP/1.1 200 OK
    Date: Thu, 12 Jul 2018 04:23:20 GMT
    Expires: -1
    Cache
    

    奇怪的是,它在缓存中被切断了。代码如下:

    #include <iostream>
    #include <istream>
    #include <ostream>
    #include <string>
    #include <boost/asio.hpp>
    #include <boost/bind.hpp>
    #include <boost/asio/ssl.hpp>
    
    using boost::asio::ip::tcp;
    
    #include <wincrypt.h>
    #pragma comment(lib, "crypt32.lib")
    
    enum { max_length = 10000 };
    
    class client
    {
    public:
        client(boost::asio::io_service& io_service,
            boost::asio::ssl::context& context,
            boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
            : socket_(io_service, context)
        {
            socket_.set_verify_mode(boost::asio::ssl::verify_peer);
            socket_.set_verify_callback(
                boost::bind(&client::verify_certificate, this, _1, _2));
    
            std::ostream request_stream(&request_);
            request_stream << "GET / HTTP/1.1\r\n";
            request_stream << "Host: www.google.com\r\n";
            request_stream << "Accept: */*\r\n";
            request_stream << "Connection: close\r\n\r\n";
    
    
            boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
                boost::bind(&client::handle_connect, this,
                    boost::asio::placeholders::error));
    
    
        }
    
        bool verify_certificate(bool preverified,
            boost::asio::ssl::verify_context& ctx)
        {
            // The verify callback can be used to check whether the certificate that is
            // being presented is valid for the peer. For example, RFC 2818 describes
            // the steps involved in doing this for HTTPS. Consult the OpenSSL
            // documentation for more details. Note that the callback is called once
            // for each certificate in the certificate chain, starting from the root
            // certificate authority.
    
            // In this example we will simply print the certificate's subject name.
            char subject_name[256];
            X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
            X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
            std::cout << "Verifying " << subject_name << "\n";
    
            return preverified;
        }
    
        void handle_connect(const boost::system::error_code& error)
        {
            if (!error)
            {
                socket_.async_handshake(boost::asio::ssl::stream_base::client,
                    boost::bind(&client::handle_handshake, this,
                        boost::asio::placeholders::error));
            }
            else
            {
                std::cout << "Connect failed: " << error.message() << "\n";
            }
        }
    
        void handle_handshake(const boost::system::error_code& error)
        {
            if (!error)
            {
                std::cout << "Handshake OK " << "\n";
                std::cout << "Request: " << "\n";
                const char* header = boost::asio::buffer_cast<const char*>(request_.data());
                std::cout << header << "\n";
    
    
                boost::asio::async_write(socket_,
                    request_,
                    boost::bind(&client::handle_write, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
            }
            else
            {
                std::cout << "Handshake failed: " << error.message() << "\n";
            }
        }
    
        void handle_write(const boost::system::error_code& error,
            size_t bytes_transferred)
        {
            if (!error)
            {
                boost::asio::async_read(socket_,
                    boost::asio::buffer(reply_, bytes_transferred),
                    boost::bind(&client::handle_read, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
            }
            else
            {
                std::cout << "Write failed: " << error.message() << "\n";
            }
        }
    
        void handle_read(const boost::system::error_code& error,
            size_t bytes_transferred)
        {
            if (!error)
            {
                std::cout << "Reply: ";
                std::cout.write(reply_, bytes_transferred);
                std::cout << "\n";
            }
            else
            {
                std::cout << "Read failed: " << error.message() << "\n";
            }
        }
    
    private:
        boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
        char reply_[max_length];
        boost::asio::streambuf request_;
    };
    
    void add_windows_root_certs(boost::asio::ssl::context &ctx)
    {
        HCERTSTORE hStore = CertOpenSystemStore(0, L"ROOT");
        if (hStore == NULL) {
            return;
        }
    
        X509_STORE *store = X509_STORE_new();
        PCCERT_CONTEXT pContext = NULL;
        while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) != NULL) {
            // convert from DER to internal format
            X509 *x509 = d2i_X509(NULL,
                (const unsigned char **)&pContext->pbCertEncoded,
                pContext->cbCertEncoded);
            if (x509 != NULL) {
                X509_STORE_add_cert(store, x509);
                X509_free(x509);
            }
        }
    
        CertFreeCertificateContext(pContext);
        CertCloseStore(hStore, 0);
    
        // attach X509_STORE to boost ssl context
        SSL_CTX_set_cert_store(ctx.native_handle(), store);
    }
    
    int main(int argc, char* argv[])
    {
        try
        {
            namespace ssl = boost::asio::ssl;
    
            boost::asio::io_service io_service;
    
            boost::asio::ip::tcp::resolver resolver(io_service); 
            boost::asio::ip::tcp::resolver::query query("www.google.com", "443");
            boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
    
            ssl::context ctx(ssl::context::tlsv12_client);
    
    
            add_windows_root_certs(ctx);
            ctx.set_verify_mode(ssl::verify_peer | ssl::verify_fail_if_no_peer_cert);
    
            // use custom verify_callback here for debugging purposes
    
            client c(io_service, ctx, iterator);
    
            io_service.run();
        }
        catch (std::exception& e)
        {
            std::cerr << "Exception: " << e.what() << "\n";
        }
    
        system("pause");
    
        return 0;
    }
    

    连接是成功的,我在wireshark中监视它,它是一个真正的ssl连接,我指定http/1.1。不知道我在这里错过了什么。

    1 回复  |  直到 6 年前
        1
  •  3
  •   sehe    6 年前
        boost::asio::async_read(socket_,
            boost::asio::buffer(reply_, bytes_transferred),
            boost::bind(&client::handle_read, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
    

    告诉read函数缓冲区的大小是 bytes_transferred 是的。那是胡说。

    使用足够大的缓冲区,重复读取 使用 boost::asio::streambuf 相反。

    哦。并考虑对http请求使用boost beast