]>
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 | #include "rgw_rados.h" | |
11fdf7f2 | 5 | #include "rgw_zone.h" |
7c673cae FG |
6 | #include "rgw_rest_conn.h" |
7 | ||
11fdf7f2 TL |
8 | #include "services/svc_zone.h" |
9 | ||
7c673cae FG |
10 | #define dout_subsys ceph_subsys_rgw |
11 | ||
11fdf7f2 | 12 | RGWRESTConn::RGWRESTConn(CephContext *_cct, RGWSI_Zone *zone_svc, |
7c673cae | 13 | const string& _remote_id, |
11fdf7f2 TL |
14 | const list<string>& remote_endpoints, |
15 | HostStyle _host_style) | |
7c673cae FG |
16 | : cct(_cct), |
17 | endpoints(remote_endpoints.begin(), remote_endpoints.end()), | |
11fdf7f2 | 18 | remote_id(_remote_id), host_style(_host_style) |
7c673cae | 19 | { |
11fdf7f2 TL |
20 | if (zone_svc) { |
21 | key = zone_svc->get_zone_params().system_key; | |
22 | self_zone_group = zone_svc->get_zonegroup().get_id(); | |
23 | } | |
24 | } | |
25 | ||
26 | RGWRESTConn::RGWRESTConn(CephContext *_cct, RGWSI_Zone *zone_svc, | |
27 | const string& _remote_id, | |
28 | const list<string>& remote_endpoints, | |
29 | RGWAccessKey _cred, | |
30 | HostStyle _host_style) | |
31 | : cct(_cct), | |
32 | endpoints(remote_endpoints.begin(), remote_endpoints.end()), | |
33 | key(std::move(_cred)), | |
34 | remote_id(_remote_id), host_style(_host_style) | |
35 | { | |
36 | if (zone_svc) { | |
37 | self_zone_group = zone_svc->get_zonegroup().get_id(); | |
7c673cae FG |
38 | } |
39 | } | |
40 | ||
41 | RGWRESTConn::RGWRESTConn(RGWRESTConn&& other) | |
42 | : cct(other.cct), | |
43 | endpoints(std::move(other.endpoints)), | |
44 | key(std::move(other.key)), | |
45 | self_zone_group(std::move(other.self_zone_group)), | |
46 | remote_id(std::move(other.remote_id)), | |
47 | counter(other.counter.load()) | |
48 | { | |
49 | } | |
50 | ||
51 | RGWRESTConn& RGWRESTConn::operator=(RGWRESTConn&& other) | |
52 | { | |
53 | cct = other.cct; | |
54 | endpoints = std::move(other.endpoints); | |
55 | key = std::move(other.key); | |
56 | self_zone_group = std::move(other.self_zone_group); | |
57 | remote_id = std::move(other.remote_id); | |
58 | counter = other.counter.load(); | |
59 | return *this; | |
60 | } | |
61 | ||
62 | int RGWRESTConn::get_url(string& endpoint) | |
63 | { | |
64 | if (endpoints.empty()) { | |
65 | ldout(cct, 0) << "ERROR: endpoints not configured for upstream zone" << dendl; | |
66 | return -EIO; | |
67 | } | |
68 | ||
69 | int i = ++counter; | |
70 | endpoint = endpoints[i % endpoints.size()]; | |
71 | ||
72 | return 0; | |
73 | } | |
74 | ||
75 | string RGWRESTConn::get_url() | |
76 | { | |
77 | string endpoint; | |
78 | if (endpoints.empty()) { | |
79 | ldout(cct, 0) << "WARNING: endpoints not configured for upstream zone" << dendl; /* we'll catch this later */ | |
80 | return endpoint; | |
81 | } | |
82 | ||
83 | int i = ++counter; | |
84 | endpoint = endpoints[i % endpoints.size()]; | |
85 | ||
86 | return endpoint; | |
87 | } | |
88 | ||
11fdf7f2 | 89 | void RGWRESTConn::populate_params(param_vec_t& params, const rgw_user *uid, const string& zonegroup) |
7c673cae | 90 | { |
11fdf7f2 TL |
91 | populate_uid(params, uid); |
92 | populate_zonegroup(params, zonegroup); | |
7c673cae FG |
93 | } |
94 | ||
95 | int RGWRESTConn::forward(const rgw_user& uid, req_info& info, obj_version *objv, size_t max_response, bufferlist *inbl, bufferlist *outbl) | |
96 | { | |
97 | string url; | |
98 | int ret = get_url(url); | |
99 | if (ret < 0) | |
100 | return ret; | |
101 | param_vec_t params; | |
102 | populate_params(params, &uid, self_zone_group); | |
103 | if (objv) { | |
104 | params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "tag", objv->tag)); | |
105 | char buf[16]; | |
106 | snprintf(buf, sizeof(buf), "%lld", (long long)objv->ver); | |
107 | params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "ver", buf)); | |
108 | } | |
11fdf7f2 | 109 | RGWRESTSimpleRequest req(cct, info.method, url, NULL, ¶ms); |
7c673cae FG |
110 | return req.forward_request(key, info, max_response, inbl, outbl); |
111 | } | |
112 | ||
113 | class StreamObjData : public RGWGetDataCB { | |
114 | rgw_obj obj; | |
115 | public: | |
116 | explicit StreamObjData(rgw_obj& _obj) : obj(_obj) {} | |
117 | }; | |
118 | ||
11fdf7f2 | 119 | int RGWRESTConn::put_obj_send_init(rgw_obj& obj, const rgw_http_param_pair *extra_params, RGWRESTStreamS3PutObj **req) |
7c673cae FG |
120 | { |
121 | string url; | |
122 | int ret = get_url(url); | |
123 | if (ret < 0) | |
124 | return ret; | |
125 | ||
11fdf7f2 | 126 | rgw_user uid; |
7c673cae FG |
127 | param_vec_t params; |
128 | populate_params(params, &uid, self_zone_group); | |
11fdf7f2 TL |
129 | |
130 | if (extra_params) { | |
131 | append_param_list(params, extra_params); | |
132 | } | |
133 | ||
134 | RGWRESTStreamS3PutObj *wr = new RGWRESTStreamS3PutObj(cct, "PUT", url, NULL, ¶ms, host_style); | |
135 | wr->send_init(obj); | |
136 | *req = wr; | |
137 | return 0; | |
138 | } | |
139 | ||
140 | int RGWRESTConn::put_obj_async(const rgw_user& uid, rgw_obj& obj, uint64_t obj_size, | |
141 | map<string, bufferlist>& attrs, bool send, | |
142 | RGWRESTStreamS3PutObj **req) | |
143 | { | |
144 | string url; | |
145 | int ret = get_url(url); | |
146 | if (ret < 0) | |
147 | return ret; | |
148 | ||
149 | param_vec_t params; | |
150 | populate_params(params, &uid, self_zone_group); | |
151 | RGWRESTStreamS3PutObj *wr = new RGWRESTStreamS3PutObj(cct, "PUT", url, NULL, ¶ms, host_style); | |
152 | ret = wr->put_obj_init(key, obj, obj_size, attrs, send); | |
c07f9fc5 FG |
153 | if (ret < 0) { |
154 | delete wr; | |
155 | return ret; | |
156 | } | |
157 | *req = wr; | |
158 | return 0; | |
7c673cae FG |
159 | } |
160 | ||
11fdf7f2 | 161 | int RGWRESTConn::complete_request(RGWRESTStreamS3PutObj *req, string& etag, real_time *mtime) |
7c673cae | 162 | { |
11fdf7f2 | 163 | int ret = req->complete_request(&etag, mtime); |
7c673cae FG |
164 | delete req; |
165 | ||
166 | return ret; | |
167 | } | |
168 | ||
11fdf7f2 | 169 | static void set_date_header(const real_time *t, map<string, string>& headers, bool high_precision_time, const string& header_name) |
7c673cae FG |
170 | { |
171 | if (!t) { | |
172 | return; | |
173 | } | |
174 | stringstream s; | |
175 | utime_t tm = utime_t(*t); | |
11fdf7f2 TL |
176 | if (high_precision_time) { |
177 | tm.gmtime_nsec(s); | |
178 | } else { | |
179 | tm.gmtime(s); | |
180 | } | |
7c673cae FG |
181 | headers[header_name] = s.str(); |
182 | } | |
183 | ||
184 | template <class T> | |
185 | static void set_header(T val, map<string, string>& headers, const string& header_name) | |
186 | { | |
187 | stringstream s; | |
188 | s << val; | |
189 | headers[header_name] = s.str(); | |
190 | } | |
191 | ||
192 | ||
11fdf7f2 | 193 | int RGWRESTConn::get_obj(const rgw_user& uid, req_info *info /* optional */, const rgw_obj& obj, |
7c673cae FG |
194 | const real_time *mod_ptr, const real_time *unmod_ptr, |
195 | uint32_t mod_zone_id, uint64_t mod_pg_ver, | |
196 | bool prepend_metadata, bool get_op, bool rgwx_stat, | |
11fdf7f2 TL |
197 | bool sync_manifest, bool skip_decrypt, |
198 | bool send, RGWHTTPStreamRWRequest::ReceiveCB *cb, RGWRESTStreamRWRequest **req) | |
199 | { | |
200 | get_obj_params params; | |
201 | params.uid = uid; | |
202 | params.info = info; | |
203 | params.mod_ptr = mod_ptr; | |
204 | params.mod_pg_ver = mod_pg_ver; | |
205 | params.prepend_metadata = prepend_metadata; | |
206 | params.get_op = get_op; | |
207 | params.rgwx_stat = rgwx_stat; | |
208 | params.sync_manifest = sync_manifest; | |
209 | params.skip_decrypt = skip_decrypt; | |
210 | params.cb = cb; | |
211 | return get_obj(obj, params, send, req); | |
212 | } | |
213 | ||
214 | int RGWRESTConn::get_obj(const rgw_obj& obj, const get_obj_params& in_params, bool send, RGWRESTStreamRWRequest **req) | |
7c673cae FG |
215 | { |
216 | string url; | |
217 | int ret = get_url(url); | |
218 | if (ret < 0) | |
219 | return ret; | |
220 | ||
221 | param_vec_t params; | |
11fdf7f2 TL |
222 | populate_params(params, &in_params.uid, self_zone_group); |
223 | if (in_params.prepend_metadata) { | |
224 | params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "prepend-metadata", "true")); | |
7c673cae | 225 | } |
11fdf7f2 | 226 | if (in_params.rgwx_stat) { |
7c673cae FG |
227 | params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "stat", "true")); |
228 | } | |
11fdf7f2 | 229 | if (in_params.sync_manifest) { |
7c673cae FG |
230 | params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "sync-manifest", "")); |
231 | } | |
11fdf7f2 | 232 | if (in_params.skip_decrypt) { |
181888fb FG |
233 | params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "skip-decrypt", "")); |
234 | } | |
7c673cae FG |
235 | if (!obj.key.instance.empty()) { |
236 | const string& instance = obj.key.instance; | |
237 | params.push_back(param_pair_t("versionId", instance)); | |
238 | } | |
11fdf7f2 TL |
239 | if (in_params.get_op) { |
240 | *req = new RGWRESTStreamReadRequest(cct, url, in_params.cb, NULL, ¶ms, host_style); | |
7c673cae | 241 | } else { |
11fdf7f2 | 242 | *req = new RGWRESTStreamHeadRequest(cct, url, in_params.cb, NULL, ¶ms); |
7c673cae FG |
243 | } |
244 | map<string, string> extra_headers; | |
11fdf7f2 TL |
245 | if (in_params.info) { |
246 | const auto& orig_map = in_params.info->env->get_map(); | |
7c673cae FG |
247 | |
248 | /* add original headers that start with HTTP_X_AMZ_ */ | |
31f18b77 FG |
249 | static constexpr char SEARCH_AMZ_PREFIX[] = "HTTP_X_AMZ_"; |
250 | for (auto iter= orig_map.lower_bound(SEARCH_AMZ_PREFIX); iter != orig_map.end(); ++iter) { | |
7c673cae | 251 | const string& name = iter->first; |
11fdf7f2 | 252 | if (name == "HTTP_X_AMZ_DATE") /* don't forward date from original request */ |
7c673cae | 253 | continue; |
31f18b77 | 254 | if (name.compare(0, strlen(SEARCH_AMZ_PREFIX), SEARCH_AMZ_PREFIX) != 0) |
7c673cae FG |
255 | break; |
256 | extra_headers[iter->first] = iter->second; | |
257 | } | |
258 | } | |
259 | ||
11fdf7f2 TL |
260 | set_date_header(in_params.mod_ptr, extra_headers, in_params.high_precision_time, "HTTP_IF_MODIFIED_SINCE"); |
261 | set_date_header(in_params.unmod_ptr, extra_headers, in_params.high_precision_time, "HTTP_IF_UNMODIFIED_SINCE"); | |
262 | if (!in_params.etag.empty()) { | |
263 | set_header(in_params.etag, extra_headers, "HTTP_IF_MATCH"); | |
7c673cae | 264 | } |
11fdf7f2 TL |
265 | if (in_params.mod_zone_id != 0) { |
266 | set_header(in_params.mod_zone_id, extra_headers, "HTTP_DEST_ZONE_SHORT_ID"); | |
267 | } | |
268 | if (in_params.mod_pg_ver != 0) { | |
269 | set_header(in_params.mod_pg_ver, extra_headers, "HTTP_DEST_PG_VER"); | |
270 | } | |
271 | if (in_params.range_is_set) { | |
272 | char buf[64]; | |
273 | snprintf(buf, sizeof(buf), "bytes=%lld-%lld", (long long)in_params.range_start, (long long)in_params.range_end); | |
274 | set_header(buf, extra_headers, "RANGE"); | |
7c673cae FG |
275 | } |
276 | ||
11fdf7f2 | 277 | int r = (*req)->send_prepare(key, extra_headers, obj); |
7c673cae | 278 | if (r < 0) { |
11fdf7f2 | 279 | goto done_err; |
7c673cae FG |
280 | } |
281 | ||
11fdf7f2 TL |
282 | if (!send) { |
283 | return 0; | |
284 | } | |
285 | ||
286 | r = (*req)->send(nullptr); | |
287 | if (r < 0) { | |
288 | goto done_err; | |
289 | } | |
290 | return 0; | |
291 | done_err: | |
292 | delete *req; | |
293 | *req = nullptr; | |
7c673cae FG |
294 | return r; |
295 | } | |
296 | ||
11fdf7f2 TL |
297 | int RGWRESTConn::complete_request(RGWRESTStreamRWRequest *req, |
298 | string *etag, | |
299 | real_time *mtime, | |
300 | uint64_t *psize, | |
301 | map<string, string> *pattrs, | |
302 | map<string, string> *pheaders) | |
7c673cae | 303 | { |
11fdf7f2 | 304 | int ret = req->complete_request(etag, mtime, psize, pattrs, pheaders); |
7c673cae FG |
305 | delete req; |
306 | ||
307 | return ret; | |
308 | } | |
309 | ||
310 | int RGWRESTConn::get_resource(const string& resource, | |
311 | param_vec_t *extra_params, | |
312 | map<string, string> *extra_headers, | |
313 | bufferlist& bl, | |
31f18b77 | 314 | bufferlist *send_data, |
7c673cae FG |
315 | RGWHTTPManager *mgr) |
316 | { | |
317 | string url; | |
318 | int ret = get_url(url); | |
319 | if (ret < 0) | |
320 | return ret; | |
321 | ||
322 | param_vec_t params; | |
323 | ||
324 | if (extra_params) { | |
325 | params.insert(params.end(), extra_params->begin(), extra_params->end()); | |
326 | } | |
327 | ||
328 | populate_params(params, nullptr, self_zone_group); | |
329 | ||
330 | RGWStreamIntoBufferlist cb(bl); | |
331 | ||
11fdf7f2 | 332 | RGWRESTStreamReadRequest req(cct, url, &cb, NULL, ¶ms, host_style); |
7c673cae FG |
333 | |
334 | map<string, string> headers; | |
335 | if (extra_headers) { | |
336 | headers.insert(extra_headers->begin(), extra_headers->end()); | |
337 | } | |
338 | ||
11fdf7f2 | 339 | ret = req.send_request(&key, headers, resource, mgr, send_data); |
7c673cae | 340 | if (ret < 0) { |
31f18b77 | 341 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
342 | return ret; |
343 | } | |
344 | ||
11fdf7f2 | 345 | return req.complete_request(); |
7c673cae FG |
346 | } |
347 | ||
348 | RGWRESTReadResource::RGWRESTReadResource(RGWRESTConn *_conn, | |
349 | const string& _resource, | |
350 | const rgw_http_param_pair *pp, | |
351 | param_vec_t *extra_headers, | |
352 | RGWHTTPManager *_mgr) | |
353 | : cct(_conn->get_ctx()), conn(_conn), resource(_resource), | |
354 | params(make_param_list(pp)), cb(bl), mgr(_mgr), | |
355 | req(cct, conn->get_url(), &cb, NULL, NULL) | |
356 | { | |
357 | init_common(extra_headers); | |
358 | } | |
359 | ||
360 | RGWRESTReadResource::RGWRESTReadResource(RGWRESTConn *_conn, | |
361 | const string& _resource, | |
362 | param_vec_t& _params, | |
363 | param_vec_t *extra_headers, | |
364 | RGWHTTPManager *_mgr) | |
365 | : cct(_conn->get_ctx()), conn(_conn), resource(_resource), params(_params), | |
366 | cb(bl), mgr(_mgr), req(cct, conn->get_url(), &cb, NULL, NULL) | |
367 | { | |
368 | init_common(extra_headers); | |
369 | } | |
370 | ||
371 | void RGWRESTReadResource::init_common(param_vec_t *extra_headers) | |
372 | { | |
11fdf7f2 | 373 | conn->populate_params(params, nullptr, conn->get_self_zonegroup()); |
7c673cae FG |
374 | |
375 | if (extra_headers) { | |
376 | headers.insert(extra_headers->begin(), extra_headers->end()); | |
377 | } | |
378 | ||
379 | req.set_params(¶ms); | |
380 | } | |
381 | ||
382 | int RGWRESTReadResource::read() | |
383 | { | |
11fdf7f2 | 384 | int ret = req.send_request(&conn->get_key(), headers, resource, mgr); |
7c673cae | 385 | if (ret < 0) { |
31f18b77 | 386 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
387 | return ret; |
388 | } | |
389 | ||
11fdf7f2 | 390 | return req.complete_request(); |
7c673cae FG |
391 | } |
392 | ||
393 | int RGWRESTReadResource::aio_read() | |
394 | { | |
11fdf7f2 | 395 | int ret = req.send_request(&conn->get_key(), headers, resource, mgr); |
7c673cae | 396 | if (ret < 0) { |
31f18b77 | 397 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
398 | return ret; |
399 | } | |
400 | ||
401 | return 0; | |
402 | } | |
403 | ||
404 | RGWRESTSendResource::RGWRESTSendResource(RGWRESTConn *_conn, | |
405 | const string& _method, | |
406 | const string& _resource, | |
407 | const rgw_http_param_pair *pp, | |
408 | param_vec_t *extra_headers, | |
409 | RGWHTTPManager *_mgr) | |
410 | : cct(_conn->get_ctx()), conn(_conn), method(_method), resource(_resource), | |
411 | params(make_param_list(pp)), cb(bl), mgr(_mgr), | |
11fdf7f2 | 412 | req(cct, method.c_str(), conn->get_url(), &cb, NULL, NULL, _conn->get_host_style()) |
7c673cae FG |
413 | { |
414 | init_common(extra_headers); | |
415 | } | |
416 | ||
417 | RGWRESTSendResource::RGWRESTSendResource(RGWRESTConn *_conn, | |
418 | const string& _method, | |
419 | const string& _resource, | |
420 | param_vec_t& params, | |
421 | param_vec_t *extra_headers, | |
422 | RGWHTTPManager *_mgr) | |
423 | : cct(_conn->get_ctx()), conn(_conn), method(_method), resource(_resource), params(params), | |
11fdf7f2 | 424 | cb(bl), mgr(_mgr), req(cct, method.c_str(), conn->get_url(), &cb, NULL, NULL, _conn->get_host_style()) |
7c673cae FG |
425 | { |
426 | init_common(extra_headers); | |
427 | } | |
428 | ||
429 | void RGWRESTSendResource::init_common(param_vec_t *extra_headers) | |
430 | { | |
11fdf7f2 | 431 | conn->populate_params(params, nullptr, conn->get_self_zonegroup()); |
7c673cae FG |
432 | |
433 | if (extra_headers) { | |
434 | headers.insert(extra_headers->begin(), extra_headers->end()); | |
435 | } | |
436 | ||
437 | req.set_params(¶ms); | |
438 | } | |
439 | ||
440 | int RGWRESTSendResource::send(bufferlist& outbl) | |
441 | { | |
11fdf7f2 | 442 | req.set_send_length(outbl.length()); |
7c673cae | 443 | req.set_outbl(outbl); |
11fdf7f2 TL |
444 | |
445 | int ret = req.send_request(&conn->get_key(), headers, resource, mgr); | |
7c673cae | 446 | if (ret < 0) { |
31f18b77 | 447 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
448 | return ret; |
449 | } | |
450 | ||
11fdf7f2 | 451 | return req.complete_request(); |
7c673cae FG |
452 | } |
453 | ||
454 | int RGWRESTSendResource::aio_send(bufferlist& outbl) | |
455 | { | |
11fdf7f2 | 456 | req.set_send_length(outbl.length()); |
7c673cae | 457 | req.set_outbl(outbl); |
11fdf7f2 TL |
458 | |
459 | int ret = req.send_request(&conn->get_key(), headers, resource, mgr); | |
7c673cae | 460 | if (ret < 0) { |
31f18b77 | 461 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
462 | return ret; |
463 | } | |
464 | ||
465 | return 0; | |
466 | } |