303 {
304 static const deadline_type epoch(boost::gregorian::date(1970, 1, 1));
306 FC_ASSERT(dest.host(),
"No host set on URL");
307
308 string path = dest.path() ? dest.path()->generic_string() : "/";
309 if (dest.query()) {
310 path = path + "?" + *dest.query();
311 }
312
313 string host_str = *dest.host();
314 if (dest.port()) {
315 auto port = *dest.port();
316 auto proto_iter = default_proto_ports.find(dest.proto());
317 if (proto_iter != default_proto_ports.end() && proto_iter->second != port) {
318 host_str = host_str + ":" + std::to_string(port);
319 }
320 }
321
322 http::request<http::string_body> req{http::verb::post, path, 11};
323 req.set(http::field::host, host_str);
324 req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
325 req.set(http::field::content_type, "application/json");
326 req.keep_alive(true);
328 req.prepare_payload();
329
333 });
334
335
336 error_code ec = std::visit(write_request_visitor(this, req, deadline), conn_iter->second);
337 FC_ASSERT(!ec,
"Failed to send request: ${message}", (
"message",ec.message()));
338
339
340 boost::beast::flat_buffer buffer;
341
342
343 http::response<http::string_body> res;
344
345
346 ec = std::visit(read_response_visitor(this, buffer, res, deadline), conn_iter->second);
347 FC_ASSERT(!ec,
"Failed to read response: ${message}", (
"message",ec.message()));
348
349
350 if (res.keep_alive()) {
351 eraser.cancel();
352 }
353
355 if( !res.body().empty() ) {
356 try {
358 } catch( ... ) {}
359 }
360 if (res.result() == http::status::internal_server_error) {
362 try {
363 auto err_var = result.get_object()["error"].get_object();
364 excp = std::make_shared<fc::exception>(err_var["code"].as_int64(), err_var["name"].as_string(), err_var["what"].as_string());
365
366 if (err_var.contains("details")) {
367 for (const auto& dvar : err_var["details"].get_array()) {
368 excp->append_log(
FC_LOG_MESSAGE(error, dvar.get_object()[
"message"].as_string()));
369 }
370 }
371 } catch( ... ) {
372
373 }
374
375 if (excp) {
376 throw *excp;
377 } else {
378 FC_THROW(
"Request failed with 500 response, but response was not parseable");
379 }
380 } else if (res.result() == http::status::not_found) {
381 FC_THROW(
"URL not found: ${url}", (
"url", (std::string)dest));
382 }
383
384 return result;
385 }
connection_map::iterator get_connection(const url &dest, const deadline_type &deadline)
boost::posix_time::ptime deadline_type
static string to_string(const variant &v, const yield_function_t &yield, const output_formatting format=output_formatting::stringify_large_ints_and_doubles)
static variant from_string(const string &utf8_str, const parse_type ptype=parse_type::legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
constexpr int64_t count() const
constexpr const microseconds & time_since_epoch() const
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
#define FC_LOG_MESSAGE(LOG_LEVEL, FORMAT,...)
A helper method for generating log messages.
std::shared_ptr< exception > exception_ptr
scoped_exit< Callback > make_scoped_exit(Callback &&c)