title: stream truncated error on HTTPS TLS handshake via a HTTP proxy using boost::asio (synchronous calls)
body: <p>I've working on some HTTP code to connect to REST endpoints. I'm working within a company network and the connection to the outside world must go through a HTTP proxy, whereas the endpoint is on HTTPS.</p>
  <p>Now, I've been successful in making these calls using both Python <code>requests</code> and <code>curl</code>, however making the same calls in C++ has been a pain.</p>
  <p>I'm attempting to perform a handshake through this proxy with the code below (connecting to an example Postmen endpoint), which has been adapted from the following examples:</p>
  <ul>
  <li><a href="https://gist.github.com/derofim/c2562832a58c607f0728aba868a5a515" rel="nofollow noreferrer">https://gist.github.com/derofim/c2562832a58c607f0728aba868a5a515</a></li>
  <li><a href="https://stackoverflow.com/questions/63300832/boost-asio-https-synchronous-call-error-code-400-bad-request">Boost Asio https synchronous call- Error code 400 bad request</a></li>
  </ul>
  <pre><code>#include &lt;boost/asio.hpp&gt;
  #include &lt;boost/asio/ssl.hpp&gt;
  
  #include &lt;boost/beast.hpp&gt;
  
  #include &lt;boost/beast/http.hpp&gt;
  #include &lt;boost/beast/http/empty_body.hpp&gt;
  #include &lt;boost/beast/http/fields.hpp&gt;
  #include &lt;boost/beast/http/message.hpp&gt;
  #include &lt;boost/beast/http/string_body.hpp&gt;
  
  #include&lt;boost/certify/https_verification.hpp&gt;
  
  #include &lt;iostream&gt;
  
  using tcp = boost::asio::ip::tcp;
  namespace http = boost::beast::http;
  
  // https://postman-echo.com/post see https://docs.postman-echo.com/?version=latest
  static const std::string
          server_endpoint = &quot;/post&quot;,
          hostname = &quot;postman-echo.com&quot;,
          target = &quot;https://postman-echo.com:443&quot;,
          port_no = &quot;443&quot;,
          authorization_token =
          &quot;Auth: &quot;
          &quot;c3RhdGljIGNvbnN0IHN0ZDo6c3RyaW5nIGF1dGhvcml6YXRpb&quot;
          &quot;25fdG9rZW4gPSAiQXV0aDogIj&quot;
          &quot;sK&quot;,
          client_name = &quot;User-Agent: demo program 0.01&quot;,
          req_str = R&quot;(name=blabla&amp;password=bloblo)&quot;;
  
  int main() {
      boost::asio::io_service io_service;
      boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
  
      // Establish TCP base socket to Proxy
      tcp::socket base_sock{io_service};
      tcp::resolver resolver(io_service);
  
      {
          // Connect socket via proxy
          const boost::asio::ip::basic_resolver_results&lt;boost::asio::ip::tcp&gt; proxy_hosts = resolver.resolve(&quot;PROXY_ADDR&quot;, &quot;PROXY_PORT&quot;);
          if (proxy_hosts.empty()) {
              throw std::range_error(&quot;Proxy cannot be resolved.&quot;);
          }
          std::cout &lt;&lt; &quot;Proxy IP address: &quot; &lt;&lt; proxy_hosts-&gt;endpoint().address() &lt;&lt; std::endl;
  
          //boost::asio::ip::tcp::socket::lowest_layer_type&amp; socket = base_sock.lowest_layer();
          base_sock.connect(proxy_hosts-&gt;endpoint());
      }
  
      {
          // Converts request to transparent TCP/IP tunnel. To facilitate TLS communications
          // through HTTP proxy.
          http::request&lt;http::string_body&gt; req1{http::verb::connect, target, 11};
          req1.set(http::field::host, target);
          http::write(base_sock, req1);
  
          boost::beast::flat_buffer buffer;
  
          http::response&lt;http::empty_body&gt; res;
          http::parser&lt;/* isRequest */ false, http::empty_body&gt; http_parser(res);
  
          /** Set the skip parse option. */
          http_parser.skip(true); // see https://stackoverflow.com/a/49837467/10904212
  
          http::read_header(base_sock, buffer, http_parser);
  
          // Write the message to standard out
          std::cout &lt;&lt; &quot;target_host response: &quot; &lt;&lt; res &lt;&lt; std::endl;
      }
  
      ctx.set_verify_mode(boost::asio::ssl::verify_peer);
      //ctx.load_verify_file(&quot;/** ssl/cacert from python requests library */&quot;);
      //ctx.add_verify_path(&quot;/** CA certificates from Curl via strace https://serverfault.com/questions/485597/default-ca-cert-bundle-location */&quot;);
      //ctx.load_verify_file(&quot;/** CA certs from curl via calling endpoints with --verbose */&quot;);
      //ctx.set_default_verify_paths(); 
      boost::certify::enable_native_https_server_verification(ctx); // from lib https://github.com/djarek/certify
      ctx.set_options(boost::asio::ssl::context::default_workarounds |
                      boost::asio::ssl::context::no_sslv2 |
                      boost::asio::ssl::context::no_sslv3);
  
      boost::asio::ssl::stream&lt;boost::asio::ip::tcp::socket&amp;&gt; ssl_socket(base_sock,
                                                                         ctx);
  
      {
          //ssl_socket.handshake(boost::asio::ssl::stream_base::client);
          ssl_socket.handshake(boost::asio::ssl::stream&lt;tcp::socket&amp;&gt;::client);
  
          /** Make REST calls here */
      }
  }
  </code></pre>
  <p>Running the above code fails on the handshake step, with a &quot;stream truncated&quot; error.</p>
  <p>My attempts thus far have been:</p>
  <ul>
  <li>Verifying certificates used were correct, of which I've fed in the certificates from Python, Curl and from <a href="https://github.com/djarek/certify" rel="nofollow noreferrer">certify</a>. This hasn't resolved the problem.</li>
  <li>Checking Python and Curl traces for their protocol steps, however I'm unable to validate this in C++ due to the limited error messages from boost::asio; whilst <code>gdb</code> traces has been difficult to follow.</li>
  <li>Lots of stackoverflow digging, unfortunately I was unable to piece together a working prototype.</li>
  </ul>
  <p>Given my limited experiences in writing network code, though, it's likely that the error is in my logic somewhere rather than an incorrect environment.</p>
  <p>Wondering if anyone could give any pointers to where might the code be incorrect?</p>