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