diff --git a/include/glaze/net/http_router.hpp b/include/glaze/net/http_router.hpp index ecd9c75978..0f244dfd8b 100644 --- a/include/glaze/net/http_router.hpp +++ b/include/glaze/net/http_router.hpp @@ -299,6 +299,7 @@ namespace glz */ void add(http_method method, std::string_view path, H handle, const route_spec& spec = {}) { +#if __cpp_exceptions try { // Install in the radix tree first. add_route can throw on conflict // (duplicate :param or *wildcard names at the same position); if it @@ -316,6 +317,16 @@ namespace glz std::fprintf(stderr, "Error adding route '%.*s': %s\n", static_cast(path.length()), path.data(), e.what()); } +#else + // Under -fno-exceptions add_route's misuse-detection throws are + // compiled to fprintf+abort (see the matching #else branches below), + // so we cannot observe the conflict here and simply propagate the + // install. Misconfigured routes still get reported on stderr. + add_route(method, path, handle, spec.constraints); + auto& entry = routes[std::string(path)][method]; + entry.handle = std::move(handle); + entry.spec = spec; +#endif } /** @@ -392,8 +403,14 @@ namespace glz current->parameter_child->full_path = current->full_path + "/" + segment; } else if (current->parameter_child->parameter_name != param_name) { - throw std::runtime_error("Route conflict: different parameter names at same position: :" + - current->parameter_child->parameter_name + " vs :" + param_name); + const auto msg = "Route conflict: different parameter names at same position: :" + + current->parameter_child->parameter_name + " vs :" + param_name; +#if __cpp_exceptions + throw std::runtime_error(msg); +#else + std::fprintf(stderr, "%s\n", msg.c_str()); + std::abort(); +#endif } current = current->parameter_child.get(); @@ -402,7 +419,13 @@ namespace glz std::string wildcard_name = segment.substr(1); if (i != segments.size() - 1) { - throw std::runtime_error("Wildcard must be the last segment in route: " + path_str); + const auto msg = "Wildcard must be the last segment in route: " + path_str; +#if __cpp_exceptions + throw std::runtime_error(msg); +#else + std::fprintf(stderr, "%s\n", msg.c_str()); + std::abort(); +#endif } if (!current->wildcard_child) { @@ -413,8 +436,14 @@ namespace glz current->wildcard_child->full_path = current->full_path + "/" + segment; } else if (current->wildcard_child->parameter_name != wildcard_name) { - throw std::runtime_error("Route conflict: different wildcard names at same position: *" + - current->wildcard_child->parameter_name + " vs *" + wildcard_name); + const auto msg = "Route conflict: different wildcard names at same position: *" + + current->wildcard_child->parameter_name + " vs *" + wildcard_name; +#if __cpp_exceptions + throw std::runtime_error(msg); +#else + std::fprintf(stderr, "%s\n", msg.c_str()); + std::abort(); +#endif } current = current->wildcard_child.get(); diff --git a/include/glaze/rpc/registry.hpp b/include/glaze/rpc/registry.hpp index c84f23c617..93b676fa76 100644 --- a/include/glaze/rpc/registry.hpp +++ b/include/glaze/rpc/registry.hpp @@ -328,6 +328,7 @@ namespace glz resp.reset(req_view); repe::state_view state{req_view, resp}; +#if __cpp_exceptions try { it->second(state); } @@ -335,6 +336,13 @@ namespace glz resp.reset(req_view); resp.set_error(error_code::parse_error, detail::build_registry_error(in.query, e.what())); } +#else + // Builds with -fno-exceptions cannot catch handler-thrown + // exceptions; user code in `it->second` is expected to be + // exception-free, matching the rest of glaze's no-exceptions + // contract (see #2265). + it->second(state); +#endif } } else { @@ -412,6 +420,7 @@ namespace glz // Zero-copy call: state_view references the parsed request and response builder directly repe::state_view state{req, resp}; +#if __cpp_exceptions try { it->second(state); } @@ -425,6 +434,10 @@ namespace glz resp.set_error(error_code::parse_error, "Unknown error"); return; } +#else + // -fno-exceptions: user handlers are expected to be exception-free (see #2265). + it->second(state); +#endif // For notifications, response buffer stays empty (no response sent) } @@ -529,6 +542,7 @@ namespace glz bool has_params = !req.params.str.empty() && req.params.str != "null"; jsonrpc::state state{req.id, response, is_notification, has_params, req.params.str}; +#if __cpp_exceptions try { it->second(std::move(state)); } @@ -540,6 +554,10 @@ namespace glz return R"({"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":)" + write_json(std::string_view{e.what()}).value_or("null") + R"(},"id":)" + id_json + "}"; } +#else + // -fno-exceptions: user handlers are expected to be exception-free (see #2265). + it->second(std::move(state)); +#endif if (is_notification) { return std::nullopt;