LCOV - code coverage report
Current view: top level - boost/beast2/server/http_session.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 0.0 % 123 0
Test Date: 2025-11-13 15:50:43 Functions: 0.0 % 11 0

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/cppalliance/beast2
       8              : //
       9              : 
      10              : #ifndef BOOST_BEAST2_SERVER_HTTP_SESSION_HPP
      11              : #define BOOST_BEAST2_SERVER_HTTP_SESSION_HPP
      12              : 
      13              : #include <boost/beast2/detail/config.hpp>
      14              : #include <boost/beast2/application.hpp>
      15              : #include <boost/beast2/log_service.hpp>
      16              : #include <boost/beast2/format.hpp>
      17              : #include <boost/beast2/read.hpp>
      18              : #include <boost/beast2/write.hpp>
      19              : #include <boost/beast2/server/any_lambda.hpp>
      20              : #include <boost/beast2/server/basic_router.hpp>
      21              : #include <boost/beast2/server/route_handler_asio.hpp>
      22              : #include <boost/beast2/server/router_asio.hpp>
      23              : #include <boost/beast2/error.hpp>
      24              : #include <boost/beast2/detail/except.hpp>
      25              : #include <boost/http_proto/request_parser.hpp>
      26              : #include <boost/http_proto/response.hpp>
      27              : #include <boost/http_proto/serializer.hpp>
      28              : #include <boost/http_proto/string_body.hpp>
      29              : #include <boost/url/parse.hpp>
      30              : #include <boost/asio/prepend.hpp>
      31              : 
      32              : namespace boost {
      33              : namespace beast2 {
      34              : 
      35              : //------------------------------------------------
      36              : /*
      37              : 
      38              : */
      39              : /** Mixin for delivering responses to HTTP requests
      40              : */
      41              : template<class Stream>
      42              : class http_session
      43              :     : private detacher::owner
      44              : {
      45              : public:
      46              :     http_session(
      47              :         application& app,
      48              :         Stream& stream,
      49              :         router_asio<Stream> rr,
      50              :         any_lambda<void(system::error_code)> close_fn);
      51              : 
      52              :     /** Called to start a new HTTP session
      53              : 
      54              :         The stream must be in a connected,
      55              :         correct state for a new session.
      56              :     */
      57              :     void do_session(acceptor_config const& config);
      58              : 
      59              : private:
      60              :     void do_read();
      61              : 
      62              :     void on_read(
      63              :         system::error_code ec,
      64              :         std::size_t bytes_transferred);
      65              : 
      66              :     void on_write(
      67              :         system::error_code const& ec,
      68              :         std::size_t bytes_transferred);
      69              : 
      70              :     void do_fail(core::string_view s,
      71              :         system::error_code const& ec);
      72              : 
      73              :     resumer do_detach() override;
      74              : 
      75              :     void do_resume(system::error_code const& ec) override;
      76              : 
      77              :     void do_resume2(system::error_code ec);
      78              : 
      79              : protected:
      80            0 :     std::string id() const
      81              :     {
      82            0 :         return std::string("[") + std::to_string(id_) + "] ";
      83              :     }
      84              : 
      85              : protected:
      86              :     section sect_;
      87              :     std::size_t id_ = 0;
      88              :     Stream& stream_;
      89              :     router_asio<Stream> rr_;
      90              :     any_lambda<void(system::error_code)> close_;
      91              :     route_state route_state_;
      92              :     http_proto::request_parser pr_;
      93              :     http_proto::serializer sr_;
      94              :     http_proto::response res_;
      95              :     acceptor_config const* pconfig_ = nullptr;
      96              : 
      97              :     using work_guard = asio::executor_work_guard<decltype(
      98              :         std::declval<Stream&>().get_executor())>;
      99              :     std::unique_ptr<work_guard> pwg_;
     100              :     std::unique_ptr<Request> preq_;
     101              :     std::unique_ptr<ResponseAsio<Stream>> pres_;
     102              : };
     103              : 
     104              : //------------------------------------------------
     105              : 
     106              : template<class Stream>
     107            0 : http_session<Stream>::
     108              : http_session(
     109              :     application& app,
     110              :     Stream& stream,
     111              :     router_asio<Stream> rr,
     112              :     any_lambda<void(system::error_code)> close)
     113            0 :     : sect_(use_log_service(app).get_section("http_session"))
     114            0 :     , id_(
     115            0 :         []() noexcept
     116              :         {
     117              :             static std::size_t n = 0;
     118            0 :             return ++n;
     119            0 :         }())
     120            0 :     , stream_(stream)
     121            0 :     , rr_(std::move(rr))
     122            0 :     , close_(close)
     123            0 :     , pr_(app.services())
     124            0 :     , sr_(app.services())
     125              : {
     126            0 : }
     127              : 
     128              : /** Called to start a new HTTP session
     129              : 
     130              :     The stream must be in a connected,
     131              :     correct state for a new session.
     132              : */
     133              : template<class Stream>
     134              : void
     135            0 : http_session<Stream>::
     136              : do_session(
     137              :     acceptor_config const& config)
     138              : {
     139            0 :     pconfig_ = &config;
     140            0 :     pr_.reset();
     141            0 :     do_read();
     142            0 : }
     143              : 
     144              : template<class Stream>
     145              : void
     146            0 : http_session<Stream>::
     147              : do_read()
     148              : {
     149            0 :     pr_.start();
     150            0 :     sr_.reset();
     151            0 :     beast2::async_read(stream_, pr_,
     152            0 :         call_mf(&http_session::on_read, this));
     153            0 : }
     154              : 
     155              : template<class Stream>
     156              : void 
     157            0 : http_session<Stream>::
     158              : on_read(
     159              :     system::error_code ec,
     160              :     std::size_t bytes_transferred)
     161              : {
     162              :     (void)bytes_transferred;
     163              : 
     164            0 :     if(ec.failed())
     165            0 :         return do_fail("http_session::on_read", ec);
     166              : 
     167            0 :     LOG_TRC(this->sect_)(
     168              :         "{} http_session::on_read bytes={}",
     169              :         this->id(), bytes_transferred);
     170              : 
     171            0 :     BOOST_ASSERT(pr_.is_complete());
     172              : 
     173              :     //----------------------------------------
     174              :     //
     175              :     // set up Request and Response objects
     176              :     //
     177              : 
     178            0 :     preq_.reset(new Request(
     179            0 :         *this->pconfig_,
     180            0 :         pr_.get(),
     181            0 :         pr_));
     182              : 
     183            0 :     pres_.reset(new ResponseAsio<Stream>(
     184              :         stream_,
     185            0 :         res_,
     186            0 :         sr_));
     187            0 :     pres_->detach = detacher(*this);
     188              : 
     189              :     // copy version
     190            0 :     pres_->m.set_version(preq_->m.version());
     191              : 
     192              :     // copy keep-alive setting
     193            0 :     pres_->m.set_start_line(
     194            0 :         http_proto::status::ok, pr_.get().version());
     195            0 :     pres_->m.set_keep_alive(pr_.get().keep_alive());
     196              : 
     197              :     // parse the URL
     198              :     {
     199            0 :         auto rv = urls::parse_uri_reference(pr_.get().target());
     200            0 :         if(rv.has_value())
     201              :         {
     202            0 :             preq_->url = rv.value();
     203            0 :             preq_->base_path = "";
     204            0 :             preq_->path = std::string(rv->encoded_path());
     205              :         }
     206              :         else
     207              :         {
     208              :             // error parsing URL
     209            0 :             pres_->status(
     210              :                 http_proto::status::bad_request);
     211            0 :             pres_->set_body(
     212            0 :                 "Bad Request: " + rv.error().message());
     213            0 :             goto do_write;
     214              :         }
     215              :     }
     216              : 
     217              :     // invoke handlers for the route
     218            0 :     BOOST_ASSERT(! pwg_);
     219            0 :     ec = rr_.dispatch(
     220            0 :         preq_->m.method(),
     221            0 :         preq_->url,
     222            0 :         *preq_, *pres_, route_state_);
     223            0 :     if(ec == route::send)
     224            0 :         goto do_write;
     225              : 
     226            0 :     if(ec == route::next)
     227              :     {
     228              :         // unhandled
     229            0 :         pres_->status(http_proto::status::not_found);
     230            0 :         std::string s;
     231            0 :         format_to(s, "The requested URL {} was not found on this server.", preq_->url);
     232              :         //pres_->m.set_keep_alive(false); // VFALCO?
     233            0 :         pres_->set_body(s);
     234            0 :         goto do_write;
     235            0 :     }
     236              : 
     237            0 :     if(ec == route::detach)
     238              :     {
     239              :         // make sure they called detach()
     240            0 :         BOOST_ASSERT(pwg_);
     241            0 :         return;
     242              :     }
     243              : 
     244              :     // error message of last resort
     245              :     {
     246            0 :         BOOST_ASSERT(ec.failed());
     247            0 :         pres_->status(http_proto::status::internal_server_error);
     248            0 :         std::string s;
     249            0 :         format_to(s, "An internal server error occurred: {}", ec.message());
     250              :         //pres_->m.set_keep_alive(false); // VFALCO?
     251            0 :         pres_->set_body(s);
     252            0 :     }
     253              : 
     254            0 : do_write:
     255            0 :     if(sr_.is_done())
     256              :     {
     257              :         // happens when the handler sends the response
     258            0 :         return on_write(system::error_code(), 0);
     259              :     }
     260              : 
     261            0 :     beast2::async_write(stream_, sr_,
     262            0 :         call_mf(&http_session::on_write, this));
     263              : }
     264              : 
     265              : template<class Stream>
     266              : void 
     267            0 : http_session<Stream>::
     268              : on_write(
     269              :     system::error_code const& ec,
     270              :     std::size_t bytes_transferred)
     271              : {
     272              :     (void)bytes_transferred;
     273              : 
     274            0 :     if(ec.failed())
     275            0 :         return do_fail("http_session::on_write", ec);
     276              : 
     277            0 :     BOOST_ASSERT(sr_.is_done());
     278              : 
     279            0 :     LOG_TRC(this->sect_)(
     280              :         "{} http_session::on_write bytes={}",
     281              :         this->id(), bytes_transferred);
     282              : 
     283            0 :     if(res_.keep_alive())
     284            0 :         return do_read();
     285              : 
     286              :     // tidy up lingering objects
     287            0 :     pr_.reset();
     288            0 :     sr_.reset();
     289            0 :     res_.clear();
     290            0 :     preq_.reset();
     291            0 :     pres_.reset();
     292              : 
     293            0 :     close_({});
     294              : }
     295              : 
     296              : template<class Stream>
     297              : void 
     298            0 : http_session<Stream>::
     299              : do_fail(
     300              :     core::string_view s, system::error_code const& ec)
     301              : {
     302            0 :     LOG_TRC(this->sect_)("{}: {}", s, ec.message());
     303              : 
     304              :     // tidy up lingering objects
     305            0 :     pr_.reset();
     306            0 :     sr_.reset();
     307            0 :     res_.clear();
     308            0 :     preq_.reset();
     309            0 :     pres_.reset();
     310              : 
     311            0 :     close_(ec);
     312            0 : }
     313              : 
     314              : template<class Stream>
     315              : auto
     316            0 : http_session<Stream>::
     317              : do_detach() ->
     318              :     resumer
     319              : {
     320            0 :     BOOST_ASSERT(stream_.get_executor().running_in_this_thread());
     321              : 
     322              :     // can't call twice
     323            0 :     BOOST_ASSERT(! pwg_);
     324            0 :     pwg_.reset(new work_guard(stream_.get_executor()));
     325              : 
     326              :     // VFALCO cancel timer
     327              : 
     328            0 :     return resumer(*this);
     329              : }
     330              : 
     331              : template<class Stream>
     332              : void
     333            0 : http_session<Stream>::
     334              : do_resume(system::error_code const& ec)
     335              : {
     336            0 :     asio::dispatch(
     337            0 :         stream_.get_executor(),
     338            0 :         asio::prepend(call_mf(
     339              :             &http_session::do_resume2, this), ec));
     340            0 : }
     341              : 
     342              : template<class Stream>
     343              : void
     344            0 : http_session<Stream>::
     345              : do_resume2(system::error_code ec)
     346              : {
     347            0 :     BOOST_ASSERT(stream_.get_executor().running_in_this_thread());
     348              : 
     349            0 :     BOOST_ASSERT(pwg_.get() != nullptr);
     350            0 :     pwg_.reset();
     351              : 
     352              :     // invoke handlers for the route
     353            0 :     BOOST_ASSERT(! pwg_);
     354            0 :     ec = rr_.resume(*preq_, *pres_, ec, route_state_);
     355              : 
     356            0 :     if(ec == route::detach)
     357              :     {
     358              :         // make sure they called detach()
     359            0 :         BOOST_ASSERT(pwg_);
     360            0 :         return;
     361              :     }
     362              : 
     363            0 :     if(ec.failed())
     364              :     {
     365              :         // give a default error response?
     366              :     }
     367            0 :     beast2::async_write(stream_, sr_,
     368            0 :         call_mf(&http_session::on_write, this));
     369              : }
     370              : 
     371              : } // beast2
     372              : } // boost
     373              : 
     374              : #endif
        

Generated by: LCOV version 2.1