And*_*hko 13 c++ ssl https boost-asio
我将二进制数据从客户端(Debian 6.0.3)发送到服务器(Windows Server 2003).为了绕过大多数防火墙,我使用HTTPS POST.客户端和服务器使用Boost.Asio和OpenSSL实现.首先,我实现了最简单的版本,它运行良好.
HTTP标头:
POST / HTTP/1.1
User-Agent: my custom client v.1
[binary data]
Run Code Online (Sandbox Code Playgroud)
([binary data]
如果这很重要,则不是base64编码的)
然后,在另一台客户机上它失败了(连接到同一台服务器机器).行为不稳定.连接始终建立良好(端口443).大多数时候我通过SSL握手很好但服务器没有接收数据(几乎没有数据,有时实际收到一两个数据包).有时我收到SSL握手错误"短读".有时我收到无效数据.
客户端连接到服务器,握手,发送HTTP POST标头,然后无限发送二进制数据,直到出现错误.对于测试,我使用自定义生成的SSL证书.
服务器代码:
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<tcp::socket> 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", ...);
...
Run Code Online (Sandbox Code Playgroud)
客户代码:
ssl::context context(io_service, ssl::context::sslv23);
context.load_verify_file("server.crt");
socket.reset(new ssl::stream<tcp::socket>(io_service, context));
socket->set_verify_mode(ssl::verify_none);
// standard connection
socket.async_handshake(ssl::stream_base::client, ...);
...
Run Code Online (Sandbox Code Playgroud)
(错误处理与不相关的代码一起被省略)
如您所见,这是最简单的SSL连接.怎么了?原因可能是防火墙吗?
我在同一个443端口上尝试了简单的TCP w/o SSL,这很好用.
编辑:
尝试添加"Content-Type:application/octet-stream",没有用.
编辑2:
通常我会收到HTTP POST标头.然后我发送数据块为chunk-size(4 bytes)chunk(chunk-size bytes)...
.服务器收到chunk-size
罚款,但没有.客户端不会通知服务器问题(没有错误)并继续发送数据.有时服务器可以接收一两个块,有时它会收到无效chunk-size
,但大部分时间都没有.
编辑3:
比较客户端和服务器上捕获的流量,没有发现任何差异.
解
我从一开始就被这个问题误导了.将其缩小到令人惊讶的细节:
如果我在Boost v.1.48中使用Boost.Asio多缓冲区(此时最新的那个),则通过SSL套接字发送失败.例:
// data to send, protocol is [packet size: 4 bytes][packet: packet_size bytes]
std::vector<char> packet = ...;
uint32_t packet_size = packet.size();
// prepare buffers
boost::array<boost::asio::const_buffer, 2> bufs = {{boost::asio::buffer(&packet_size, sizeof(packet_size)), boost::asio::buffer(packet)}};
// send multi buffers by single call
boost::asio::async_write(socket, bufs, ...);
Run Code Online (Sandbox Code Playgroud)
单独发送packet_size
和packet
在此示例中解决问题.我没有把任何可疑行为称为bug,特别是如果它与Boost库有关.但这个看起来真的像个bug.尝试Boost v.1.47 - 工作正常.尝试使用通常的TCP套接字(不是SSL) - 工作正常.Linux和Windows都是一样的.
我将在Asio邮件列表中找到有关此问题的任何报告,如果没有找到则会报告.
如果您不必在Web服务器前运行,则不必使用HTTPS协议.从防火墙的角度来看,HTTPS看起来像是另一个SSL连接,它不知道经历了什么.因此,如果您唯一需要的只是传递数据 - 而不是实际的Web服务器,请使用443端口上的SSL连接.
因此,只需对SSL连接进行故障排除,问题就与HTTP无关.
如果要使用HTTP Web服务器而不是自定义客户端:
两点:
最简单的是
POST /url HTTP/1.0
User-Agent: my custom client v.1
Content-Type: application/octet-stream
Content-Length: NNN
Actual Content
Run Code Online (Sandbox Code Playgroud)
或者对于HTTP/1.1
POST /url HTTP/1.1
Host: www.example.com
User-Agent: my custom client v.1
Content-Type: application/octet-stream
Content-Length: NNN
Actual Content
Run Code Online (Sandbox Code Playgroud)
注意:您无法发送无限数据.HTTP协议需要固定的内容长度,并且大多数时候Web服务器会在将数据传递给后端之前先加载数据.
所以你必须通过块传输数据.
我从一开始就被这个问题误导了。将其缩小到令人惊讶的细节:
如果我在 Boost v.1.48(目前最新的)中使用 Boost.Asio 多缓冲区,则通过 SSL 套接字发送会失败。例子:
// data to send, protocol is [packet size: 4 bytes][packet: packet_size bytes]
std::vector<char> packet = ...;
uint32_t packet_size = packet.size();
// prepare buffers
boost::array<boost::asio::const_buffer, 2> bufs = {{boost::asio::buffer(&packet_size, sizeof(packet_size)), boost::asio::buffer(packet)}};
// send multi buffers by single call
boost::asio::async_write(socket, bufs, ...);
Run Code Online (Sandbox Code Playgroud)
单独发送packet_size
,packet
在本例中可以解决这个问题。我绝不会将任何可疑行为称为错误,尤其是当它与 Boost 库相关时。但这确实看起来像一个错误。在 Boost v.1.47 上试过 - 工作正常。尝试使用通常的 TCP 套接字(不是 SSL 套接字) - 工作正常。在 Linux 和 Windows 上都一样。
我将在 Asio 邮件列表中找到有关此问题的任何报告,如果没有找到,我将报告它。