Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
http_plugin.hpp
Go to the documentation of this file.
1#pragma once
5#include <fc/io/json.hpp>
7
8namespace sysio {
9 using namespace appbase;
10
17 using url_response_callback = std::function<void(int,fc::variant)>;
18
29 using url_handler = std::function<void(string,string,url_response_callback)>;
30
38 using api_description = std::map<string, url_handler>;
39
41 //If empty, unix socket support will be completely disabled. If not empty,
42 // unix socket support is enabled with the given default path (treated relative
43 // to the datadir)
45 //If non 0, HTTP will be enabled by default on the given port number. If
46 // 0, HTTP will not be enabled by default
48 };
49
64 class http_plugin : public appbase::plugin<http_plugin>
65 {
66 public:
68 virtual ~http_plugin();
69
70 //must be called before initialize
71 static void set_defaults(const http_plugin_defaults config);
72
74 virtual void set_program_options(options_description&, options_description& cfg) override;
75
76 void plugin_initialize(const variables_map& options);
77 void plugin_startup();
78 void plugin_shutdown();
79 void handle_sighup() override;
80
81 void add_handler(const string& url, const url_handler&, int priority = appbase::priority::medium_low);
83 for (const auto& call : api)
84 add_handler(call.first, call.second, priority);
85 }
86
87 void add_async_handler(const string& url, const url_handler& handler);
89 for (const auto& call : api)
90 add_handler(call.first, call.second);
91 }
92
93 // standard exception handling for api handlers
94 static void handle_exception( const char *api_name, const char *call_name, const string& body, url_response_callback cb );
95
96 bool is_on_loopback() const;
97 bool is_secure() const;
98
99 bool verbose_errors()const;
100
104
106
109
110 private:
111 std::shared_ptr<class http_plugin_impl> my;
112 };
113
118 uint16_t code{};
119 string message;
120
121 struct error_info {
122 int64_t code{};
123 string name;
124 string what;
125
127 string message;
128 string file;
130 string method;
131 };
132
134
135 static const uint8_t details_limit = 10;
136
138
139 error_info(const fc::exception& exc, bool include_full_log) {
140 code = exc.code();
141 name = exc.name();
142 what = exc.what();
143 uint8_t limit = include_full_log ? details_limit : 1;
144 for( auto itr = exc.get_log().begin(); itr != exc.get_log().end(); ++itr ) {
145 // Prevent sending trace that are too big
146 if( details.size() >= limit ) break;
147 // Append error
149 include_full_log ? itr->get_message() : itr->get_limited_message(),
150 itr->get_context().get_file(),
151 itr->get_context().get_line_number(),
152 itr->get_context().get_method()
153 };
154 details.emplace_back( detail );
155 }
156 }
157 };
158
160 };
161
166 inline std::string_view make_trimmed_string_view(const std::string& body) {
167 if (body.empty()) {
168 return {};
169 }
170 size_t left = 0;
171 size_t right = body.size() - 1;
172
173 while(left < right)
174 {
175 if (body[left] == ' ') {
176 ++left;
177 } else {
178 break;
179 }
180 }
181 while(left < right)
182 {
183 if (body[right] == ' ') {
184 --right;
185 } else {
186 break;
187 }
188 }
189 if ((left == right) && (body[left] == ' ')) {
190 return {};
191 }
192 return std::string_view(body).substr(left, right-left+1);
193 }
194
195 inline bool is_empty_content(const std::string& body) {
196 const auto trimmed_body_view = make_trimmed_string_view(body);
197 if (trimmed_body_view.empty()) {
198 return true;
199 }
200 const size_t body_size = trimmed_body_view.size();
201 if ((body_size > 1) && (trimmed_body_view.at(0) == '{') && (trimmed_body_view.at(body_size - 1) == '}')) {
202 for(size_t idx=1; idx<body_size-1; ++idx)
203 {
204 if ((trimmed_body_view.at(idx) != ' ') && (trimmed_body_view.at(idx) != '\t'))
205 {
206 return false;
207 }
208 }
209 } else {
210 return false;
211 }
212 return true;
213 }
214
215 enum class http_params_types {
216 no_params = 0,
217 params_required = 1,
219 };
220
221 template<typename T, http_params_types params_type>
222 T parse_params(const std::string& body) {
223 if constexpr (params_type == http_params_types::params_required) {
224 if (is_empty_content(body)) {
225 SYS_THROW(chain::invalid_http_request, "A Request body is required");
226 }
227 }
228
229 try {
230 try {
231 if constexpr (params_type == http_params_types::no_params || params_type == http_params_types::possible_no_params) {
232 if (is_empty_content(body)) {
233 if constexpr (std::is_same_v<T, std::string>) {
234 return std::string("{}");
235 }
236 return {};
237 }
238 if constexpr (params_type == http_params_types::no_params) {
239 SYS_THROW(chain::invalid_http_request, "no parameter should be given");
240 }
241 }
242 return fc::json::from_string(body).as<T>();
243 } catch (const chain::chain_exception& e) { // SYS_RETHROW_EXCEPTIONS does not re-type these so, re-code it
244 throw fc::exception(e);
245 }
246 } SYS_RETHROW_EXCEPTIONS(chain::invalid_http_request, "Unable to parse valid input from POST body");
247 }
248}
249
251FC_REFLECT(sysio::error_results::error_info, (code)(name)(what)(details))
252FC_REFLECT(sysio::error_results, (code)(message)(error))
std::string name
#define SYS_THROW(exc_type, FORMAT,...)
#define SYS_RETHROW_EXCEPTIONS(exception_type, FORMAT,...)
Used to generate a useful error report when an exception is thrown.
Definition exception.hpp:58
const log_messages & get_log() const
int64_t code() const
const char * name() const
const char * what() const noexcept override
static variant from_string(const string &utf8_str, const parse_type ptype=parse_type::legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
Definition json.cpp:442
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition variant.hpp:191
T as() const
Definition variant.hpp:327
void add_api(const api_description &api, int priority=appbase::priority::medium_low)
void add_handler(const string &url, const url_handler &, int priority=appbase::priority::medium_low)
void add_async_handler(const string &url, const url_handler &handler)
bool is_secure() const
virtual void set_program_options(options_description &, options_description &cfg) override
bool verbose_errors() const
get_supported_apis_result get_supported_apis() const
fc::microseconds get_max_response_time() const
bool is_on_loopback() const
static void set_defaults(const http_plugin_defaults config)
void plugin_initialize(const variables_map &options)
static void handle_exception(const char *api_name, const char *call_name, const string &body, url_response_callback cb)
void add_async_api(const api_description &api)
void handle_sighup() override
Defines exception's used by fc.
bool is_empty_content(const std::string &body)
std::map< string, url_handler > api_description
An API, containing URLs and handlers.
std::function< void(string, string, url_response_callback)> url_handler
Callback type for a URL handler.
std::string_view make_trimmed_string_view(const std::string &body)
Used to trim whitespace from body. Returned string_view valid only for lifetime of body.
std::function< void(int, fc::variant)> url_response_callback
A callback function provided to a URL handler to allow it to specify the HTTP response code and body.
T parse_params(const std::string &body)
#define APPBASE_PLUGIN_REQUIRES(PLUGINS)
Definition plugin.hpp:11
#define T(meth, val, expected)
fc::variant call(const std::string &url, const std::string &path, const T &v)
Definition main.cpp:258
#define FC_REFLECT(TYPE, MEMBERS)
Specializes fc::reflector for TYPE.
Definition reflect.hpp:311
unsigned short uint16_t
Definition stdint.h:125
signed __int64 int64_t
Definition stdint.h:135
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
static constexpr int medium_low
Immutable except for fc::from_variant.
Definition name.hpp:43
vector< error_detail > details
error_info(const fc::exception &exc, bool include_full_log)
static const uint8_t details_limit
Structure used to create JSON error responses.