will_deref_and_erase_t asio_server_connection::handle_http_line()

in Release/src/http/listener/http_server_asio.cpp [634:759]


will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::system::error_code& ec)
{
    auto thisRequest = http_request::_create_request(make_unique<linux_request_context>());
    set_request(thisRequest);
    if (ec)
    {
        // client closed connection
        if (ec == boost::asio::error::eof || // peer has performed an orderly shutdown
            ec ==
                boost::asio::error::operation_aborted ||  // this can be removed. ECONNABORTED happens only for accept()
            ec == boost::asio::error::connection_reset || // connection reset by peer
            ec == boost::asio::error::timed_out           // connection timed out
        )
        {
            return finish_request_response();
        }
        else
        {
            thisRequest._reply_if_not_already(status_codes::BadRequest);
            m_close = true;
            (will_erase_from_parent_t) do_bad_response();
            (will_deref_t) deref();
            return will_deref_and_erase_t {};
        }
    }
    else
    {
        // read http status line
        std::istream request_stream(&m_request_buf);
        request_stream.imbue(std::locale::classic());
        std::skipws(request_stream);

        web::http::method http_verb;
#ifndef _UTF16_STRINGS
        request_stream >> http_verb;
#else
        {
            std::string tmp;
            request_stream >> tmp;
            http_verb = utility::conversions::latin1_to_utf16(tmp);
        }
#endif

        if (boost::iequals(http_verb, methods::GET))
            http_verb = methods::GET;
        else if (boost::iequals(http_verb, methods::POST))
            http_verb = methods::POST;
        else if (boost::iequals(http_verb, methods::PUT))
            http_verb = methods::PUT;
        else if (boost::iequals(http_verb, methods::DEL))
            http_verb = methods::DEL;
        else if (boost::iequals(http_verb, methods::HEAD))
            http_verb = methods::HEAD;
        else if (boost::iequals(http_verb, methods::TRCE))
            http_verb = methods::TRCE;
        else if (boost::iequals(http_verb, methods::CONNECT))
            http_verb = methods::CONNECT;
        else if (boost::iequals(http_verb, methods::OPTIONS))
            http_verb = methods::OPTIONS;

        // Check to see if there is not allowed character on the input
        if (!web::http::details::validate_method(http_verb))
        {
            thisRequest.reply(status_codes::BadRequest);
            m_close = true;
            (will_erase_from_parent_t) do_bad_response();
            (will_deref_t) deref();
            return will_deref_and_erase_t {};
        }

        thisRequest.set_method(http_verb);

        std::string http_path_and_version;
        std::getline(request_stream, http_path_and_version);
        const size_t VersionPortionSize = sizeof(" HTTP/1.1\r") - 1;

        // Make sure path and version is long enough to contain the HTTP version
        if (http_path_and_version.size() < VersionPortionSize + 2)
        {
            thisRequest.reply(status_codes::BadRequest);
            m_close = true;
            (will_erase_from_parent_t) do_bad_response();
            (will_deref_t) deref();
            return will_deref_and_erase_t {};
        }

        // Get the path - remove the version portion and prefix space
        try
        {
            thisRequest.set_request_uri(utility::conversions::to_string_t(
                http_path_and_version.substr(1, http_path_and_version.size() - VersionPortionSize - 1)));
        }
        catch (const std::exception& e) // may be std::range_error indicating invalid Unicode, or web::uri_exception
        {
            thisRequest.reply(status_codes::BadRequest, e.what());
            m_close = true;
            (will_erase_from_parent_t) do_bad_response();
            (will_deref_t) deref();
            return will_deref_and_erase_t {};
        }

        // Get the version
        std::string http_version =
            http_path_and_version.substr(http_path_and_version.size() - VersionPortionSize + 1, VersionPortionSize - 2);

        auto requestImpl = thisRequest._get_impl().get();
        web::http::http_version parsed_version = web::http::http_version::from_string(http_version);
        requestImpl->_set_http_version(parsed_version);

        // if HTTP version is 1.0 then disable pipelining
        if (parsed_version == web::http::http_versions::HTTP_1_0)
        {
            m_close = true;
        }

        // Get the remote IP address
        boost::system::error_code socket_ec;
        auto endpoint = m_socket->remote_endpoint(socket_ec);
        if (!socket_ec)
        {
            requestImpl->_set_remote_address(utility::conversions::to_string_t(endpoint.address().to_string()));
        }

        return handle_headers();
    }
}