Запрос HTTPS с Boost.Asio и OpenSSL

Я пытаюсь прочитать символ тикера https://mtgox.com/api/0/data/ticker.php из моего приложения на С++. Я использую Boost.Asio и OpenSSL, потому что для службы требуется HTTPS.

Boost version: 1.47.0

OpenSSL: 1.0.0d [8.02.2011] Win32

Для приложения; Я взял пример из http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/example/ssl/client.cpp чтобы начать и изменить его следующим образом:

Здесь я хочу подключиться к:

boost::asio::ip::tcp::resolver::query query("mtgox.com", "443");

Я установил проверку на отсутствие, потому что квитирование не сработало иначе. Я не уверен, что это проблема с mtgox или эта реализация действительно строгая, потому что когда я печатаю сертификат на экране, он выглядит законным (и хром не имеет проблем с этим при посещении страницы тикера).

socket_.set_verify_mode(boost::asio::ssl::context::verify_none);

Это запрос, который я отправляю:

std::stringstream request_;

request_ << "GET /api/0/data/ticker.php HTTP/1.1\r\n";
request_ << "Host: mtgox.com\r\n";
request_ << "Accept-Encoding: *\r\n";
request_ << "\r\n";

boost::asio::async_write(socket_, boost::asio::buffer(request_.str()), boost::bind(&client::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

(полный код: http://pastebin.com/zRTTqZVe)

Я столкнулся с следующей ошибкой:

Connection OK!
Verifying:
/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority
Sending request: 
GET /api/0/data/ticker.php HTTP 1.1
Host: mtgox.com
Accept-Encoding: *

Sending request OK!

Read failed: An existing connection was forcibly closed by the remote host

Я иду в правильном направлении с этим? Сообщение об ошибке на самом деле не описывает проблему, и я не знаю, какой шаг я сделал неправильно.

Update: Я использовал cURL, чтобы понять, что пошло не так:

curl --trace-ascii out.txt https://mtgox.com/api/0/data/ticker.php

(полный вывод: http://pastebin.com/Rzp0RnAK) Он не работает во время проверки. Когда я подключаюсь к "небезопасному" параметру

curl --trace-ascii out.txt -k https://mtgox.com/api/0/data/ticker.php

(полный вывод: http://pastebin.com/JR43A7ux)

все работает нормально.

Fix:

  • Я исправил опечатку в заголовках HTTP
  • Я добавил корневой сертификат и снова вернулась проверка SSL.

Ответы

Ответ 1

Короче:

  • Вы отправляете "HTTP 1.1" вместо "HTTP/1.1". Этого достаточно, чтобы сервер отказался от вашего запроса. Существуют и другие различия между вашим запросом и cURL, вам может потребоваться изменить эти параметры, даже если они кажутся мне действительными.

  • Возможно, OpenSSL не имеет корневого сертификата, используемого сервером, в отличие от Chrome, и почему проверка не выполняется.

Подробнее:

  • Учитывая рабочий и нерабочий инструмент, вы всегда должны сравнивать, что происходит. Здесь вы имеете выход cURL и ваш запрос - их сравнение показало ряд различий; как правило, даже с зашифрованным соединением вы можете использовать мощный пакетный сниффер, такой как Wireshark, который как можно больше расшифровывает информацию из пакетов. Здесь это позволит увидеть, что на самом деле сервер отправляет меньше пакетов (я ожидаю); другой возможностью было бы то, что ваш клиент не получал данные, отправленные сервером (скажем, потому что у клиента была некоторая ошибка).

  • Если я правильно понял, завиток показал только, почему вам нужно отключить проверку, верно? Сертификат выглядит действительным для меня и на хроме, но корневой центр сертификации совершенно неизвестен; curl упоминает "сертификат CA", то есть сертификат органа по сертификации. Корневой сертификат доверен, поскольку он уже присутствует в базе данных сертификата клиента - я думаю, что у Chrome может быть более полная база данных, чем OpenSSL (которая используется как cURL, так и вашей программой).