]>
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/exception.hh>
25 #include <seastar/http/json_path.hh>
33 void verify_param(const request
& req
, const sstring
& param
) {
34 if (req
.get_query_param(param
) == "") {
35 throw missing_param_exception(param
);
38 routes::routes() : _general_handler([this](std::exception_ptr eptr
) mutable {
39 return exception_reply(eptr
);
43 for (int i
= 0; i
< NUM_OPERATION
; i
++) {
44 for (auto kv
: _map
[i
]) {
48 for (int i
= 0; i
< NUM_OPERATION
; i
++) {
49 for (auto r
: _rules
[i
]) {
56 std::unique_ptr
<reply
> routes::exception_reply(std::exception_ptr eptr
) {
57 auto rep
= std::make_unique
<reply
>();
59 // go over the register exception handler
60 // if one of them handle the exception, return.
61 for (auto e
: _exceptions
) {
63 return e
.second(eptr
);
65 // this is needed if there are more then one register exception handler
66 // so if the exception handler throw a new exception, they would
67 // get the new exception and not the original one.
68 eptr
= std::current_exception();
71 std::rethrow_exception(eptr
);
72 } catch (const base_exception
& e
) {
73 rep
->set_status(e
.status(), json_exception(e
).to_json());
75 rep
->set_status(reply::status_type::internal_server_error
,
76 json_exception(std::current_exception()).to_json());
83 future
<std::unique_ptr
<reply
> > routes::handle(const sstring
& path
, std::unique_ptr
<request
> req
, std::unique_ptr
<reply
> rep
) {
84 handler_base
* handler
= get_handler(str2type(req
->_method
),
85 normalize_url(path
), req
->param
);
86 if (handler
!= nullptr) {
88 for (auto& i
: handler
->_mandatory_param
) {
89 verify_param(*req
.get(), i
);
91 auto r
= handler
->handle(path
, std::move(req
), std::move(rep
));
92 return r
.handle_exception(_general_handler
);
93 } catch (const redirect_exception
& _e
) {
94 rep
.reset(new reply());
95 rep
->add_header("Location", _e
.url
).set_status(_e
.status()).done(
98 rep
= exception_reply(std::current_exception());
101 rep
.reset(new reply());
102 json_exception
ex(not_found_exception("Not found"));
103 rep
->set_status(reply::status_type::not_found
, ex
.to_json()).done(
106 return make_ready_future
<std::unique_ptr
<reply
>>(std::move(rep
));
109 sstring
routes::normalize_url(const sstring
& url
) {
110 if (url
.length() < 2 || url
.at(url
.length() - 1) != '/') {
113 return url
.substr(0, url
.length() - 1);
116 handler_base
* routes::get_handler(operation_type type
, const sstring
& url
,
117 parameters
& params
) {
118 handler_base
* handler
= get_exact_match(type
, url
);
119 if (handler
!= nullptr) {
123 for (auto&& rule
: _rules
[type
]) {
124 handler
= rule
.second
->get(url
, params
);
125 if (handler
!= nullptr) {
133 routes
& routes::add(operation_type type
, const url
& url
,
134 handler_base
* handler
) {
135 match_rule
* rule
= new match_rule(handler
);
136 rule
->add_str(url
._path
);
137 if (url
._param
!= "") {
138 rule
->add_param(url
._param
, true);
140 return add(rule
, type
);
143 template <typename Map
, typename Key
>
144 static auto delete_rule_from(operation_type type
, Key
& key
, Map
& map
) {
145 auto& bucket
= map
[type
];
146 auto ret
= bucket
.find(key
);
147 using ret_type
= decltype(ret
->second
);
148 if (ret
!= bucket
.end()) {
149 ret_type v
= ret
->second
;
153 return static_cast<ret_type
>(nullptr);
156 handler_base
* routes::drop(operation_type type
, const sstring
& url
) {
157 return delete_rule_from(type
, url
, _map
);
160 routes
& routes::put(operation_type type
, const sstring
& url
, handler_base
* handler
) {
161 auto it
= _map
[type
].emplace(url
, handler
);
162 if (it
.second
== false) {
163 throw std::runtime_error(format("Handler for {} already exists.", url
));
168 match_rule
* routes::del_cookie(rule_cookie cookie
, operation_type type
) {
169 return delete_rule_from(type
, cookie
, _rules
);
172 void routes::add_alias(const path_description
& old_path
, const path_description
& new_path
) {
175 path
<< old_path
.path
;
176 for (const auto& p
: old_path
.params
) {
177 // the path_description path does not contains the path parameters
178 // so just add a fake parameter to the path for each of the parameters,
179 // and add the string for each fixed string part.
180 if (p
.type
== path_description::url_component_type::FIXED_STRING
) {
187 auto a
= get_handler(old_path
.operations
.method
, path
.str(), p
);
189 throw std::runtime_error("routes::add_alias path_description not found: " + old_path
.path
);
191 // if a handler is found then it must be a function_handler
192 new_path
.set(*this, new function_handler(*static_cast<function_handler
*>(a
)));
195 rule_registration::rule_registration(routes
& rs
, match_rule
& rule
, operation_type op
)
196 : _routes(rs
) , _op(op
)
197 , _cookie(_routes
.add_cookie(&rule
, _op
)) {}
199 rule_registration::~rule_registration() {
200 _routes
.del_cookie(_cookie
, _op
);
203 handler_registration::handler_registration(routes
& rs
, handler_base
& h
, const sstring
& url
, operation_type op
)
204 : _routes(rs
), _url(url
), _op(op
) {
205 _routes
.put(_op
, _url
, &h
);
208 handler_registration::~handler_registration() {
209 _routes
.drop(_op
, _url
);