http_client.cc
1 // Copyright 2018, Beeri 15. All rights reserved.
2 // Author: Roman Gershman (romange@gmail.com)
3 //
4 
5 #include "util/http/http_client.h"
6 
7 #include <boost/asio/connect.hpp>
8 #include <boost/beast/core/flat_buffer.hpp>
9 #include <boost/beast/http/dynamic_body.hpp>
10 #include <boost/beast/http/read.hpp>
11 #include <boost/beast/http/string_body.hpp>
12 #include <boost/beast/http/write.hpp>
13 
14 #include "base/logging.h"
15 #include "util/asio/fiber_socket.h"
16 #include "util/asio/yield.h"
17 
18 namespace util {
19 namespace http {
20 
21 using fibers_ext::yield;
22 using namespace boost;
23 
24 namespace h2 = beast::http;
25 
26 Client::Client(IoContext* io_context) : io_context_(*io_context) {}
27 
28 Client::~Client() {}
29 
30 system::error_code Client::Connect(StringPiece host, StringPiece service) {
31  socket_.reset(
32  new FiberSyncSocket(strings::AsString(host), strings::AsString(service), &io_context_));
33 
34  return socket_->ClientWaitToConnect(connect_timeout_ms_);
35 }
36 
37 ::boost::system::error_code Client::Send(Verb verb, StringPiece url, StringPiece body,
38  Response* response) {
39  // Set the URL
40  h2::request<h2::string_body> req{verb, boost::string_view(url.data(), url.size()), 11};
41 
42  // Optional headers
43  for (const auto& k_v : headers_) {
44  req.set(k_v.first, k_v.second);
45  }
46  req.body().assign(body.begin(), body.end());
47  req.prepare_payload();
48 
49  system::error_code ec;
50 
51  // Send the HTTP request to the remote host.
52  h2::write(*socket_, req, ec);
53  if (ec) {
54  VLOG(1) << "Error " << ec;
55  return ec;
56  }
57 
58  // This buffer is used for reading and must be persisted
59  beast::flat_buffer buffer;
60 
61  h2::read(*socket_, buffer, *response, ec);
62  VLOG(2) << "Resp: " << *response;
63 
64  return ec;
65 }
66 
67 void Client::Shutdown() {
68  if (socket_) {
69  system::error_code ec;
70  socket_->Shutdown(ec);
71  socket_.reset();
72  }
73 }
74 
75 bool Client::IsConnected() const {
76  return socket_ && socket_->is_open() && !socket_->status();
77 }
78 
79 } // namespace http
80 } // namespace util