-
Notifications
You must be signed in to change notification settings - Fork 98
Add options support for cors #599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c3d8fe2
95919c6
fe1f410
d4edd47
744c577
19beae1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -17,8 +17,10 @@ | |||||
|
|
||||||
| #pragma once | ||||||
|
|
||||||
| #include <boost/algorithm/string.hpp> | ||||||
| #include <boost/beast/http/verb.hpp> | ||||||
|
|
||||||
| #include <iostream> | ||||||
| #include <list> | ||||||
| #include <optional> | ||||||
| #include <regex> | ||||||
|
|
@@ -84,7 +86,8 @@ namespace mtconnect::sink::rest_sink { | |||||
| m_pattern(pattern), | ||||||
| m_command(request), | ||||||
| m_function(function), | ||||||
| m_swagger(swagger) | ||||||
| m_swagger(swagger), | ||||||
| m_catchAll(true) | ||||||
| {} | ||||||
|
|
||||||
| /// @brief Added summary and description to the routing | ||||||
|
|
@@ -295,6 +298,15 @@ namespace mtconnect::sink::rest_sink { | |||||
| return true; | ||||||
| } | ||||||
|
|
||||||
| /// @brief check if the routing's path pattern matches a given path (ignoring verb) | ||||||
| /// @param[in] path the request path to test | ||||||
| /// @return `true` if the path matches this routing's pattern | ||||||
| bool matchesPath(const std::string &path) const | ||||||
| { | ||||||
| std::smatch m; | ||||||
| return std::regex_match(path, m, m_pattern); | ||||||
| } | ||||||
|
|
||||||
| /// @brief check if this is related to a swagger API | ||||||
| /// @returns `true` if related to swagger | ||||||
| auto isSwagger() const { return m_swagger; } | ||||||
|
|
@@ -304,6 +316,10 @@ namespace mtconnect::sink::rest_sink { | |||||
| /// @brief Get the routing `verb` | ||||||
| const auto &getVerb() const { return m_verb; } | ||||||
|
|
||||||
| /// @brief Check if the route is a catch-all (every path segment is a parameter) | ||||||
| /// @returns `true` if all path segments are parameters (e.g. `/{device}`) | ||||||
| auto isCatchAll() const { return m_catchAll; } | ||||||
|
|
||||||
| /// @brief Get the optional command associated with the routing | ||||||
| /// @returns optional routing | ||||||
| const auto &getCommand() const { return m_command; } | ||||||
|
|
@@ -319,21 +335,60 @@ namespace mtconnect::sink::rest_sink { | |||||
| protected: | ||||||
| void pathParameters(std::string s) | ||||||
| { | ||||||
| std::regex reg("\\{([^}]+)\\}"); | ||||||
| std::smatch match; | ||||||
| std::stringstream pat; | ||||||
|
|
||||||
| while (regex_search(s, match, reg)) | ||||||
| using namespace boost::algorithm; | ||||||
| using SplitList = std::list<boost::iterator_range<std::string::iterator>>; | ||||||
|
|
||||||
| SplitList parts; | ||||||
| auto pos = s.find_first_not_of('/'); | ||||||
| if (pos != std::string::npos) | ||||||
| { | ||||||
| pat << match.prefix() << "([^/]+)"; | ||||||
| m_pathParameters.emplace_back(match[1]); | ||||||
| s = match.suffix().str(); | ||||||
| auto range = boost::make_iterator_range(s.begin() + pos, s.end()); | ||||||
| split(parts, range, [](char c) { return c == '/'; }); | ||||||
|
||||||
| split(parts, range, [](char c) { return c == '/'; }); | |
| split(parts, range, boost::is_any_of("/")); |
Copilot
AI
Mar 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::string_view(start, openBrace) / std::string_view(openBrace + 1, closeBrace) / etc. are constructed from iterators, but std::string_view does not have iterator-pair constructors. This will not compile; create the view from a pointer+length (e.g. &*it + std::distance) or append via pat.write() / std::string(start, openBrace) instead.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,13 +19,15 @@ | |
|
|
||
| #include <boost/algorithm/string.hpp> | ||
| #include <boost/algorithm/string/case_conv.hpp> | ||
| #include <boost/algorithm/string/join.hpp> | ||
| #include <boost/asio.hpp> | ||
| #include <boost/asio/coroutine.hpp> | ||
| #include <boost/beast.hpp> | ||
| #include <boost/beast/core.hpp> | ||
| #include <boost/beast/http.hpp> | ||
| #include <boost/beast/ssl.hpp> | ||
| #include <boost/beast/version.hpp> | ||
| #include <boost/range/adaptor/transformed.hpp> | ||
| #include <boost/tokenizer.hpp> | ||
|
|
||
| #include <thread> | ||
|
|
@@ -413,4 +415,44 @@ namespace mtconnect::sink::rest_sink { | |
| // addRouting({boost::beast::http::verb::get, "/swagger.yaml", handler, true}); | ||
| } | ||
|
|
||
| bool Server::handleOptionsRequest(SessionPtr session, const RequestPtr request) | ||
| { | ||
| using namespace boost; | ||
| using namespace adaptors; | ||
| set<http::verb> specificVerbs; | ||
| set<http::verb> catchAllVerbs; | ||
| for (const auto &r : m_routings) | ||
| { | ||
| if (!r.isSwagger() && r.matchesPath(request->m_path)) | ||
| { | ||
| if (r.isCatchAll()) | ||
| catchAllVerbs.insert(r.getVerb()); | ||
| else | ||
| specificVerbs.insert(r.getVerb()); | ||
| } | ||
| } | ||
|
|
||
| // If any specific route matched, use only those; otherwise fall back to catch-alls | ||
| auto &verbs = specificVerbs.empty() ? catchAllVerbs : specificVerbs; | ||
|
|
||
| // OPTIONS is always allowed | ||
| verbs.insert(http::verb::options); | ||
|
|
||
| // Build the Allow / Access-Control-Allow-Methods header value | ||
| string methods = algorithm::join( | ||
| verbs | transformed([](http::verb v) { return string(http::to_string(v)); }), ", "); | ||
|
|
||
| auto response = std::make_unique<Response>(status::no_content, "", "text/plain"); | ||
| response->m_close = false; | ||
| response->m_fields.emplace_back("Allow", methods); | ||
| response->m_fields.emplace_back("Access-Control-Allow-Methods", methods); | ||
| response->m_fields.emplace_back("Access-Control-Allow-Headers", | ||
| "Content-Type, Accept, Accept-Encoding"); | ||
| response->m_fields.emplace_back("Access-Control-Max-Age", "86400"); | ||
|
|
||
| session->writeResponse(std::move(response)); | ||
|
|
||
| return true; | ||
| } | ||
|
Comment on lines
+422
to
+456
|
||
|
|
||
| } // namespace mtconnect::sink::rest_sink | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#include <iostream>appears unused in this header. Consider removing it to avoid unnecessary recompiles and header bloat.