Skip to content
Open

more #245

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .cursor/rules/doc.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
description: Documentation style conventions for code snippets, javadocs, and API documentation examples
globs:
alwaysApply: false
---

- `route_params` are named `rp`
60 changes: 51 additions & 9 deletions include/boost/http/server/cors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,73 @@
namespace boost {
namespace http {

/** Options for CORS middleware configuration.
*/
struct cors_options
{
/// Allowed origin, or "*" for any. Empty defaults to "*".
std::string origin;

/// Allowed HTTP methods. Empty defaults to common methods.
std::string methods;

/// Allowed request headers.
std::string allowedHeaders;

/// Response headers exposed to client.
std::string exposedHeaders;

/// Max age for preflight cache.
std::chrono::seconds max_age{ 0 };

/// Status code for preflight response.
status result = status::no_content;

/// If true, pass preflight to next handler.
bool preFlightContinue = false;

/// If true, allow credentials.
bool credentials = false;
};

class cors
/** CORS middleware for handling cross-origin requests.

This middleware handles Cross-Origin Resource Sharing
(CORS) by setting appropriate response headers and
handling preflight OPTIONS requests.

@par Example
@code
cors_options opts;
opts.origin = "*";
opts.methods = "GET,POST,PUT,DELETE";
opts.credentials = true;

router.use( cors( opts ) );
@endcode

@see cors_options
*/
class BOOST_HTTP_DECL cors
{
cors_options options_;

public:
BOOST_HTTP_DECL
explicit cors(
cors_options options = {}) noexcept;
/** Construct a CORS middleware.

BOOST_HTTP_DECL
route_result
operator()(route_params& p) const;
@param options Configuration options.
*/
explicit cors(cors_options options = {}) noexcept;

private:
cors_options options_;
/** Handle a request.

Sets CORS headers and handles preflight requests.

@param rp The route parameters.

@return A task that completes with the routing result.
*/
route_task operator()(route_params& rp) const;
};

} // http
Expand Down
48 changes: 48 additions & 0 deletions include/boost/http/server/encode_url.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// 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/http
//

#ifndef BOOST_HTTP_SERVER_ENCODE_URL_HPP
#define BOOST_HTTP_SERVER_ENCODE_URL_HPP

#include <boost/http/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>
#include <string>

namespace boost {
namespace http {

/** Percent-encode a URL for safe use in HTTP responses.

Encodes characters that are not safe in URLs using
percent-encoding (e.g. space becomes %20). This is
useful for encoding URLs that will be included in
Location headers or HTML links.

The following characters are NOT encoded:
- Unreserved: A-Z a-z 0-9 - _ . ~
- Reserved (allowed in URLs): ! # $ & ' ( ) * + , / : ; = ? @

@par Example
@code
std::string url = encode_url( "/path/to/file with spaces.txt" );
// url == "/path/to/file%20with%20spaces.txt"
@endcode

@param url The URL or URL component to encode.

@return A new string with unsafe characters percent-encoded.
*/
BOOST_HTTP_DECL
std::string
encode_url(core::string_view url);

} // http
} // boost

#endif
51 changes: 51 additions & 0 deletions include/boost/http/server/escape_html.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// 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/http
//

#ifndef BOOST_HTTP_SERVER_ESCAPE_HTML_HPP
#define BOOST_HTTP_SERVER_ESCAPE_HTML_HPP

#include <boost/http/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>
#include <string>

namespace boost {
namespace http {

/** Escape a string for safe inclusion in HTML.

Replaces characters that have special meaning in HTML
with their corresponding character entity references:

@li `&` becomes `&amp;`
@li `<` becomes `&lt;`
@li `>` becomes `&gt;`
@li `"` becomes `&quot;`
@li `'` becomes `&#39;`

This function is used to prevent XSS (Cross-Site Scripting)
attacks when embedding user input in HTML responses.

@par Example
@code
std::string safe = escape_html( "<script>alert('xss')</script>" );
// safe == "&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;"
@endcode

@param s The string to escape.

@return A new string with HTML special characters escaped.
*/
BOOST_HTTP_DECL
std::string
escape_html(core::string_view s);

} // http
} // boost

#endif
84 changes: 84 additions & 0 deletions include/boost/http/server/etag.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// 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/http
//

#ifndef BOOST_HTTP_SERVER_ETAG_HPP
#define BOOST_HTTP_SERVER_ETAG_HPP

#include <boost/http/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>
#include <cstdint>
#include <string>

namespace boost {
namespace http {

/** Options for ETag generation.
*/
struct etag_options
{
/// Generate a weak ETag (prefixed with W/).
bool weak = false;
};

/** Generate an ETag from content.

Creates an ETag by computing a hash of the provided
content. The resulting ETag can be used in HTTP
responses to enable caching.

@par Example
@code
std::string content = "Hello, World!";
std::string tag = etag( content );
// tag == "\"d-3/1gIbsr1bCvZ2KQgJ7DpTGR3YH\""
@endcode

@param body The content to hash.

@param opts Options controlling ETag generation.

@return An ETag string suitable for use in the ETag header.
*/
BOOST_HTTP_DECL
std::string
etag(core::string_view body, etag_options opts = {});

/** Generate an ETag from file metadata.

Creates an ETag based on a file's size and modification
time. This is more efficient than hashing file content
and is suitable for static file serving.

@par Example
@code
std::uint64_t size = 1234;
std::uint64_t mtime = 1704067200; // Unix timestamp
std::string tag = etag( size, mtime );
// tag == "\"4d2-65956a00\""
@endcode

@param size The file size in bytes.

@param mtime The file modification time (typically Unix timestamp).

@param opts Options controlling ETag generation.

@return An ETag string suitable for use in the ETag header.
*/
BOOST_HTTP_DECL
std::string
etag(
std::uint64_t size,
std::uint64_t mtime,
etag_options opts = {});

} // http
} // boost

#endif
65 changes: 65 additions & 0 deletions include/boost/http/server/fresh.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// 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/http
//

#ifndef BOOST_HTTP_SERVER_FRESH_HPP
#define BOOST_HTTP_SERVER_FRESH_HPP

#include <boost/http/detail/config.hpp>
#include <boost/http/request.hpp>
#include <boost/http/response.hpp>

namespace boost {
namespace http {

/** Check if a response is fresh for conditional GET.

Compares the request's conditional headers (`If-None-Match`
and `If-Modified-Since`) against the response's caching
headers (`ETag` and `Last-Modified`) to determine if the
cached response is still valid.

If this returns `true`, the server should respond with
304 Not Modified instead of sending the full response body.

@par Example
@code
// Prepare response headers
rp.res.set( field::etag, "\"abc123\"" );
rp.res.set( field::last_modified, "Wed, 21 Oct 2024 07:28:00 GMT" );

// Check freshness
if( is_fresh( rp.req, rp.res ) )
{
rp.status( status::not_modified );
co_return co_await rp.send( "" );
}

// Send full response
co_return co_await rp.send( content );
@endcode

@param req The HTTP request.

@param res The HTTP response (with ETag/Last-Modified set).

@return `true` if the response is fresh (304 should be sent),
`false` if the full response should be sent.

@see http::field::if_none_match, http::field::if_modified_since
*/
BOOST_HTTP_DECL
bool
is_fresh(
request const& req,
response const& res) noexcept;

} // http
} // boost

#endif
Loading
Loading