]>
git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/src/http/routes.cc
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 * Copyright 2015 Cloudius Systems
22 #include <seastar/http/routes.hh>
23 #include <seastar/http/reply.hh>
24 #include <seastar/http/request.hh>
25 #include <seastar/http/exception.hh>
26 #include <seastar/http/json_path.hh>
34 void verify_param(const http::request
& req
, const sstring
& param
) {
35 if (req
.get_query_param(param
) == "") {
36 throw missing_param_exception(param
);
39 routes::routes() : _general_handler([this](std::exception_ptr eptr
) mutable {
40 return exception_reply(eptr
);
44 for (int i
= 0; i
< NUM_OPERATION
; i
++) {
45 for (auto kv
: _map
[i
]) {
49 for (int i
= 0; i
< NUM_OPERATION
; i
++) {
50 for (auto r
: _rules
[i
]) {
57 std::unique_ptr
<http::reply
> routes::exception_reply(std::exception_ptr eptr
) {
58 auto rep
= std::make_unique
<http::reply
>();
60 // go over the register exception handler
61 // if one of them handle the exception, return.
62 for (auto e
: _exceptions
) {
64 return e
.second(eptr
);
66 // this is needed if there are more then one register exception handler
67 // so if the exception handler throw a new exception, they would
68 // get the new exception and not the original one.
69 eptr
= std::current_exception();
72 std::rethrow_exception(eptr
);
73 } catch (const base_exception
& e
) {
74 rep
->set_status(e
.status(), json_exception(e
).to_json());
76 rep
->set_status(http::reply::status_type::internal_server_error
,
77 json_exception(std::current_exception()).to_json());
84 future
<std::unique_ptr
<http::reply
> > routes::handle(const sstring
& path
, std::unique_ptr
<http::request
> req
, std::unique_ptr
<http::reply
> rep
) {
85 handler_base
* handler
= get_handler(str2type(req
->_method
),
86 normalize_url(path
), req
->param
);
87 if (handler
!= nullptr) {
89 for (auto& i
: handler
->_mandatory_param
) {
90 verify_param(*req
.get(), i
);
92 auto r
= handler
->handle(path
, std::move(req
), std::move(rep
));
93 return r
.handle_exception(_general_handler
);
94 } catch (const redirect_exception
& _e
) {
95 rep
.reset(new http::reply());
96 rep
->add_header("Location", _e
.url
).set_status(_e
.status()).done(
99 rep
= exception_reply(std::current_exception());
102 rep
.reset(new http::reply());
103 json_exception
ex(not_found_exception("Not found"));
104 rep
->set_status(http::reply::status_type::not_found
, ex
.to_json()).done(
107 return make_ready_future
<std::unique_ptr
<http::reply
>>(std::move(rep
));
110 sstring
routes::normalize_url(const sstring
& url
) {
111 if (url
.length() < 2 || url
.at(url
.length() - 1) != '/') {
114 return url
.substr(0, url
.length() - 1);
117 handler_base
* routes::get_handler(operation_type type
, const sstring
& url
,
118 parameters
& params
) {
119 handler_base
* handler
= get_exact_match(type
, url
);
120 if (handler
!= nullptr) {
124 for (auto&& rule
: _rules
[type
]) {
125 handler
= rule
.second
->get(url
, params
);
126 if (handler
!= nullptr) {
131 return _default_handler
;
134 routes
& routes::add(operation_type type
, const url
& url
,
135 handler_base
* handler
) {
136 match_rule
* rule
= new match_rule(handler
);
137 rule
->add_str(url
._path
);
138 if (url
._param
!= "") {
139 rule
->add_param(url
._param
, true);
141 return add(rule
, type
);
144 routes
& routes::add_default_handler(handler_base
* handler
) {
145 _default_handler
= handler
;
149 template <typename Map
, typename Key
>
150 static auto delete_rule_from(operation_type type
, Key
& key
, Map
& map
) {
151 auto& bucket
= map
[type
];
152 auto ret
= bucket
.find(key
);
153 using ret_type
= decltype(ret
->second
);
154 if (ret
!= bucket
.end()) {
155 ret_type v
= ret
->second
;
159 return static_cast<ret_type
>(nullptr);
162 handler_base
* routes::drop(operation_type type
, const sstring
& url
) {
163 return delete_rule_from(type
, url
, _map
);
166 routes
& routes::put(operation_type type
, const sstring
& url
, handler_base
* handler
) {
167 auto it
= _map
[type
].emplace(url
, handler
);
168 if (it
.second
== false) {
169 throw std::runtime_error(format("Handler for {} already exists.", url
));
174 match_rule
* routes::del_cookie(rule_cookie cookie
, operation_type type
) {
175 return delete_rule_from(type
, cookie
, _rules
);
178 void routes::add_alias(const path_description
& old_path
, const path_description
& new_path
) {
181 path
<< old_path
.path
;
182 for (const auto& p
: old_path
.params
) {
183 // the path_description path does not contains the path parameters
184 // so just add a fake parameter to the path for each of the parameters,
185 // and add the string for each fixed string part.
186 if (p
.type
== path_description::url_component_type::FIXED_STRING
) {
193 auto a
= get_handler(old_path
.operations
.method
, path
.str(), p
);
195 throw std::runtime_error("routes::add_alias path_description not found: " + old_path
.path
);
197 // if a handler is found then it must be a function_handler
198 new_path
.set(*this, new function_handler(*static_cast<function_handler
*>(a
)));
201 rule_registration::rule_registration(routes
& rs
, match_rule
& rule
, operation_type op
)
202 : _routes(rs
) , _op(op
)
203 , _cookie(_routes
.add_cookie(&rule
, _op
)) {}
205 rule_registration::~rule_registration() {
206 _routes
.del_cookie(_cookie
, _op
);
209 handler_registration::handler_registration(routes
& rs
, handler_base
& h
, const sstring
& url
, operation_type op
)
210 : _routes(rs
), _url(url
), _op(op
) {
211 _routes
.put(_op
, _url
, &h
);
214 handler_registration::~handler_registration() {
215 _routes
.drop(_op
, _url
);