]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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, ¶ms); | |
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); | |
c07f9fc5 FG |
117 | RGWRESTStreamWriteRequest *wr = new RGWRESTStreamWriteRequest(cct, url, NULL, ¶ms); |
118 | ret = wr->put_obj_init(key, obj, obj_size, attrs); | |
119 | if (ret < 0) { | |
120 | delete wr; | |
121 | return ret; | |
122 | } | |
123 | *req = wr; | |
124 | return 0; | |
7c673cae FG |
125 | } |
126 | ||
127 | int RGWRESTConn::complete_request(RGWRESTStreamWriteRequest *req, string& etag, real_time *mtime) | |
128 | { | |
129 | int ret = req->complete(etag, mtime); | |
130 | delete req; | |
131 | ||
132 | return ret; | |
133 | } | |
134 | ||
135 | static void set_date_header(const real_time *t, map<string, string>& headers, const string& header_name) | |
136 | { | |
137 | if (!t) { | |
138 | return; | |
139 | } | |
140 | stringstream s; | |
141 | utime_t tm = utime_t(*t); | |
142 | tm.gmtime_nsec(s); | |
143 | headers[header_name] = s.str(); | |
144 | } | |
145 | ||
146 | template <class T> | |
147 | static void set_header(T val, map<string, string>& headers, const string& header_name) | |
148 | { | |
149 | stringstream s; | |
150 | s << val; | |
151 | headers[header_name] = s.str(); | |
152 | } | |
153 | ||
154 | ||
155 | int RGWRESTConn::get_obj(const rgw_user& uid, req_info *info /* optional */, rgw_obj& obj, | |
156 | const real_time *mod_ptr, const real_time *unmod_ptr, | |
157 | uint32_t mod_zone_id, uint64_t mod_pg_ver, | |
158 | bool prepend_metadata, bool get_op, bool rgwx_stat, | |
159 | bool sync_manifest, RGWGetDataCB *cb, | |
160 | RGWRESTStreamRWRequest **req) | |
161 | { | |
162 | string url; | |
163 | int ret = get_url(url); | |
164 | if (ret < 0) | |
165 | return ret; | |
166 | ||
167 | param_vec_t params; | |
168 | populate_params(params, &uid, self_zone_group); | |
169 | if (prepend_metadata) { | |
170 | params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "prepend-metadata", self_zone_group)); | |
171 | } | |
172 | if (rgwx_stat) { | |
173 | params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "stat", "true")); | |
174 | } | |
175 | if (sync_manifest) { | |
176 | params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "sync-manifest", "")); | |
177 | } | |
178 | if (!obj.key.instance.empty()) { | |
179 | const string& instance = obj.key.instance; | |
180 | params.push_back(param_pair_t("versionId", instance)); | |
181 | } | |
182 | if (get_op) { | |
183 | *req = new RGWRESTStreamReadRequest(cct, url, cb, NULL, ¶ms); | |
184 | } else { | |
185 | *req = new RGWRESTStreamHeadRequest(cct, url, cb, NULL, ¶ms); | |
186 | } | |
187 | map<string, string> extra_headers; | |
188 | if (info) { | |
31f18b77 | 189 | const auto& orig_map = info->env->get_map(); |
7c673cae FG |
190 | |
191 | /* add original headers that start with HTTP_X_AMZ_ */ | |
31f18b77 FG |
192 | static constexpr char SEARCH_AMZ_PREFIX[] = "HTTP_X_AMZ_"; |
193 | for (auto iter= orig_map.lower_bound(SEARCH_AMZ_PREFIX); iter != orig_map.end(); ++iter) { | |
7c673cae FG |
194 | const string& name = iter->first; |
195 | if (name == "HTTP_X_AMZ_DATE") /* dont forward date from original request */ | |
196 | continue; | |
31f18b77 | 197 | if (name.compare(0, strlen(SEARCH_AMZ_PREFIX), SEARCH_AMZ_PREFIX) != 0) |
7c673cae FG |
198 | break; |
199 | extra_headers[iter->first] = iter->second; | |
200 | } | |
201 | } | |
202 | ||
203 | set_date_header(mod_ptr, extra_headers, "HTTP_IF_MODIFIED_SINCE"); | |
204 | set_date_header(unmod_ptr, extra_headers, "HTTP_IF_UNMODIFIED_SINCE"); | |
205 | if (mod_zone_id != 0) { | |
206 | set_header(mod_zone_id, extra_headers, "HTTP_DEST_ZONE_SHORT_ID"); | |
207 | } | |
208 | if (mod_pg_ver != 0) { | |
209 | set_header(mod_pg_ver, extra_headers, "HTTP_DEST_PG_VER"); | |
210 | } | |
211 | ||
31f18b77 | 212 | int r = (*req)->send_request(key, extra_headers, obj); |
7c673cae FG |
213 | if (r < 0) { |
214 | delete *req; | |
215 | *req = nullptr; | |
216 | } | |
217 | ||
218 | return r; | |
219 | } | |
220 | ||
221 | int RGWRESTConn::complete_request(RGWRESTStreamRWRequest *req, string& etag, real_time *mtime, | |
222 | uint64_t *psize, map<string, string>& attrs) | |
223 | { | |
31f18b77 | 224 | int ret = req->complete_request(etag, mtime, psize, attrs); |
7c673cae FG |
225 | delete req; |
226 | ||
227 | return ret; | |
228 | } | |
229 | ||
230 | int RGWRESTConn::get_resource(const string& resource, | |
231 | param_vec_t *extra_params, | |
232 | map<string, string> *extra_headers, | |
233 | bufferlist& bl, | |
31f18b77 | 234 | bufferlist *send_data, |
7c673cae FG |
235 | RGWHTTPManager *mgr) |
236 | { | |
237 | string url; | |
238 | int ret = get_url(url); | |
239 | if (ret < 0) | |
240 | return ret; | |
241 | ||
242 | param_vec_t params; | |
243 | ||
244 | if (extra_params) { | |
245 | params.insert(params.end(), extra_params->begin(), extra_params->end()); | |
246 | } | |
247 | ||
248 | populate_params(params, nullptr, self_zone_group); | |
249 | ||
250 | RGWStreamIntoBufferlist cb(bl); | |
251 | ||
252 | RGWRESTStreamReadRequest req(cct, url, &cb, NULL, ¶ms); | |
253 | ||
254 | map<string, string> headers; | |
255 | if (extra_headers) { | |
256 | headers.insert(extra_headers->begin(), extra_headers->end()); | |
257 | } | |
258 | ||
31f18b77 | 259 | ret = req.send_request(&key, headers, resource, send_data, mgr); |
7c673cae | 260 | if (ret < 0) { |
31f18b77 | 261 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
262 | return ret; |
263 | } | |
264 | ||
265 | string etag; | |
266 | map<string, string> attrs; | |
31f18b77 | 267 | return req.complete_request(etag, NULL, NULL, attrs); |
7c673cae FG |
268 | } |
269 | ||
270 | RGWRESTReadResource::RGWRESTReadResource(RGWRESTConn *_conn, | |
271 | const string& _resource, | |
272 | const rgw_http_param_pair *pp, | |
273 | param_vec_t *extra_headers, | |
274 | RGWHTTPManager *_mgr) | |
275 | : cct(_conn->get_ctx()), conn(_conn), resource(_resource), | |
276 | params(make_param_list(pp)), cb(bl), mgr(_mgr), | |
277 | req(cct, conn->get_url(), &cb, NULL, NULL) | |
278 | { | |
279 | init_common(extra_headers); | |
280 | } | |
281 | ||
282 | RGWRESTReadResource::RGWRESTReadResource(RGWRESTConn *_conn, | |
283 | const string& _resource, | |
284 | param_vec_t& _params, | |
285 | param_vec_t *extra_headers, | |
286 | RGWHTTPManager *_mgr) | |
287 | : cct(_conn->get_ctx()), conn(_conn), resource(_resource), params(_params), | |
288 | cb(bl), mgr(_mgr), req(cct, conn->get_url(), &cb, NULL, NULL) | |
289 | { | |
290 | init_common(extra_headers); | |
291 | } | |
292 | ||
293 | void RGWRESTReadResource::init_common(param_vec_t *extra_headers) | |
294 | { | |
295 | populate_params(params, nullptr, conn->get_self_zonegroup()); | |
296 | ||
297 | if (extra_headers) { | |
298 | headers.insert(extra_headers->begin(), extra_headers->end()); | |
299 | } | |
300 | ||
301 | req.set_params(¶ms); | |
302 | } | |
303 | ||
304 | int RGWRESTReadResource::read() | |
305 | { | |
31f18b77 | 306 | int ret = req.send_request(&conn->get_key(), headers, resource, nullptr, mgr); |
7c673cae | 307 | if (ret < 0) { |
31f18b77 | 308 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
309 | return ret; |
310 | } | |
311 | ||
312 | string etag; | |
313 | map<string, string> attrs; | |
31f18b77 | 314 | return req.complete_request(etag, NULL, NULL, attrs); |
7c673cae FG |
315 | } |
316 | ||
317 | int RGWRESTReadResource::aio_read() | |
318 | { | |
31f18b77 | 319 | int ret = req.send_request(&conn->get_key(), headers, resource, nullptr, mgr); |
7c673cae | 320 | if (ret < 0) { |
31f18b77 | 321 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
322 | return ret; |
323 | } | |
324 | ||
325 | return 0; | |
326 | } | |
327 | ||
328 | RGWRESTSendResource::RGWRESTSendResource(RGWRESTConn *_conn, | |
329 | const string& _method, | |
330 | const string& _resource, | |
331 | const rgw_http_param_pair *pp, | |
332 | param_vec_t *extra_headers, | |
333 | RGWHTTPManager *_mgr) | |
334 | : cct(_conn->get_ctx()), conn(_conn), method(_method), resource(_resource), | |
335 | params(make_param_list(pp)), cb(bl), mgr(_mgr), | |
336 | req(cct, method.c_str(), conn->get_url(), &cb, NULL, NULL) | |
337 | { | |
338 | init_common(extra_headers); | |
339 | } | |
340 | ||
341 | RGWRESTSendResource::RGWRESTSendResource(RGWRESTConn *_conn, | |
342 | const string& _method, | |
343 | const string& _resource, | |
344 | param_vec_t& params, | |
345 | param_vec_t *extra_headers, | |
346 | RGWHTTPManager *_mgr) | |
347 | : cct(_conn->get_ctx()), conn(_conn), method(_method), resource(_resource), params(params), | |
348 | cb(bl), mgr(_mgr), req(cct, method.c_str(), conn->get_url(), &cb, NULL, NULL) | |
349 | { | |
350 | init_common(extra_headers); | |
351 | } | |
352 | ||
353 | void RGWRESTSendResource::init_common(param_vec_t *extra_headers) | |
354 | { | |
355 | populate_params(params, nullptr, conn->get_self_zonegroup()); | |
356 | ||
357 | if (extra_headers) { | |
358 | headers.insert(extra_headers->begin(), extra_headers->end()); | |
359 | } | |
360 | ||
361 | req.set_params(¶ms); | |
362 | } | |
363 | ||
364 | int RGWRESTSendResource::send(bufferlist& outbl) | |
365 | { | |
366 | req.set_outbl(outbl); | |
31f18b77 | 367 | int ret = req.send_request(&conn->get_key(), headers, resource, nullptr, mgr); |
7c673cae | 368 | if (ret < 0) { |
31f18b77 | 369 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
370 | return ret; |
371 | } | |
372 | ||
373 | string etag; | |
374 | map<string, string> attrs; | |
31f18b77 | 375 | return req.complete_request(etag, NULL, NULL, attrs); |
7c673cae FG |
376 | } |
377 | ||
378 | int RGWRESTSendResource::aio_send(bufferlist& outbl) | |
379 | { | |
380 | req.set_outbl(outbl); | |
31f18b77 | 381 | int ret = req.send_request(&conn->get_key(), headers, resource, nullptr, mgr); |
7c673cae | 382 | if (ret < 0) { |
31f18b77 | 383 | ldout(cct, 5) << __func__ << ": send_request() resource=" << resource << " returned ret=" << ret << dendl; |
7c673cae FG |
384 | return ret; |
385 | } | |
386 | ||
387 | return 0; | |
388 | } | |
389 |