Arbiter  0.0.0
http.hpp
1 #pragma once
2 
3 #include <condition_variable>
4 #include <map>
5 #include <memory>
6 #include <mutex>
7 #include <string>
8 #include <vector>
9 
10 #include <curl/curl.h>
11 
12 #ifndef ARBITER_IS_AMALGAMATION
13 #ifndef ARBITER_EXTERNAL_JSON
14 #include <arbiter/third/json/json.hpp>
15 #endif
16 #endif
17 
18 #ifdef ARBITER_EXTERNAL_JSON
19 #include <json/json.h>
20 #endif
21 
22 #ifdef ARBITER_CUSTOM_NAMESPACE
23 namespace ARBITER_CUSTOM_NAMESPACE
24 {
25 #endif
26 
27 namespace arbiter
28 {
29 namespace http
30 {
31 
33 using Headers = std::map<std::string, std::string>;
34 
36 using Query = std::map<std::string, std::string>;
37 
41 std::string sanitize(std::string path, std::string exclusions = "/");
42 
47 std::string buildQueryString(const http::Query& query);
48 
51 class Response
52 {
53 public:
54  Response(int code = 0)
55  : m_code(code)
56  , m_data()
57  { }
58 
59  Response(int code, std::vector<char> data)
60  : m_code(code)
61  , m_data(data)
62  { }
63 
64  Response(
65  int code,
66  const std::vector<char>& data,
67  const Headers& headers)
68  : m_code(code)
69  , m_data(data)
70  , m_headers(headers)
71  { }
72 
73  ~Response() { }
74 
75  bool ok() const { return m_code / 100 == 2; }
76  bool clientError() const { return m_code / 100 == 4; }
77  bool serverError() const { return m_code / 100 == 5; }
78  int code() const { return m_code; }
79 
80  std::vector<char> data() const { return m_data; }
81  const Headers& headers() const { return m_headers; }
82 
83 private:
84  int m_code;
85  std::vector<char> m_data;
86  Headers m_headers;
87 };
88 
89 class Pool;
90 
91 class Curl
92 {
93  friend class Pool;
94 
95 public:
96  ~Curl();
97 
98  http::Response get(std::string path, Headers headers, Query query);
99  http::Response head(std::string path, Headers headers, Query query);
100  http::Response put(
101  std::string path,
102  const std::vector<char>& data,
103  Headers headers,
104  Query query);
105  http::Response post(
106  std::string path,
107  const std::vector<char>& data,
108  Headers headers,
109  Query query);
110 
111 private:
112  Curl(bool verbose, std::size_t timeout);
113 
114  void init(std::string path, const Headers& headers, const Query& query);
115 
116  Curl(const Curl&);
117  Curl& operator=(const Curl&);
118 
119  CURL* m_curl;
120  curl_slist* m_headers;
121  const bool m_verbose;
122  const std::size_t m_timeout;
123 
124  std::vector<char> m_data;
125 };
126 
127 class Resource
128 {
129 public:
130  Resource(Pool& pool, Curl& curl, std::size_t id, std::size_t retry);
131  ~Resource();
132 
133  http::Response get(
134  std::string path,
135  Headers headers = Headers(),
136  Query query = Query());
137 
138  http::Response head(
139  std::string path,
140  Headers headers = Headers(),
141  Query query = Query());
142 
143  http::Response put(
144  std::string path,
145  const std::vector<char>& data,
146  Headers headers = Headers(),
147  Query query = Query());
148 
149  http::Response post(
150  std::string path,
151  const std::vector<char>& data,
152  Headers headers = Headers(),
153  Query query = Query());
154 
155 private:
156  Pool& m_pool;
157  Curl& m_curl;
158  std::size_t m_id;
159  std::size_t m_retry;
160 
161  http::Response exec(std::function<http::Response()> f);
162 };
163 
164 class Pool
165 {
166  // Only HttpResource may release.
167  friend class Resource;
168 
169 public:
170  Pool(
171  std::size_t concurrent,
172  std::size_t retry,
173  const Json::Value& json);
174 
175  Resource acquire();
176 
177 private:
178  void release(std::size_t id);
179 
180  std::vector<std::unique_ptr<Curl>> m_curls;
181  std::vector<std::size_t> m_available;
182  std::size_t m_retry;
183 
184  std::mutex m_mutex;
185  std::condition_variable m_cv;
186 };
187 
190 } // namespace http
191 } // namespace arbiter
192 
193 #ifdef ARBITER_CUSTOM_NAMESPACE
194 }
195 #endif
196 
Definition: arbiter.cpp:16