]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
9f95a23c | 2 | // vim: ts=8 sw=2 smarttab ft=cpp |
7c673cae FG |
3 | |
4 | #ifndef CEPH_RGW_HTTP_CLIENT_H | |
5 | #define CEPH_RGW_HTTP_CLIENT_H | |
6 | ||
eafe8130 | 7 | #include "common/async/yield_context.h" |
7c673cae FG |
8 | #include "common/Cond.h" |
9 | #include "rgw_common.h" | |
10 | #include "rgw_string.h" | |
9f95a23c | 11 | #include "rgw_http_client_types.h" |
7c673cae FG |
12 | |
13 | #include <atomic> | |
14 | ||
20effc67 TL |
15 | using param_pair_t = std::pair<std::string, std::string>; |
16 | using param_vec_t = std::vector<param_pair_t>; | |
7c673cae | 17 | |
11fdf7f2 TL |
18 | void rgw_http_client_init(CephContext *cct); |
19 | void rgw_http_client_cleanup(); | |
20 | ||
7c673cae | 21 | struct rgw_http_req_data; |
11fdf7f2 TL |
22 | class RGWHTTPManager; |
23 | ||
20effc67 TL |
24 | class RGWHTTPClient : public RGWIOProvider, |
25 | public NoDoutPrefix | |
7c673cae FG |
26 | { |
27 | friend class RGWHTTPManager; | |
28 | ||
29 | bufferlist send_bl; | |
30 | bufferlist::iterator send_iter; | |
7c673cae FG |
31 | bool has_send_len; |
32 | long http_status; | |
11fdf7f2 TL |
33 | bool send_data_hint{false}; |
34 | size_t receive_pause_skip{0}; /* how many bytes to skip next time receive_data is called | |
35 | due to being paused */ | |
7c673cae | 36 | |
11fdf7f2 | 37 | void *user_info{nullptr}; |
7c673cae | 38 | |
11fdf7f2 | 39 | rgw_http_req_data *req_data; |
7c673cae | 40 | |
7c673cae FG |
41 | bool verify_ssl; // Do not validate self signed certificates, default to false |
42 | ||
20effc67 | 43 | std::string ca_path; |
522d829b | 44 | |
20effc67 | 45 | std::string client_cert; |
522d829b | 46 | |
20effc67 | 47 | std::string client_key; |
522d829b | 48 | |
7c673cae FG |
49 | std::atomic<unsigned> stopped { 0 }; |
50 | ||
11fdf7f2 | 51 | |
7c673cae FG |
52 | protected: |
53 | CephContext *cct; | |
11fdf7f2 | 54 | |
20effc67 TL |
55 | std::string method; |
56 | std::string url; | |
57 | ||
58 | std::string protocol; | |
59 | std::string host; | |
60 | std::string resource_prefix; | |
11fdf7f2 TL |
61 | |
62 | size_t send_len{0}; | |
63 | ||
7c673cae FG |
64 | param_vec_t headers; |
65 | ||
f67539c2 TL |
66 | long req_timeout{0L}; |
67 | ||
20effc67 TL |
68 | void init(); |
69 | ||
11fdf7f2 TL |
70 | RGWHTTPManager *get_manager(); |
71 | ||
72 | int init_request(rgw_http_req_data *req_data); | |
7c673cae FG |
73 | |
74 | virtual int receive_header(void *ptr, size_t len) { | |
75 | return 0; | |
76 | } | |
11fdf7f2 | 77 | virtual int receive_data(void *ptr, size_t len, bool *pause) { |
7c673cae FG |
78 | return 0; |
79 | } | |
11fdf7f2 TL |
80 | |
81 | virtual int send_data(void *ptr, size_t len, bool *pause=nullptr) { | |
7c673cae FG |
82 | return 0; |
83 | } | |
84 | ||
85 | /* Callbacks for libcurl. */ | |
7c673cae FG |
86 | static size_t receive_http_header(void *ptr, |
87 | size_t size, | |
88 | size_t nmemb, | |
89 | void *_info); | |
90 | ||
7c673cae FG |
91 | static size_t receive_http_data(void *ptr, |
92 | size_t size, | |
93 | size_t nmemb, | |
94 | void *_info); | |
95 | ||
7c673cae FG |
96 | static size_t send_http_data(void *ptr, |
97 | size_t size, | |
98 | size_t nmemb, | |
99 | void *_info); | |
11fdf7f2 | 100 | |
9f95a23c | 101 | ceph::mutex& get_req_lock(); |
11fdf7f2 TL |
102 | |
103 | /* needs to be called under req_lock() */ | |
104 | void _set_write_paused(bool pause); | |
105 | void _set_read_paused(bool pause); | |
7c673cae FG |
106 | public: |
107 | static const long HTTP_STATUS_NOSTATUS = 0; | |
108 | static const long HTTP_STATUS_UNAUTHORIZED = 401; | |
109 | static const long HTTP_STATUS_NOTFOUND = 404; | |
110 | ||
11fdf7f2 TL |
111 | static constexpr int HTTPCLIENT_IO_READ = 0x1; |
112 | static constexpr int HTTPCLIENT_IO_WRITE = 0x2; | |
113 | static constexpr int HTTPCLIENT_IO_CONTROL = 0x4; | |
114 | ||
7c673cae | 115 | virtual ~RGWHTTPClient(); |
11fdf7f2 | 116 | explicit RGWHTTPClient(CephContext *cct, |
20effc67 TL |
117 | const std::string& _method, |
118 | const std::string& _url); | |
119 | ||
120 | std::ostream& gen_prefix(std::ostream& out) const override; | |
121 | ||
7c673cae | 122 | |
20effc67 TL |
123 | void append_header(const std::string& name, const std::string& val) { |
124 | headers.push_back(std::pair<std::string, std::string>(name, val)); | |
7c673cae FG |
125 | } |
126 | ||
127 | void set_send_length(size_t len) { | |
128 | send_len = len; | |
129 | has_send_len = true; | |
130 | } | |
131 | ||
11fdf7f2 TL |
132 | void set_send_data_hint(bool hint) { |
133 | send_data_hint = hint; | |
134 | } | |
7c673cae FG |
135 | |
136 | long get_http_status() const { | |
137 | return http_status; | |
138 | } | |
139 | ||
9f95a23c TL |
140 | void set_http_status(long _http_status) { |
141 | http_status = _http_status; | |
142 | } | |
143 | ||
7c673cae FG |
144 | void set_verify_ssl(bool flag) { |
145 | verify_ssl = flag; | |
146 | } | |
147 | ||
f67539c2 TL |
148 | // set request timeout in seconds |
149 | // zero (default) mean that request will never timeout | |
150 | void set_req_timeout(long timeout) { | |
151 | req_timeout = timeout; | |
152 | } | |
153 | ||
9f95a23c | 154 | int process(optional_yield y); |
7c673cae | 155 | |
9f95a23c | 156 | int wait(optional_yield y); |
11fdf7f2 TL |
157 | void cancel(); |
158 | bool is_done(); | |
159 | ||
7c673cae FG |
160 | rgw_http_req_data *get_req_data() { return req_data; } |
161 | ||
20effc67 | 162 | std::string to_str(); |
7c673cae FG |
163 | |
164 | int get_req_retcode(); | |
11fdf7f2 | 165 | |
20effc67 | 166 | void set_url(const std::string& _url) { |
11fdf7f2 TL |
167 | url = _url; |
168 | } | |
169 | ||
20effc67 | 170 | void set_method(const std::string& _method) { |
11fdf7f2 TL |
171 | method = _method; |
172 | } | |
173 | ||
174 | void set_io_user_info(void *_user_info) override { | |
175 | user_info = _user_info; | |
176 | } | |
177 | ||
178 | void *get_io_user_info() override { | |
179 | return user_info; | |
180 | } | |
522d829b | 181 | |
20effc67 | 182 | void set_ca_path(const std::string& _ca_path) { |
522d829b TL |
183 | ca_path = _ca_path; |
184 | } | |
185 | ||
20effc67 | 186 | void set_client_cert(const std::string& _client_cert) { |
522d829b TL |
187 | client_cert = _client_cert; |
188 | } | |
189 | ||
20effc67 | 190 | void set_client_key(const std::string& _client_key) { |
522d829b TL |
191 | client_key = _client_key; |
192 | } | |
7c673cae FG |
193 | }; |
194 | ||
195 | ||
196 | class RGWHTTPHeadersCollector : public RGWHTTPClient { | |
197 | public: | |
198 | typedef std::string header_name_t; | |
199 | typedef std::string header_value_t; | |
200 | typedef std::set<header_name_t, ltstr_nocase> header_spec_t; | |
201 | ||
202 | RGWHTTPHeadersCollector(CephContext * const cct, | |
20effc67 TL |
203 | const std::string& method, |
204 | const std::string& url, | |
11fdf7f2 TL |
205 | const header_spec_t &relevant_headers) |
206 | : RGWHTTPClient(cct, method, url), | |
7c673cae FG |
207 | relevant_headers(relevant_headers) { |
208 | } | |
209 | ||
210 | std::map<header_name_t, header_value_t, ltstr_nocase> get_headers() const { | |
211 | return found_headers; | |
212 | } | |
213 | ||
214 | /* Throws std::out_of_range */ | |
215 | const header_value_t& get_header_value(const header_name_t& name) const { | |
216 | return found_headers.at(name); | |
217 | } | |
218 | ||
219 | protected: | |
220 | int receive_header(void *ptr, size_t len) override; | |
221 | ||
7c673cae FG |
222 | private: |
223 | const std::set<header_name_t, ltstr_nocase> relevant_headers; | |
224 | std::map<header_name_t, header_value_t, ltstr_nocase> found_headers; | |
225 | }; | |
226 | ||
227 | ||
228 | class RGWHTTPTransceiver : public RGWHTTPHeadersCollector { | |
229 | bufferlist * const read_bl; | |
230 | std::string post_data; | |
231 | size_t post_data_index; | |
232 | ||
233 | public: | |
234 | RGWHTTPTransceiver(CephContext * const cct, | |
20effc67 TL |
235 | const std::string& method, |
236 | const std::string& url, | |
7c673cae FG |
237 | bufferlist * const read_bl, |
238 | const header_spec_t intercept_headers = {}) | |
11fdf7f2 | 239 | : RGWHTTPHeadersCollector(cct, method, url, intercept_headers), |
7c673cae FG |
240 | read_bl(read_bl), |
241 | post_data_index(0) { | |
242 | } | |
243 | ||
244 | RGWHTTPTransceiver(CephContext * const cct, | |
20effc67 TL |
245 | const std::string& method, |
246 | const std::string& url, | |
7c673cae FG |
247 | bufferlist * const read_bl, |
248 | const bool verify_ssl, | |
249 | const header_spec_t intercept_headers = {}) | |
11fdf7f2 | 250 | : RGWHTTPHeadersCollector(cct, method, url, intercept_headers), |
7c673cae FG |
251 | read_bl(read_bl), |
252 | post_data_index(0) { | |
253 | set_verify_ssl(verify_ssl); | |
254 | } | |
255 | ||
256 | void set_post_data(const std::string& _post_data) { | |
257 | this->post_data = _post_data; | |
258 | } | |
259 | ||
260 | protected: | |
11fdf7f2 | 261 | int send_data(void* ptr, size_t len, bool *pause=nullptr) override; |
7c673cae | 262 | |
11fdf7f2 | 263 | int receive_data(void *ptr, size_t len, bool *pause) override { |
7c673cae FG |
264 | read_bl->append((char *)ptr, len); |
265 | return 0; | |
266 | } | |
267 | }; | |
268 | ||
269 | typedef RGWHTTPTransceiver RGWPostHTTPData; | |
270 | ||
271 | ||
272 | class RGWCompletionManager; | |
273 | ||
11fdf7f2 TL |
274 | enum RGWHTTPRequestSetState { |
275 | SET_NOP = 0, | |
276 | SET_WRITE_PAUSED = 1, | |
277 | SET_WRITE_RESUME = 2, | |
278 | SET_READ_PAUSED = 3, | |
279 | SET_READ_RESUME = 4, | |
280 | }; | |
281 | ||
7c673cae | 282 | class RGWHTTPManager { |
11fdf7f2 TL |
283 | struct set_state { |
284 | rgw_http_req_data *req; | |
285 | int bitmask; | |
286 | ||
287 | set_state(rgw_http_req_data *_req, int _bitmask) : req(_req), bitmask(_bitmask) {} | |
288 | }; | |
7c673cae FG |
289 | CephContext *cct; |
290 | RGWCompletionManager *completion_mgr; | |
291 | void *multi_handle; | |
9f95a23c | 292 | bool is_started = false; |
7c673cae FG |
293 | std::atomic<unsigned> going_down { 0 }; |
294 | std::atomic<unsigned> is_stopped { 0 }; | |
295 | ||
9f95a23c | 296 | ceph::shared_mutex reqs_lock = ceph::make_shared_mutex("RGWHTTPManager::reqs_lock"); |
20effc67 TL |
297 | std::map<uint64_t, rgw_http_req_data *> reqs; |
298 | std::list<rgw_http_req_data *> unregistered_reqs; | |
299 | std::list<set_state> reqs_change_state; | |
300 | std::map<uint64_t, rgw_http_req_data *> complete_reqs; | |
9f95a23c TL |
301 | int64_t num_reqs = 0; |
302 | int64_t max_threaded_req = 0; | |
7c673cae FG |
303 | int thread_pipe[2]; |
304 | ||
305 | void register_request(rgw_http_req_data *req_data); | |
306 | void complete_request(rgw_http_req_data *req_data); | |
307 | void _complete_request(rgw_http_req_data *req_data); | |
11fdf7f2 | 308 | bool unregister_request(rgw_http_req_data *req_data); |
7c673cae FG |
309 | void _unlink_request(rgw_http_req_data *req_data); |
310 | void unlink_request(rgw_http_req_data *req_data); | |
9f95a23c | 311 | void finish_request(rgw_http_req_data *req_data, int r, long http_status = -1); |
7c673cae | 312 | void _finish_request(rgw_http_req_data *req_data, int r); |
11fdf7f2 | 313 | void _set_req_state(set_state& ss); |
7c673cae FG |
314 | int link_request(rgw_http_req_data *req_data); |
315 | ||
316 | void manage_pending_requests(); | |
317 | ||
318 | class ReqsThread : public Thread { | |
319 | RGWHTTPManager *manager; | |
320 | ||
321 | public: | |
11fdf7f2 | 322 | explicit ReqsThread(RGWHTTPManager *_m) : manager(_m) {} |
7c673cae FG |
323 | void *entry() override; |
324 | }; | |
325 | ||
9f95a23c | 326 | ReqsThread *reqs_thread = nullptr; |
7c673cae FG |
327 | |
328 | void *reqs_thread_entry(); | |
329 | ||
330 | int signal_thread(); | |
331 | ||
332 | public: | |
333 | RGWHTTPManager(CephContext *_cct, RGWCompletionManager *completion_mgr = NULL); | |
334 | ~RGWHTTPManager(); | |
335 | ||
11fdf7f2 | 336 | int start(); |
7c673cae FG |
337 | void stop(); |
338 | ||
11fdf7f2 | 339 | int add_request(RGWHTTPClient *client); |
7c673cae | 340 | int remove_request(RGWHTTPClient *client); |
11fdf7f2 | 341 | int set_request_state(RGWHTTPClient *client, RGWHTTPRequestSetState state); |
7c673cae FG |
342 | }; |
343 | ||
11fdf7f2 TL |
344 | class RGWHTTP |
345 | { | |
346 | public: | |
347 | static int send(RGWHTTPClient *req); | |
9f95a23c | 348 | static int process(RGWHTTPClient *req, optional_yield y); |
11fdf7f2 | 349 | }; |
7c673cae | 350 | #endif |