]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_rest_conn.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / rgw / rgw_rest_conn.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "rgw_rados.h"
5 #include "rgw_rest_conn.h"
6
7 #define dout_subsys ceph_subsys_rgw
8
9 RGWRESTConn::RGWRESTConn(CephContext *_cct, RGWRados *store,
10 const string& _remote_id,
11 const list<string>& remote_endpoints)
12 : cct(_cct),
13 endpoints(remote_endpoints.begin(), remote_endpoints.end()),
14 remote_id(_remote_id)
15 {
16 if (store) {
17 key = store->get_zone_params().system_key;
18 self_zone_group = store->get_zonegroup().get_id();
19 }
20 }
21
22 RGWRESTConn::RGWRESTConn(RGWRESTConn&& other)
23 : cct(other.cct),
24 endpoints(std::move(other.endpoints)),
25 key(std::move(other.key)),
26 self_zone_group(std::move(other.self_zone_group)),
27 remote_id(std::move(other.remote_id)),
28 counter(other.counter.load())
29 {
30 }
31
32 RGWRESTConn& RGWRESTConn::operator=(RGWRESTConn&& other)
33 {
34 cct = other.cct;
35 endpoints = std::move(other.endpoints);
36 key = std::move(other.key);
37 self_zone_group = std::move(other.self_zone_group);
38 remote_id = std::move(other.remote_id);
39 counter = other.counter.load();
40 return *this;
41 }
42
43 int RGWRESTConn::get_url(string& endpoint)
44 {
45 if (endpoints.empty()) {
46 ldout(cct, 0) << "ERROR: endpoints not configured for upstream zone" << dendl;
47 return -EIO;
48 }
49
50 int i = ++counter;
51 endpoint = endpoints[i % endpoints.size()];
52
53 return 0;
54 }
55
56 string RGWRESTConn::get_url()
57 {
58 string endpoint;
59 if (endpoints.empty()) {
60 ldout(cct, 0) << "WARNING: endpoints not configured for upstream zone" << dendl; /* we'll catch this later */
61 return endpoint;
62 }
63
64 int i = ++counter;
65 endpoint = endpoints[i % endpoints.size()];
66
67 return endpoint;
68 }
69
70 static void populate_params(param_vec_t& params, const rgw_user *uid, const string& zonegroup)
71 {
72 if (uid) {
73 string uid_str = uid->to_str();
74 if (!uid->empty()) {
75 params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "uid", uid_str));
76 }
77 }
78 if (!zonegroup.empty()) {
79 params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "zonegroup", zonegroup));
80 }
81 }
82
83 int RGWRESTConn::forward(const rgw_user& uid, req_info& info, obj_version *objv, size_t max_response, bufferlist *inbl, bufferlist *outbl)
84 {
85 string url;
86 int ret = get_url(url);
87 if (ret < 0)
88 return ret;
89 param_vec_t params;
90 populate_params(params, &uid, self_zone_group);
91 if (objv) {
92 params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "tag", objv->tag));
93 char buf[16];
94 snprintf(buf, sizeof(buf), "%lld", (long long)objv->ver);
95 params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "ver", buf));
96 }
97 RGWRESTSimpleRequest req(cct, url, NULL, &params);
98 return req.forward_request(key, info, max_response, inbl, outbl);
99 }
100
101 class StreamObjData : public RGWGetDataCB {
102 rgw_obj obj;
103 public:
104 explicit StreamObjData(rgw_obj& _obj) : obj(_obj) {}
105 };
106
107 int RGWRESTConn::put_obj_init(const rgw_user& uid, rgw_obj& obj, uint64_t obj_size,
108 map<string, bufferlist>& attrs, RGWRESTStreamWriteRequest **req)
109 {
110 string url;
111 int ret = get_url(url);
112 if (ret < 0)
113 return ret;
114
115 param_vec_t params;
116 populate_params(params, &uid, self_zone_group);
117 *req = new RGWRESTStreamWriteRequest(cct, url, NULL, &params);
118 return (*req)->put_obj_init(key, obj, obj_size, attrs);
119 }
120
121 int RGWRESTConn::complete_request(RGWRESTStreamWriteRequest *req, string& etag, real_time *mtime)
122 {
123 int ret = req->complete(etag, mtime);
124 delete req;
125
126 return ret;
127 }
128
129 static void set_date_header(const real_time *t, map<string, string>& headers, const string& header_name)
130 {
131 if (!t) {
132 return;
133 }
134 stringstream s;
135 utime_t tm = utime_t(*t);
136 tm.gmtime_nsec(s);
137 headers[header_name] = s.str();
138 }
139
140 template <class T>
141 static void set_header(T val, map<string, string>& headers, const string& header_name)
142 {
143 stringstream s;
144 s << val;
145 headers[header_name] = s.str();
146 }
147
148
149 int RGWRESTConn::get_obj(const rgw_user& uid, req_info *info /* optional */, rgw_obj& obj,
150 const real_time *mod_ptr, const real_time *unmod_ptr,
151 uint32_t mod_zone_id, uint64_t mod_pg_ver,
152 bool prepend_metadata, bool get_op, bool rgwx_stat,
153 bool sync_manifest, RGWGetDataCB *cb,
154 RGWRESTStreamRWRequest **req)
155 {
156 string url;
157 int ret = get_url(url);
158 if (ret < 0)
159 return ret;
160
161 param_vec_t params;
162 populate_params(params, &uid, self_zone_group);
163 if (prepend_metadata) {
164 params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "prepend-metadata", self_zone_group));
165 }
166 if (rgwx_stat) {
167 params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "stat", "true"));
168 }
169 if (sync_manifest) {
170 params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "sync-manifest", ""));
171 }
172 if (!obj.key.instance.empty()) {
173 const string& instance = obj.key.instance;
174 params.push_back(param_pair_t("versionId", instance));
175 }
176 if (get_op) {
177 *req = new RGWRESTStreamReadRequest(cct, url, cb, NULL, &params);
178 } else {
179 *req = new RGWRESTStreamHeadRequest(cct, url, cb, NULL, &params);
180 }
181 map<string, string> extra_headers;
182 if (info) {
183 map<string, string, ltstr_nocase>& orig_map = info->env->get_map();
184
185 /* add original headers that start with HTTP_X_AMZ_ */
186 #define SEARCH_AMZ_PREFIX "HTTP_X_AMZ_"
187 for (map<string, string>::iterator iter = orig_map.lower_bound(SEARCH_AMZ_PREFIX); iter != orig_map.end(); ++iter) {
188 const string& name = iter->first;
189 if (name == "HTTP_X_AMZ_DATE") /* dont forward date from original request */
190 continue;
191 if (name.compare(0, sizeof(SEARCH_AMZ_PREFIX) - 1, "HTTP_X_AMZ_") != 0)
192 break;
193 extra_headers[iter->first] = iter->second;
194 }
195 }
196
197 set_date_header(mod_ptr, extra_headers, "HTTP_IF_MODIFIED_SINCE");
198 set_date_header(unmod_ptr, extra_headers, "HTTP_IF_UNMODIFIED_SINCE");
199 if (mod_zone_id != 0) {
200 set_header(mod_zone_id, extra_headers, "HTTP_DEST_ZONE_SHORT_ID");
201 }
202 if (mod_pg_ver != 0) {
203 set_header(mod_pg_ver, extra_headers, "HTTP_DEST_PG_VER");
204 }
205
206 int r = (*req)->get_obj(key, extra_headers, obj);
207 if (r < 0) {
208 delete *req;
209 *req = nullptr;
210 }
211
212 return r;
213 }
214
215 int RGWRESTConn::complete_request(RGWRESTStreamRWRequest *req, string& etag, real_time *mtime,
216 uint64_t *psize, map<string, string>& attrs)
217 {
218 int ret = req->complete(etag, mtime, psize, attrs);
219 delete req;
220
221 return ret;
222 }
223
224 int RGWRESTConn::get_resource(const string& resource,
225 param_vec_t *extra_params,
226 map<string, string> *extra_headers,
227 bufferlist& bl,
228 RGWHTTPManager *mgr)
229 {
230 string url;
231 int ret = get_url(url);
232 if (ret < 0)
233 return ret;
234
235 param_vec_t params;
236
237 if (extra_params) {
238 params.insert(params.end(), extra_params->begin(), extra_params->end());
239 }
240
241 populate_params(params, nullptr, self_zone_group);
242
243 RGWStreamIntoBufferlist cb(bl);
244
245 RGWRESTStreamReadRequest req(cct, url, &cb, NULL, &params);
246
247 map<string, string> headers;
248 if (extra_headers) {
249 headers.insert(extra_headers->begin(), extra_headers->end());
250 }
251
252 ret = req.get_resource(key, headers, resource, mgr);
253 if (ret < 0) {
254 ldout(cct, 5) << __func__ << ": get_resource() resource=" << resource << " returned ret=" << ret << dendl;
255 return ret;
256 }
257
258 string etag;
259 map<string, string> attrs;
260 return req.complete(etag, NULL, NULL, attrs);
261 }
262
263 RGWRESTReadResource::RGWRESTReadResource(RGWRESTConn *_conn,
264 const string& _resource,
265 const rgw_http_param_pair *pp,
266 param_vec_t *extra_headers,
267 RGWHTTPManager *_mgr)
268 : cct(_conn->get_ctx()), conn(_conn), resource(_resource),
269 params(make_param_list(pp)), cb(bl), mgr(_mgr),
270 req(cct, conn->get_url(), &cb, NULL, NULL)
271 {
272 init_common(extra_headers);
273 }
274
275 RGWRESTReadResource::RGWRESTReadResource(RGWRESTConn *_conn,
276 const string& _resource,
277 param_vec_t& _params,
278 param_vec_t *extra_headers,
279 RGWHTTPManager *_mgr)
280 : cct(_conn->get_ctx()), conn(_conn), resource(_resource), params(_params),
281 cb(bl), mgr(_mgr), req(cct, conn->get_url(), &cb, NULL, NULL)
282 {
283 init_common(extra_headers);
284 }
285
286 void RGWRESTReadResource::init_common(param_vec_t *extra_headers)
287 {
288 populate_params(params, nullptr, conn->get_self_zonegroup());
289
290 if (extra_headers) {
291 headers.insert(extra_headers->begin(), extra_headers->end());
292 }
293
294 req.set_params(&params);
295 }
296
297 int RGWRESTReadResource::read()
298 {
299 int ret = req.get_resource(conn->get_key(), headers, resource, mgr);
300 if (ret < 0) {
301 ldout(cct, 5) << __func__ << ": get_resource() resource=" << resource << " returned ret=" << ret << dendl;
302 return ret;
303 }
304
305 string etag;
306 map<string, string> attrs;
307 return req.complete(etag, NULL, NULL, attrs);
308 }
309
310 int RGWRESTReadResource::aio_read()
311 {
312 int ret = req.get_resource(conn->get_key(), headers, resource, mgr);
313 if (ret < 0) {
314 ldout(cct, 5) << __func__ << ": get_resource() resource=" << resource << " returned ret=" << ret << dendl;
315 return ret;
316 }
317
318 return 0;
319 }
320
321 RGWRESTSendResource::RGWRESTSendResource(RGWRESTConn *_conn,
322 const string& _method,
323 const string& _resource,
324 const rgw_http_param_pair *pp,
325 param_vec_t *extra_headers,
326 RGWHTTPManager *_mgr)
327 : cct(_conn->get_ctx()), conn(_conn), method(_method), resource(_resource),
328 params(make_param_list(pp)), cb(bl), mgr(_mgr),
329 req(cct, method.c_str(), conn->get_url(), &cb, NULL, NULL)
330 {
331 init_common(extra_headers);
332 }
333
334 RGWRESTSendResource::RGWRESTSendResource(RGWRESTConn *_conn,
335 const string& _method,
336 const string& _resource,
337 param_vec_t& params,
338 param_vec_t *extra_headers,
339 RGWHTTPManager *_mgr)
340 : cct(_conn->get_ctx()), conn(_conn), method(_method), resource(_resource), params(params),
341 cb(bl), mgr(_mgr), req(cct, method.c_str(), conn->get_url(), &cb, NULL, NULL)
342 {
343 init_common(extra_headers);
344 }
345
346 void RGWRESTSendResource::init_common(param_vec_t *extra_headers)
347 {
348 populate_params(params, nullptr, conn->get_self_zonegroup());
349
350 if (extra_headers) {
351 headers.insert(extra_headers->begin(), extra_headers->end());
352 }
353
354 req.set_params(&params);
355 }
356
357 int RGWRESTSendResource::send(bufferlist& outbl)
358 {
359 req.set_outbl(outbl);
360 int ret = req.get_resource(conn->get_key(), headers, resource, mgr);
361 if (ret < 0) {
362 ldout(cct, 5) << __func__ << ": get_resource() resource=" << resource << " returned ret=" << ret << dendl;
363 return ret;
364 }
365
366 string etag;
367 map<string, string> attrs;
368 return req.complete(etag, NULL, NULL, attrs);
369 }
370
371 int RGWRESTSendResource::aio_send(bufferlist& outbl)
372 {
373 req.set_outbl(outbl);
374 int ret = req.get_resource(conn->get_key(), headers, resource, mgr);
375 if (ret < 0) {
376 ldout(cct, 5) << __func__ << ": get_resource() resource=" << resource << " returned ret=" << ret << dendl;
377 return ret;
378 }
379
380 return 0;
381 }
382