diff --git a/example/server/main.cpp b/example/server/main.cpp index 0f87bb5..9713599 100644 --- a/example/server/main.cpp +++ b/example/server/main.cpp @@ -75,9 +75,8 @@ int server_main( int argc, char* argv[] ) //srv.wwwroot.use(post_work()); srv.wwwroot.use( http_proto::cors(), - []( http_proto::Request& req, - http_proto::Response& res) -> - http_proto::route_result + []( http_proto::route_params&) -> + http_proto::route_result { return http_proto::route::next; }); diff --git a/example/server/post_work.cpp b/example/server/post_work.cpp index 5420aad..db9a513 100644 --- a/example/server/post_work.cpp +++ b/example/server/post_work.cpp @@ -63,10 +63,9 @@ struct task http_proto::route_result post_work:: operator()( - http_proto::Request&, - http_proto::Response& res) const + http_proto::route_params& p) const { - return res.post(task()); + return p.post(task()); } } // beast2 diff --git a/example/server/post_work.hpp b/example/server/post_work.hpp index ca097e8..b75c398 100644 --- a/example/server/post_work.hpp +++ b/example/server/post_work.hpp @@ -20,8 +20,7 @@ struct post_work { system::error_code operator()( - http_proto::Request&, - http_proto::Response& res) const; + http_proto::route_params&) const; }; } // beast2 diff --git a/example/server/serve_detached.hpp b/example/server/serve_detached.hpp index d11dae0..bd1c849 100644 --- a/example/server/serve_detached.hpp +++ b/example/server/serve_detached.hpp @@ -39,10 +39,9 @@ class serve_detached system::error_code operator()( - http_proto::Request&, - http_proto::Response& res) const + http_proto::route_params& p) const { - return res.detach( + return p.detach( [&](http_proto::resumer resume) { asio::post(*tp_, @@ -50,8 +49,8 @@ class serve_detached { // Simulate some asynchronous work std::this_thread::sleep_for(std::chrono::seconds(1)); - res.status(http_proto::status::ok); - res.set_body("Hello from serve_detached!\n"); + p.status(http_proto::status::ok); + p.set_body("Hello from serve_detached!\n"); resume(http_proto::route::send); // resume( res.send("Hello from serve_detached!\n") ); }); diff --git a/example/server/serve_log_admin.cpp b/example/server/serve_log_admin.cpp index 93ab826..32a15f5 100644 --- a/example/server/serve_log_admin.cpp +++ b/example/server/serve_log_admin.cpp @@ -30,8 +30,7 @@ class serve_log_page system::error_code operator()( - http_proto::Request&, - http_proto::Response& res) const + http_proto::route_params& p) const { auto const v = ls_.get_sections(); std::string s; @@ -72,9 +71,9 @@ class serve_log_page format_to(s, "\n"); format_to(s, "\n"); - res.status(http_proto::status::ok); - res.message.set(http_proto::field::content_type, "text/html; charset=UTF-8"); - res.set_body(std::move(s)); + p.status(http_proto::status::ok); + p.res.set(http_proto::field::content_type, "text/html; charset=UTF-8"); + p.set_body(std::move(s)); return http_proto::route::send; } @@ -97,12 +96,11 @@ class handle_submit system::error_code operator()( - http_proto::Request&, - http_proto::Response& res) const + http_proto::route_params& p) const { - res.status(http_proto::status::ok); - res.message.set(http_proto::field::content_type, "plain/text; charset=UTF-8"); - res.set_body("submit"); + p.status(http_proto::status::ok); + p.res.set(http_proto::field::content_type, "plain/text; charset=UTF-8"); + p.set_body("submit"); return http_proto::route::send; } diff --git a/include/boost/beast2/server/http_stream.hpp b/include/boost/beast2/server/http_stream.hpp index 349668f..1d813c1 100644 --- a/include/boost/beast2/server/http_stream.hpp +++ b/include/boost/beast2/server/http_stream.hpp @@ -121,8 +121,7 @@ class http_stream using work_guard = asio::executor_work_guard().get_executor())>; std::unique_ptr pwg_; - http_proto::Request req_; - ResponseAsio res_; + asio_route_params p_; }; //------------------------------------------------ @@ -173,12 +172,12 @@ http_stream( , stream_(stream) , routes_(std::move(routes)) , close_(close) - , res_(stream_) + , p_(stream_) { - req_.parser = http_proto::request_parser(app); + p_.parser = http_proto::request_parser(app); - res_.serializer = http_proto::serializer(app); - res_.detach = http_proto::detacher(*this); + p_.serializer = http_proto::serializer(app); + p_.detach = http_proto::detacher(*this); } // called to start a new HTTP session. @@ -191,8 +190,8 @@ on_stream_begin( { pconfig_ = &config; - req_.parser.reset(); - res_.data.clear(); + p_.parser.reset(); + p_.session_data.clear(); do_read(); } @@ -202,9 +201,9 @@ void http_stream:: do_read() { - req_.parser.start(); + p_.parser.start(); - beast2::async_read(stream_, req_.parser, + beast2::async_read(stream_, p_.parser, call_mf(&http_stream::on_read, this)); } @@ -225,7 +224,7 @@ on_read( "{} http_stream::on_read bytes={}", this->id(), bytes_transferred); - BOOST_ASSERT(req_.parser.is_complete()); + BOOST_ASSERT(p_.parser.is_complete()); on_headers(); } @@ -237,27 +236,26 @@ http_stream:: on_headers() { // set up Request and Response objects - res_.serializer.reset(); // VFALCO HACK for now we make a copy of the message - req_.message = req_.parser.get(); - //res_.message.set_version(req_.message.version()); - res_.message.set_start_line( // VFALCO WTF - http_proto::status::ok, req_.message.version()); - res_.message.set_keep_alive(req_.message.keep_alive()); - res_.data.clear(); + p_.req = p_.parser.get(); + p_.route_data.clear(); + p_.res.set_start_line( // VFALCO WTF + http_proto::status::ok, p_.req.version()); + p_.res.set_keep_alive(p_.req.keep_alive()); + p_.serializer.reset(); // parse the URL { - auto rv = urls::parse_uri_reference(req_.message.target()); + auto rv = urls::parse_uri_reference(p_.req.target()); if(rv.has_error()) { // error parsing URL - res_.status(http_proto::status::bad_request); - res_.set_body("Bad Request: " + rv.error().message()); + p_.status(http_proto::status::bad_request); + p_.set_body("Bad Request: " + rv.error().message()); return do_respond(rv.error()); } - req_.url = rv.value(); + p_.url = rv.value(); } // invoke handlers for the route @@ -275,11 +273,11 @@ do_dispatch( { BOOST_ASSERT(! pwg_); // can't be detached rv = routes_.dispatch( - req_.message.method(), req_.url, req_, res_); + p_.req.method(), p_.url, p_); } else { - rv = routes_.resume(req_, res_, rv); + rv = routes_.resume(p_, rv); } do_respond(rv); @@ -303,13 +301,13 @@ do_respond( { // VFALCO what if the connection was closed or keep-alive=false? // handler sendt the response? - BOOST_ASSERT(res_.serializer.is_done()); + BOOST_ASSERT(p_.serializer.is_done()); return on_write(system::error_code(), 0); } if(rv == http_proto::route::detach) { - // didn't call res.detach()? + // didn't call detach()? if(! pwg_) detail::throw_logic_error(); return; @@ -319,20 +317,19 @@ do_respond( { // unhandled request auto const status = http_proto::status::not_found; - res_.status(status); - //res_.message.set_keep_alive(false); // VFALCO? - res_.set_body(http_proto::to_string(status)); + p_.status(status); + p_.set_body(http_proto::to_string(status)); } else if(rv != http_proto::route::send) { // error message of last resort BOOST_ASSERT(rv.failed()); BOOST_ASSERT(! http_proto::is_route_result(rv)); - res_.status(http_proto::status::internal_server_error); + p_.status(http_proto::status::internal_server_error); std::string s; format_to(s, "An internal server error occurred: {}", rv.message()); - res_.message.set_keep_alive(false); // VFALCO? - res_.set_body(s); + p_.res.set_keep_alive(false); // VFALCO? + p_.set_body(s); } do_write(); @@ -344,8 +341,8 @@ void http_stream:: do_write() { - BOOST_ASSERT(! res_.serializer.is_done()); - beast2::async_write(stream_, res_.serializer, + BOOST_ASSERT(! p_.serializer.is_done()); + beast2::async_write(stream_, p_.serializer, call_mf(&http_stream::on_write, this)); } @@ -362,13 +359,13 @@ on_write( if(ec.failed()) return do_fail("http_stream::on_write", ec); - BOOST_ASSERT(res_.serializer.is_done()); + BOOST_ASSERT(p_.serializer.is_done()); LOG_TRC(this->sect_)( "{} http_stream::on_write bytes={}", this->id(), bytes_transferred); - if(res_.message.keep_alive()) + if(p_.res.keep_alive()) return do_read(); do_close(); @@ -419,8 +416,8 @@ do_fail( LOG_TRC(this->sect_)("{}: {}", s, ec.message()); // tidy up lingering objects - req_.parser.reset(); - res_.serializer.reset(); + p_.parser.reset(); + p_.serializer.reset(); close_(ec); } @@ -441,9 +438,9 @@ void http_stream:: clear() noexcept { - req_.parser.reset(); - res_.serializer.reset(); - res_.message.clear(); + p_.parser.reset(); + p_.serializer.reset(); + p_.res.clear(); } } // beast2 diff --git a/include/boost/beast2/server/route_handler_asio.hpp b/include/boost/beast2/server/route_handler_asio.hpp index c266b5a..c00a9db 100644 --- a/include/boost/beast2/server/route_handler_asio.hpp +++ b/include/boost/beast2/server/route_handler_asio.hpp @@ -18,10 +18,11 @@ namespace boost { namespace beast2 { -/** Response object for Asio HTTP route handlers +/** Route parameters object for Asio HTTP route handlers */ template -class ResponseAsio : public http_proto::Response +class asio_route_params + : public http_proto::route_params { public: using stream_type = typename std::decay::type; @@ -30,7 +31,7 @@ class ResponseAsio : public http_proto::Response template explicit - ResponseAsio( + asio_route_params( Args&&... args) : stream(std::forward(args)...) { @@ -44,7 +45,7 @@ class ResponseAsio : public http_proto::Response template void -ResponseAsio:: +asio_route_params:: do_post() { asio::post( diff --git a/include/boost/beast2/server/router.hpp b/include/boost/beast2/server/router.hpp index 3e2c32a..c967dfb 100644 --- a/include/boost/beast2/server/router.hpp +++ b/include/boost/beast2/server/router.hpp @@ -19,7 +19,7 @@ namespace beast2 { /** The sans-IO router type */ -using router = http_proto::basic_router; +using router = http_proto::basic_router; } // beast2 } // boost diff --git a/include/boost/beast2/server/router_asio.hpp b/include/boost/beast2/server/router_asio.hpp index e1efcd9..8860a8a 100644 --- a/include/boost/beast2/server/router_asio.hpp +++ b/include/boost/beast2/server/router_asio.hpp @@ -21,7 +21,7 @@ namespace beast2 { */ template using router_asio = http_proto::basic_router< - http_proto::Request, ResponseAsio>; + asio_route_params>; } // beast2 } // boost diff --git a/include/boost/beast2/server/serve_redirect.hpp b/include/boost/beast2/server/serve_redirect.hpp index 3623078..adc105a 100644 --- a/include/boost/beast2/server/serve_redirect.hpp +++ b/include/boost/beast2/server/serve_redirect.hpp @@ -21,8 +21,7 @@ struct serve_redirect BOOST_BEAST2_DECL http_proto::route_result operator()( - http_proto::Request&, - http_proto::Response&) const; + http_proto::route_params&) const; }; } // beast2 diff --git a/include/boost/beast2/server/serve_static.hpp b/include/boost/beast2/server/serve_static.hpp index a4376d6..fb9d5d8 100644 --- a/include/boost/beast2/server/serve_static.hpp +++ b/include/boost/beast2/server/serve_static.hpp @@ -165,8 +165,7 @@ struct serve_static */ BOOST_BEAST2_DECL system::error_code operator()( - http_proto::Request&, - http_proto::Response&) const; + http_proto::route_params&) const; private: struct impl; diff --git a/src/server/route_rule.hpp b/src/server/route_rule.hpp index 98cc1ad..3c5e2f0 100644 --- a/src/server/route_rule.hpp +++ b/src/server/route_rule.hpp @@ -262,6 +262,7 @@ struct route_seg core::string_view constraint; char ptype = 0; // ':' | '?' | NULL char modifier = 0; + char term; // param terminator or NULL }; struct param_segment_rule_t @@ -343,6 +344,15 @@ struct path_rule_t return rv1.error(); route_seg rs = rv1.value(); rs.prefix = { it2, it1 }; + if(it != end) + { + if( *it == ':' || + *it == '*') + { + // can't have ":id:id" + return grammar::error::syntax; + } + } rv.segs.push_back(rs); it1 = it; continue; diff --git a/src/server/serve_redirect.cpp b/src/server/serve_redirect.cpp index 8030663..8d61994 100644 --- a/src/server/serve_redirect.cpp +++ b/src/server/serve_redirect.cpp @@ -106,18 +106,17 @@ prepare_error( auto serve_redirect:: operator()( - http_proto::Request& req, - http_proto::Response& res) const -> + http_proto::route_params& p) const -> http_proto::route_result { std::string body; - prepare_error(res.message, body, - http_proto::status::moved_permanently, req.message); - urls::url u1(req.message.target()); + prepare_error(p.res, body, + http_proto::status::moved_permanently, p.req); + urls::url u1(p.req.target()); u1.set_scheme_id(urls::scheme::https); u1.set_host_address("localhost"); // VFALCO WTF IS THIS! - res.message.append(http_proto::field::location, u1.buffer()); - res.serializer.start(res.message, + p.res.append(http_proto::field::location, u1.buffer()); + p.serializer.start(p.res, http_proto::string_body( std::move(body))); return http_proto::route::send; } diff --git a/src/server/serve_static.cpp b/src/server/serve_static.cpp index 4d6ca1c..2f8d67c 100644 --- a/src/server/serve_static.cpp +++ b/src/server/serve_static.cpp @@ -170,28 +170,27 @@ serve_static( auto serve_static:: operator()( - http_proto::Request& req, - http_proto::Response& res) const -> + http_proto::route_params& p) const -> http_proto::route_result { // Allow: GET, HEAD - if( req.message.method() != http_proto::method::get && - req.message.method() != http_proto::method::head) + if( p.req.method() != http_proto::method::get && + p.req.method() != http_proto::method::head) { if(impl_->opt.fallthrough) return http_proto::route::next; - res.message.set_status( + p.res.set_status( http_proto::status::method_not_allowed); - res.message.set(http_proto::field::allow, "GET, HEAD"); - res.set_body(""); + p.res.set(http_proto::field::allow, "GET, HEAD"); + p.set_body(""); return http_proto::route::send; } // Build the path to the requested file std::string path; - path_cat(path, impl_->path, req.path); - if(req.parser.get().target().back() == '/') + path_cat(path, impl_->path, p.path); + if(p.parser.get().target().back() == '/') { path.push_back('/'); path.append("index.html"); @@ -206,18 +205,18 @@ operator()( size = f.size(ec); if(! ec.failed()) { - res.message.set_start_line( + p.res.set_start_line( http_proto::status::ok, - req.message.version()); - res.message.set_payload_size(size); + p.req.version()); + p.res.set_payload_size(size); auto mt = mime_type(get_extension(path)); - res.message.append( + p.res.append( http_proto::field::content_type, mt); // send file - res.serializer.start( - res.message, std::move(f), size); + p.serializer.start( + p.res, std::move(f), size); return http_proto::route::send; } diff --git a/test/unit/server/route_handler_asio.cpp b/test/unit/server/route_handler_asio.cpp index ad1f0ed..1f4c21d 100644 --- a/test/unit/server/route_handler_asio.cpp +++ b/test/unit/server/route_handler_asio.cpp @@ -31,18 +31,17 @@ struct route_handler_asio_test }; using test_router = http_proto::basic_router< - http_proto::Request, ResponseAsio>; + asio_route_params>; void check( test_router& r, core::string_view url, http_proto::route_result rv0 = http_proto::route::send) { - http_proto::Request req; - ResponseAsio res; + asio_route_params req; auto rv = r.dispatch( http_proto::method::get, - urls::url_view(url), req, res); + urls::url_view(url), req); if(BOOST_TEST_EQ(rv.message(), rv0.message())) BOOST_TEST(rv == rv0); } @@ -52,8 +51,7 @@ struct route_handler_asio_test template http_proto::route_result operator()( - http_proto::Request&, - ResponseAsio&) const + asio_route_params&) const { BOOST_TEST(true); return http_proto::route::send;