2011-04-01 チャンクとかの処理がどうしても…
Boost.AsioでSSL非同期通信
ちょこちょこ、boost::asio::streambufで例外が投げられるけど、
一応まともに動くコードになりました。
io_service::workって作ってないとスレッドが落ちちゃうのね…
template<boost::asio::ssl::context_base::method SSL_TYPE = boost::asio::ssl::context::sslv23> class async_https{ public: async_https(boost::asio::io_service& io_service,string_type* response) : io_service_(io_service),protocol_("https"),work_(std::auto_ptr<boost::asio::io_service::work>(new boost::asio::io_service::work(io_service))), ctx_(io_service,SSL_TYPE), socket_(io_service,ctx_), resolver_(io_service) { response_ = response; thread = boost::thread(boost::bind(&boost::asio::io_service::run,&io_service_)); disconnect = false; } string_type protocol() const {return protocol_;} std::auto_ptr<boost::asio::io_service::work> work_; boost::asio::io_service& io_service_; const string_type protocol_; ~async_https(){ thread.detach(); thread.join(); io_service_.reset(); } void start(const std::string& host,boost::asio::streambuf *request){ std::ostream os(&request_); os << request; boost::asio::ip::tcp::resolver::query query(host, "https"); resolver_.async_resolve( query, boost::bind(&async_https::handle_resolve, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator) ); } void stop(){ disconnect=true; } private: //ヘッダー処理関数 void header_process(std::string *data) { //レスポンスチェック std::istringstream response_stream(*data); std::string http_version; response_stream >> http_version; unsigned int status_code; response_stream >> status_code; std::string status_message; response_stream >> status_message; //ヘッダー切り捨て data->erase(0,data->find("\r\n\r\n")+4); if (!response_stream || http_version.substr(0, 5) != "HTTP/") { throw std::invalid_argument("Invalid response"); } } //async_resolve後ハンドル void handle_resolve(const boost::system::error_code& err,boost::asio::ip::tcp::resolver::iterator endpoint_iterator) { if(!err) { //正常 boost::asio::ip::tcp::endpoint endpoint= *endpoint_iterator; socket_.lowest_layer().async_connect( endpoint, boost::bind(&async_https::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator) ); } else throw std::invalid_argument("Error: "+err.message()); } //async_connect後ハンドル void handle_connect(const boost::system::error_code& err,boost::asio::ip::tcp::resolver::iterator endpoint_iterator) { if(!err) { //正常接続 socket_.async_handshake( boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::client, boost::bind(&async_https::handle_handshake, this, boost::asio::placeholders::error) ); } else if(endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) { //接続ミス socket_.lowest_layer().close(); boost::asio::ip::tcp::endpoint endpoint= *endpoint_iterator; socket_.lowest_layer().async_connect( endpoint, boost::bind(&async_https::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator) ); } else throw std::invalid_argument("Error: "+err.message()); } //async_handshake後ハンドル void handle_handshake(const boost::system::error_code& err) { if(!err) { //正常ハンドシェイク boost::asio::async_write( socket_, request_, boost::bind(&async_https::handle_write_request, this, boost::asio::placeholders::error) ); } else throw std::invalid_argument("Error: "+err.message()); } //async_write後ハンドル void handle_write_request(const boost::system::error_code& err) { if(!err) { //正常送信 read(); } else throw std::invalid_argument("Error: "+err.message()); } void read() { boost::asio::async_read( socket_, response_stream_, boost::asio::transfer_at_least(1), boost::bind(&async_https::handle_read,this,boost::asio::placeholders::error) ); } //readハンドル void handle_read(const boost::system::error_code& err) { if(!err) { buffer = static_cast<std::string>(boost::asio::buffer_cast<const char*>(response_stream_.data())); header_process(&buffer); *response_ = buffer; if(disconnect) return; read(); } else if (err == boost::asio::error::eof || err == boost::asio::error::shut_down ) { std::cout << "Error: "+err.message(); } } boost::thread thread; bool disconnect; boost::asio::ssl::context ctx_; boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; boost::asio::ip::tcp::resolver resolver_; boost::asio::streambuf request_; boost::asio::streambuf response_stream_; std::string *response_; std::string buffer; };
あとはチャンクの処理を組み込ませたいんだよな・・・。
非同期だと末尾に変なゴミがついて、うまく+=で追加できないんだよ。
「ここはこうした方が良いよ」って事があったら、コメントお願いします。
