title: How to correctly send binary data over HTTPS POST?
body: <p>I send binary data from client (Debian 6.0.3) to server (Windows Server 2003). To bypass most firewalls I use <strong>HTTPS POST</strong>. Client and server are implemented using <strong>Boost.Asio</strong> and <strong>OpenSSL</strong>. First I implemented the simplest possible version and it worked fine.</p>
  
  <p><strong>HTTP Header:</strong></p>
  
  <pre><code>POST / HTTP/1.1
  User-Agent: my custom client v.1
  
  [binary data]
  </code></pre>
  
  <p>(<code>[binary data]</code> is not base64 encoded if this matters)</p>
  
  <p>Then, on another client machine it failed (connected to the same server machine). The behavior is not stable. Connection always is established fine (port 443). Most time I pass SSL handshake fine but server receive no data (almost no data, sometimes a packet or two are actually received). Sometimes I receive SSL handshake error "short read". Sometimes I receive invalid data.</p>
  
  <p>Client connects to server, handshakes, sends HTTP POST header and then infinitely sends binary data until something wrong hapenned. For test I use custom generated SSL certificate.</p>
  
  <p><strong>Server code:</strong></p>
  
  <pre><code>namespace ssl = boost::asio::ssl;
  ssl::context context(io_service, ssl::context::sslv23);
  context.set_options(ssl::context::default_workarounds | ssl::context::no_sslv2);
  context.use_certificate_chain_file("server.pem");
  context.use_private_key_file("server.pem", boost::asio::ssl::context::pem);
  
  ssl::stream&lt;tcp::socket&gt; socket(io_service, context);
  
  // standard connection accepting
  
  socket.async_handshake(ssl::stream_base::server, ...);
  ...
  boost::asio::async_read_until(socket, POST_header, "\r\n\r\n", ...);
  ...
  </code></pre>
  
  <p><strong>Client code:</strong></p>
  
  <pre><code>ssl::context context(io_service, ssl::context::sslv23);
  context.load_verify_file("server.crt");
  socket.reset(new ssl::stream&lt;tcp::socket&gt;(io_service, context));
  socket-&gt;set_verify_mode(ssl::verify_none);
  
  // standard connection
  
  socket.async_handshake(ssl::stream_base::client, ...);
  ...
  </code></pre>
  
  <p>(error handling is omitted along with not relevant code)</p>
  
  <p>As you can see, it's the simplest possible SSL connection. What is wrong? Can the reason be a firewall?</p>
  
  <p>I tried simple TCP w/o SSL over the same 443 port, this works fine.</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>Tried adding "Content-Type: application/octet-stream", doesn't help.</p>
  
  <p><strong>EDIT 2:</strong></p>
  
  <p>Usually I receive HTTP POST header fine. Then I send data chunks as <code>chunk-size(4 bytes)chunk(chunk-size bytes)...</code>. Server receives <code>chunk-size</code> fine, but then nothing. Client doesn't notify server problems (no errors) and continue to send data. Sometimes server can receive chunk or two, sometimes it receives invalid <code>chunk-size</code>, but most time just nothing.</p>
  
  <p><strong>EDIT 3:</strong></p>
  
  <p>Compared captured traffic on client and server, didn't find any differences. </p>
  
  <p><strong>Solution</strong></p>
  
  <p>I was misled from the start with this problem. Narrowed it down to surprising details:</p>
  
  <p>Sending over SSL socket fails if I use Boost.Asio multi-buffers in Boost v.1.48 (the most recent one at this moment). Example:</p>
  
  <pre><code>// data to send, protocol is [packet size: 4 bytes][packet: packet_size bytes]
  std::vector&lt;char&gt; packet = ...;
  uint32_t packet_size = packet.size();
  // prepare buffers
  boost::array&lt;boost::asio::const_buffer, 2&gt; bufs = {{boost::asio::buffer(&amp;packet_size, sizeof(packet_size)), boost::asio::buffer(packet)}};
  // send multi buffers by single call
  boost::asio::async_write(socket, bufs, ...);
  </code></pre>
  
  <p>Sending separately <code>packet_size</code> and <code>packet</code> in this example works around the problem. I'm far from calling any suspicious behavior as a bug, especially if it's related with Boost libraries. But this one really looks like a bug. Tried on Boost v.1.47 - works fine. Tried with usual TCP socket (not SSL one) - works fine. The same on both Linux and Windows. </p>
  
  <p>I'm going to find any reports about this problem in Asio mailing list and will report it if nothing found.</p>