Quantcast
Viewing all articles
Browse latest Browse all 1529

boost beast async stackless coroutine HTTPS client throws: 167772451 - application data after close notify (SSL routines)

I'm trying to develop a quick HTTPS client using boost::beast (version 1.86) and stackless coroutines. I'm throwing up an HTTPS post to api.mailgun.net.

Everything works EXCEPT RIGHT AFTER the async_shutdown is called an SSL 167772451 - application data after close notify (SSL routines) is thrown.

I'm not sure why that is. The request_/response_ pointers should not be freed at this point and all of the reading should be completed in its entirety.

Below is the code. Again, it fails right after async_shutdown is called in the last function which is the biggest co-routine. Is this error "normal" and ignorable?

/*** Do the session*/struct Session{    boost::asio::coroutine coroutine_;    boost::shared_ptr<http_ssl_stream> stream_;    boost::shared_ptr<RequestType> request_;    uint timeout_;    std::string host_;    std::string port_;    std::unique_ptr<boost::asio::ip::tcp::resolver> resolver_;    std::unique_ptr<ResponseType> response_;    std::unique_ptr<BufferType> buffer_;    /**    * First call    */    template<typename Self>    void operator()( Self &self )    {        // Set SNI Hostname (many hosts need this to handshake successfully)        if( !SSL_set_tlsext_host_name(stream_->native_handle(), host_.c_str()) )        {            // Callback with error            return self.complete( boost::beast::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category() ), boost::none );        }        // Resolve the resolve        resolver_.reset( new boost::asio::ip::tcp::resolver( stream_->get_executor() ) );        // Resolve        resolver_->async_resolve( host_, port_, std::move( self ) );    }    /**    * On resolved call    */    template<typename Self>    void operator()( Self &self, boost::beast::error_code error, boost::asio::ip::tcp::resolver::results_type results )    {        // Resolve error, quit        if( error )        {            return self.complete( error, boost::none );        }        // Set the expiration        boost::beast::get_lowest_layer( *stream_ ).expires_after( std::chrono::seconds( timeout_ ) );        // Do a connnect        boost::beast::get_lowest_layer( *stream_ ).async_connect(                    results,                    std::move( self )                );    }    /**    * On connected    */    template<typename Self>    void operator()( Self &self, boost::beast::error_code error, boost::asio::ip::tcp::resolver::results_type::endpoint_type results )    {        // Connect error        if( error )        {            return self.complete( error, boost::none );        }        // Set the expiration        boost::beast::get_lowest_layer( *stream_ ).expires_after( std::chrono::seconds( timeout_ ) );        // Do a handshake        stream_->async_handshake(                    boost::asio::ssl::stream_base::client,                    std::move( self )                );    }    /**    * After handshake    */    template<typename Self>    void operator()( Self &self, boost::beast::error_code error, std::size_t bytes_transferred=0 )    {        // Coroutine for easy state knowing        BOOST_ASIO_CORO_REENTER( coroutine_ )        {            /*            // Do the handshake            BOOST_ASIO_CORO_YIELD            {                // Connect error                if( error )                    return self.complete( error, boost::none );                // Set the expiration                boost::beast::get_lowest_layer( *stream_ ).expires_after( std::chrono::seconds( timeout_ ) );                // Do a handshake                stream_->async_handshake(                            boost::asio::ssl::stream_base::client,                            std::move( self )                        );            }            */            // Do the write            BOOST_ASIO_CORO_YIELD            {                // Handshake error                if( error )                {                    return self.complete( error, boost::none );                }                // Set up an HTTP GET request message                request_->version( 11 );                //request_->body() = body_;                // Set the expiration                boost::beast::get_lowest_layer( *stream_ ).expires_after( std::chrono::seconds( timeout_ ) );                // Write the request                boost::beast::http::async_write( *stream_, *request_, std::move( self ) );            }            // Execute a read            BOOST_ASIO_CORO_YIELD            {                // Write error                if( error )                {                    return self.complete( error, boost::none );                }                // Create the response                response_.reset( new ResponseType );                // Create the buffa                buffer_.reset( new BufferType );                // Set the expiration                boost::beast::get_lowest_layer( *stream_ ).expires_after( std::chrono::seconds( timeout_ ) );                // Receive the HTTP response                boost::beast::http::async_read( *stream_, *buffer_, *response_, std::move( self ) );            }            // Shutdown the socket            BOOST_ASIO_CORO_YIELD            {                // Read error                if( error )                {                    return self.complete( error, boost::none );                }                // Set the expiration                boost::beast::get_lowest_layer( *stream_ ).expires_after( std::chrono::seconds( timeout_ ) );                // Receive the HTTP response                stream_->async_shutdown( std::move( self ) );            }            // Shutdown error            if( error == boost::asio::error::eof or error == boost::asio::ssl::error::stream_truncated )            {                // Rationale:                // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error                error = {};            }            // Did we get it?            if( error )            {                self.complete( error, boost::none );                return;            }            // Return no error and the buffer            self.complete( error, *response_ );        }    }};

Viewing all articles
Browse latest Browse all 1529

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>