Files
scylladb/http/api_docs.hh
Amnon Heiman f06c12e031 http: fix crash due to set_routes() not managing lifetime correctly
When using the set_routes with the registry builder, the shared_ptr of
the registry builder should be captured.

In the original implementation the api_registery_builder captured this
parameter, but as the shared_ptr was not captured it was deleted,
causing the http to crash when running in debug.

In this implementation the method that use the registry creates a lambda
function and inside it calls the set_api_doc method, this allows to
catch the shared_ptr so it lives until the function complete.

It also replaces the c style cast to static_cast and add a FIXME note to
the routes implementation, that handlers should be deleted to prevent
memory leak.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-04-26 13:09:26 +03:00

160 lines
4.6 KiB
C++

/*
* This file is open source software, licensed to you under the terms
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Copyright 2015 Cloudius Systems
*/
#ifndef API_DOCS_HH_
#define API_DOCS_HH_
#include "json/json_elements.hh"
#include "json/formatter.hh"
#include "routes.hh"
#include "transformers.hh"
#include <string>
namespace httpd {
struct api_doc : public json::json_base {
json::json_element<std::string> path;
json::json_element<std::string> description;
void register_params() {
add(&path, "path");
add(&description, "description");
}
api_doc() {
register_params();
}
api_doc(const api_doc & e) {
register_params();
path = e.path;
description = e.description;
}
template<class T>
api_doc& operator=(const T& e) {
path = e.path;
description = e.description;
return *this;
}
api_doc& operator=(const api_doc& e) {
path = e.path;
description = e.description;
return *this;
}
};
struct api_docs : public json::json_base {
json::json_element<std::string> apiVersion;
json::json_element<std::string> swaggerVersion;
json::json_list<api_doc> apis;
void register_params() {
add(&apiVersion, "apiVersion");
add(&swaggerVersion, "swaggerVersion");
add(&apis, "apis");
}
api_docs() {
apiVersion = "0.0.1";
swaggerVersion = "1.2";
register_params();
}
api_docs(const api_docs & e) {
apiVersion = "0.0.1";
swaggerVersion = "1.2";
register_params();
}
template<class T>
api_docs& operator=(const T& e) {
apis = e.apis;
return *this;
}
api_docs& operator=(const api_docs& e) {
apis = e.apis;
return *this;
}
};
class api_registry : public handler_base {
sstring _base_path;
sstring _file_directory;
api_docs _docs;
routes& _routes;
public:
api_registry(routes& routes, const sstring& file_directory,
const sstring& base_path)
: _base_path(base_path), _file_directory(file_directory), _routes(
routes) {
_routes.put(GET, _base_path, this);
}
future<std::unique_ptr<reply>> handle(const sstring& path,
std::unique_ptr<request> req, std::unique_ptr<reply> rep) override {
rep->_content = json::formatter::to_json(_docs);
rep->done("json");
return make_ready_future<std::unique_ptr<reply>>(std::move(rep));
}
void reg(const sstring& api, const sstring& description,
const sstring& alternative_path = "") {
api_doc doc;
doc.description = description;
doc.path = "/" + api;
_docs.apis.push(doc);
sstring path =
(alternative_path == "") ?
_file_directory + api + ".json" : alternative_path;
file_handler* index = new file_handler(path,
new content_replace("json"));
_routes.put(GET, _base_path + "/" + api, index);
}
};
class api_registry_builder {
sstring _file_directory;
sstring _base_path;
public:
static const sstring DEFAULT_DIR;
static const sstring DEFAULT_PATH;
api_registry_builder(const sstring& file_directory = DEFAULT_DIR,
const sstring& base_path = DEFAULT_PATH)
: _file_directory(file_directory), _base_path(base_path) {
}
void set_api_doc(routes& r) {
new api_registry(r, _file_directory, _base_path);
}
void register_function(routes& r, const sstring& api,
const sstring& description, const sstring& alternative_path = "") {
auto h = r.get_exact_match(GET, _base_path);
if (h) {
// if a handler is found, it was added there by the api_registry_builder
// with the set_api_doc method, so we know it's the type
static_cast<api_registry*>(h)->reg(api, description, alternative_path);
};
}
};
}
#endif /* API_DOCS_HH_ */