]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/src/http/routes.cc
update download target update for octopus release
[ceph.git] / ceph / src / seastar / src / http / routes.cc
CommitLineData
11fdf7f2
TL
1/*
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.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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
16 * under the License.
17 */
18/*
19 * Copyright 2015 Cloudius Systems
20 */
21
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>
26
27namespace seastar {
28
29namespace httpd {
30
31using namespace std;
32
33void verify_param(const request& req, const sstring& param) {
34 if (req.get_query_param(param) == "") {
35 throw missing_param_exception(param);
36 }
37}
38routes::routes() : _general_handler([this](std::exception_ptr eptr) mutable {
39 return exception_reply(eptr);
40}) {}
41
42routes::~routes() {
43 for (int i = 0; i < NUM_OPERATION; i++) {
44 for (auto kv : _map[i]) {
45 delete kv.second;
46 }
47 }
48 for (int i = 0; i < NUM_OPERATION; i++) {
49 for (auto r : _rules[i]) {
50 delete r;
51 }
52 }
53
54}
55
56std::unique_ptr<reply> routes::exception_reply(std::exception_ptr eptr) {
57 auto rep = std::make_unique<reply>();
58 try {
59 // go over the register exception handler
60 // if one of them handle the exception, return.
61 for (auto e: _exceptions) {
62 try {
63 return e.second(eptr);
64 } catch (...) {
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();
69 }
70 }
71 std::rethrow_exception(eptr);
72 } catch (const base_exception& e) {
73 rep->set_status(e.status(), json_exception(e).to_json());
74 } catch (exception& e) {
75 rep->set_status(reply::status_type::internal_server_error,
76 json_exception(e).to_json());
77 } catch (...) {
78 rep->set_status(reply::status_type::internal_server_error,
79 json_exception(std::runtime_error(
80 "Unknown unhandled exception")).to_json());
81 }
82 rep->done("json");
83 return rep;
84}
85
86future<std::unique_ptr<reply> > routes::handle(const sstring& path, std::unique_ptr<request> req, std::unique_ptr<reply> rep) {
87 handler_base* handler = get_handler(str2type(req->_method),
88 normalize_url(path), req->param);
89 if (handler != nullptr) {
90 try {
91 for (auto& i : handler->_mandatory_param) {
92 verify_param(*req.get(), i);
93 }
94 auto r = handler->handle(path, std::move(req), std::move(rep));
95 return r.handle_exception(_general_handler);
96 } catch (const redirect_exception& _e) {
97 rep.reset(new reply());
98 rep->add_header("Location", _e.url).set_status(_e.status()).done(
99 "json");
100 } catch (...) {
101 rep = exception_reply(std::current_exception());
102 }
103 } else {
104 rep.reset(new reply());
105 json_exception ex(not_found_exception("Not found"));
106 rep->set_status(reply::status_type::not_found, ex.to_json()).done(
107 "json");
108 }
109 return make_ready_future<std::unique_ptr<reply>>(std::move(rep));
110}
111
112sstring routes::normalize_url(const sstring& url) {
113 if (url.length() < 2 || url.at(url.length() - 1) != '/') {
114 return url;
115 }
116 return url.substr(0, url.length() - 1);
117}
118
119handler_base* routes::get_handler(operation_type type, const sstring& url,
120 parameters& params) {
121 handler_base* handler = get_exact_match(type, url);
122 if (handler != nullptr) {
123 return handler;
124 }
125
126 for (auto rule = _rules[type].cbegin(); rule != _rules[type].cend();
127 ++rule) {
128 handler = (*rule)->get(url, params);
129 if (handler != nullptr) {
130 return handler;
131 }
132 params.clear();
133 }
134 return nullptr;
135}
136
137routes& routes::add(operation_type type, const url& url,
138 handler_base* handler) {
139 match_rule* rule = new match_rule(handler);
140 rule->add_str(url._path);
141 if (url._param != "") {
142 rule->add_param(url._param, true);
143 }
144 return add(rule, type);
145}
146
147void routes::add_alias(const path_description& old_path, const path_description& new_path) {
148 httpd::parameters p;
149 stringstream path;
150 path << old_path.path;
151 for (const auto& p : old_path.params) {
152 // the path_description path does not contains the path parameters
153 // so just add a fake parameter to the path for each of the parameters,
154 // and add the string for each fixed string part.
155 if (p.type == path_description::url_component_type::FIXED_STRING) {
156 path << p.name;
157 } else {
158 path << "/k";
159 }
160
161 }
162 auto a = get_handler(old_path.operations.method, path.str(), p);
163 if (!a) {
164 throw std::runtime_error("routes::add_alias path_description not found: " + old_path.path);
165 }
166 // if a handler is found then it must be a function_handler
167 new_path.set(*this, new function_handler(*static_cast<function_handler*>(a)));
168}
169
170}
171
172}