]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_rest_conn.cc
import 15.2.0 Octopus source
[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
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 12RGWRESTConn::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
26RGWRESTConn::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
41RGWRESTConn::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
51RGWRESTConn& 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
62int 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
75string 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 89void 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
95int 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, &params);
7c673cae
FG
110 return req.forward_request(key, info, max_response, inbl, outbl);
111}
112
113class StreamObjData : public RGWGetDataCB {
114 rgw_obj obj;
115public:
116 explicit StreamObjData(rgw_obj& _obj) : obj(_obj) {}
117};
118
11fdf7f2 119int 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, &params, host_style);
135 wr->send_init(obj);
136 *req = wr;
137 return 0;
138}
139
140int 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, &params, 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 161int 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 169static 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
184template <class T>
185static 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 193int 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
214int 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, &params, host_style);
7c673cae 241 } else {
11fdf7f2 242 *req = new RGWRESTStreamHeadRequest(cct, url, in_params.cb, NULL, &params);
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;
291done_err:
292 delete *req;
293 *req = nullptr;
7c673cae
FG
294 return r;
295}
296
11fdf7f2
TL
297int 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
310int 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, &params, 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
348RGWRESTReadResource::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
360RGWRESTReadResource::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
371void 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(&params);
380}
381
382int 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
393int 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
404RGWRESTSendResource::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
417RGWRESTSendResource::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
429void 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(&params);
438}
439
440int 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
454int 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}