Skip to content

Commit ccfb859

Browse files
feat: helmet middleware and tests.
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
1 parent 08339fe commit ccfb859

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//
2+
// Copyright (c) 2025 Amlal El Mahrouss (amlal at nekernel dot org)
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/http_proto
8+
//
9+
10+
#ifndef BOOST_HTTP_PROTO_SERVER_HELMET_HPP
11+
#define BOOST_HTTP_PROTO_SERVER_HELMET_HPP
12+
13+
#include <boost/http_proto/detail/config.hpp>
14+
#include <boost/http_proto/server/route_handler.hpp>
15+
16+
namespace boost {
17+
namespace http_proto {
18+
19+
/// \brief Helmet middleware options.
20+
struct helmet_options
21+
{
22+
using helmet_pair = std::pair<std::string, std::vector<std::string>>;
23+
using helmet_map = std::vector<helmet_pair>;
24+
using cached_pair = std::pair<std::string, std::string>;
25+
using cached_vector = std::vector<cached_pair>;
26+
27+
/// \brief {key, enabled}
28+
/// \note i.e {bad-header, ""} <-- disabled
29+
struct helmet_headers_option {
30+
helmet_map headers = {
31+
{"Content-Security-Policy", {"default-src 'self'", "base-uri 'self'", "font-src 'self' https: data:", "form-action 'self'", "frame-ancestors 'self'",
32+
"img-src 'self' data:", "object-src 'none'", "script-src 'self'", "script-src-attr 'none'", "style-src 'self' https: 'unsafe-inline'", "upgrade-insecure-requests"}},
33+
{"Cross-Origin-Embedder-Policy", {"require-corp"}},
34+
{"Cross-Origin-Opener-Policy", {"same-origin"}},
35+
{"Cross-Origin-Resource-Policy", {"same-origin"}},
36+
{"X-DNS-Prefetch-Control", {"off"}},
37+
{"Expect-CT", {"max-age=86400, enforce"}},
38+
{"X-Frame-Options", {"SAMEORIGIN"}},
39+
{"X-Powered-By", {""}}, // Remove this header
40+
{"Strict-Transport-Security", {"max-age=15552000", "includeSubDomains"}},
41+
{"X-Download-Options", {"noopen"}},
42+
{"X-Content-Type-Options", {"nosniff"}},
43+
{"Origin-Agent-Cluster", {"?1"}},
44+
{"X-Permitted-Cross-Domain-Policies", {"none"}},
45+
{"Referrer-Policy", {"no-referrer"}},
46+
{"X-XSS-Protection", {"0"}} // Disabled as modern browsers have better protections
47+
};
48+
49+
cached_vector cachedHeaders;
50+
} requestHeaders;
51+
};
52+
53+
/// \brief Middleware inspired by express.js concept of helmets.
54+
class helmet
55+
{
56+
public:
57+
BOOST_HTTP_PROTO_DECL
58+
explicit helmet(
59+
helmet_options options = {}) noexcept;
60+
61+
BOOST_HTTP_PROTO_DECL
62+
route_result
63+
operator()(route_params& p) const;
64+
65+
private:
66+
helmet_options options_;
67+
};
68+
}
69+
70+
}
71+
#endif

src/server/helmet.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// Copyright (c) 2025 Amlal El Mahrouss (amlal at nekernel dot org)
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/http_proto
8+
//
9+
10+
#include <boost/http_proto/server/helmet.hpp>
11+
12+
namespace boost {
13+
namespace http_proto {
14+
15+
namespace detail {
16+
auto setHeaderValues(const std::vector<std::string>& fields_value) -> std::string {
17+
if (fields_value.empty())
18+
detail::throw_invalid_argument();
19+
20+
std::string res_value;
21+
bool first = false;
22+
23+
for (const auto& value: fields_value)
24+
{
25+
if (first) res_value += "; ";
26+
res_value += value;
27+
first = true;
28+
}
29+
30+
return res_value;
31+
}
32+
}
33+
34+
helmet::
35+
helmet(
36+
helmet_options options) noexcept
37+
: options_(std::move(options))
38+
{
39+
for (auto& hdr : options_.requestHeaders.headers)
40+
{
41+
if (hdr.second.empty())
42+
detail::throw_length_error();
43+
44+
options_.requestHeaders.cachedHeaders.push_back(std::make_pair(hdr.first, detail::setHeaderValues(hdr.second)));
45+
}
46+
}
47+
48+
route_result
49+
helmet::
50+
operator()(
51+
route_params& p) const
52+
{
53+
for (const auto& hdr : options_.requestHeaders.cachedHeaders)
54+
{
55+
p.res.set(hdr.first, hdr.second);
56+
}
57+
58+
return route::next;
59+
}
60+
61+
}
62+
}

test/unit/server/helmet.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// Copyright (c) 2025 Amlal El Mahrouss (amlal at nekernel dot org)
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/http_proto
8+
//
9+
10+
#include <boost/http_proto/server/helmet.hpp>
11+
#include "test_suite.hpp"
12+
13+
namespace boost {
14+
namespace http_proto {
15+
16+
struct helmet_test
17+
{
18+
void run() {}
19+
};
20+
21+
TEST_SUITE(
22+
helmet_test,
23+
"boost.http_proto.server.helmet");
24+
}
25+
26+
}

0 commit comments

Comments
 (0)