diff --git a/example/server/main.cpp b/example/server/main.cpp index 794c71f..501cb8e 100644 --- a/example/server/main.cpp +++ b/example/server/main.cpp @@ -14,12 +14,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -187,7 +189,32 @@ int server_main( int argc, char* argv[] ) } return http::route::next; }); - srv.wwwroot.use("/", serve_static( argv[3] )); + + http::helmet_options options; + + options.set(http::x_download_options(http::helmet_download_type::noopen)); + options.set(http::x_frame_origin(http::helmet_origin_type::deny)); + + http::helmet::csp_policy sp; + + sp.allow("script-src", http::csp_type::self) + .allow("object-src", http::csp_type::none) + .allow("style-src", "https://example.com/index.css") + .allow("style-src", "https://example.com/foo.css") + .allow("style-src", http::csp_type::self); + + options.set(http::content_security_policy(sp)); + + srv.wwwroot.use( + http::helmet(options), + [] ( http::route_params& ) -> + http::route_result + { + return http::route::next; + }); + + srv.wwwroot.use("/", serve_not_found( argv[3] )); + srv.wwwroot.use("/", serve_static( argv[3] )); app.start(); srv.attach(); diff --git a/include/boost/beast2/server/serve_not_found.hpp b/include/boost/beast2/server/serve_not_found.hpp new file mode 100644 index 0000000..c98556b --- /dev/null +++ b/include/boost/beast2/server/serve_not_found.hpp @@ -0,0 +1,44 @@ +// +// Copyright (c) 2025 Amlal El Mahrouss (amlal at nekernel dot org) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/beast2 +// + +#ifndef BOOST_BEAST2_SERVER_SERVE_REDIRECT_HPP +#define BOOST_BEAST2_SERVER_SERVE_REDIRECT_HPP + +#include +#include + +namespace boost { +namespace beast2 { + +struct serve_not_found +{ +private: + struct serve_impl; + serve_impl* impl_{}; + +public: + serve_not_found(const core::string_view&); + ~serve_not_found(); + + serve_not_found& operator=(serve_not_found&&) noexcept; + serve_not_found(serve_not_found&&) noexcept; + + /** Serves a 404.html when a resource isn't found. + @note if no 404.html is found the route will be ignored. + */ + BOOST_BEAST2_DECL + http::route_result + operator()( + http::route_params&) const; +}; + +} // beast2 +} // boost + +#endif diff --git a/src/server/serve_not_found.cpp b/src/server/serve_not_found.cpp new file mode 100644 index 0000000..fbb1ebe --- /dev/null +++ b/src/server/serve_not_found.cpp @@ -0,0 +1,99 @@ +// +// Copyright (c) 2025 Amlal El Mahrouss (amlal at nekernel dot org) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/beast2 +// + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace beast2 { + + struct serve_not_found::serve_impl + { + std::string path_; + }; + + serve_not_found::serve_not_found(const core::string_view& path) + : impl_(new serve_impl()) + { + impl_->path_ = path; + } + + serve_not_found::~serve_not_found() + { + if (impl_) + delete impl_; + + impl_ = nullptr; + } + + serve_not_found& serve_not_found::operator=(serve_not_found&& other) noexcept + { + delete impl_; + impl_ = other.impl_; + other.impl_ = nullptr; + + return *this; + } + + serve_not_found:: + serve_not_found(serve_not_found&& other) noexcept + : impl_(other.impl_) + { + other.impl_ = nullptr; + } + + http::route_result + serve_not_found::operator()( + http::route_params& p) const + { + std::string path{impl_->path_}; + path += p.path; + + system::error_code ec{}; + + capy::file f; + + f.open(path.c_str(), capy::file_mode::scan, ec); + + if (!ec.failed()) + return http::route::next; + + p.res.set_start_line(http::status::not_found); + p.res.append(http::field::content_type, "text/html"); + + std::string body; + std::ostringstream ss; + + ss << + "" + "" + "NOT FOUND" + "\n" + "" + "

NOT FOUND

" + "

THE FOLLOWING RESOURCE: " << p.path << ", WAS NOT FOUND.

" + "" + "" + ; + + body = ss.str(); + + // send 404 template to client + p.serializer.start(p.res, + http::string_body( std::move(body))); + + return http::route::send; + } + +} +} \ No newline at end of file