1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
5 * Ceph - scalable distributed file system
7 * Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
16 #include "include/page.h"
20 #include "rgw_rest_s3.h"
21 #include "rgw_rest_metadata.h"
22 #include "rgw_client_io.h"
23 #include "rgw_mdlog_types.h"
24 #include "common/errno.h"
25 #include "common/strtol.h"
26 #include "rgw/rgw_b64.h"
27 #include "include/ceph_assert.h"
29 #define dout_context g_ceph_context
30 #define dout_subsys ceph_subsys_rgw
32 static inline void frame_metadata_key(req_state
*s
, string
& out
) {
34 string key
= s
->info
.args
.get("key", &exists
);
37 if (!s
->init_state
.url_bucket
.empty()) {
38 section
= s
->init_state
.url_bucket
;
47 out
+= string(":") + key
;
51 void RGWOp_Metadata_Get::execute() {
54 frame_metadata_key(s
, metadata_key
);
56 auto meta_mgr
= store
->ctl()->meta
.mgr
;
59 http_ret
= meta_mgr
->get(metadata_key
, s
->formatter
, s
->yield
);
61 dout(5) << "ERROR: can't get key: " << cpp_strerror(http_ret
) << dendl
;
68 void RGWOp_Metadata_Get_Myself::execute() {
71 owner_id
= s
->owner
.get_id().to_str();
72 s
->info
.args
.append("key", owner_id
);
74 return RGWOp_Metadata_Get::execute();
77 void RGWOp_Metadata_List::execute() {
79 ldout(s
->cct
, 16) << __func__
80 << " raw marker " << s
->info
.args
.get("marker")
84 marker
= s
->info
.args
.get("marker");
85 if (!marker
.empty()) {
86 marker
= rgw::from_base64(marker
);
88 ldout(s
->cct
, 16) << __func__
89 << " marker " << marker
<< dendl
;
91 marker
= std::string("");
94 bool max_entries_specified
;
95 string max_entries_str
=
96 s
->info
.args
.get("max-entries", &max_entries_specified
);
98 bool extended_response
= (max_entries_specified
); /* for backward compatibility, if max-entries is not specified
99 we will send the old response format */
100 uint64_t max_entries
= 0;
102 if (max_entries_specified
) {
104 max_entries
= (unsigned)strict_strtol(max_entries_str
.c_str(), 10, &err
);
106 dout(5) << "Error parsing max-entries " << max_entries_str
<< dendl
;
114 frame_metadata_key(s
, metadata_key
);
120 marker = "3:b55a9110:root::bu_9:head";
121 marker = "3:b9a8b2a6:root::sorry_janefonda_890:head";
122 marker = "3:bf885d8f:root::sorry_janefonda_665:head";
125 http_ret
= store
->ctl()->meta
.mgr
->list_keys_init(metadata_key
, marker
, &handle
);
127 dout(5) << "ERROR: can't get key: " << cpp_strerror(http_ret
) << dendl
;
134 if (extended_response
) {
135 s
->formatter
->open_object_section("result");
138 s
->formatter
->open_array_section("keys");
140 auto meta_mgr
= store
->ctl()->meta
.mgr
;
145 left
= (max_entries_specified
? max_entries
- count
: max
);
146 http_ret
= meta_mgr
->list_keys_next(handle
, left
, keys
, &truncated
);
148 dout(5) << "ERROR: lists_keys_next(): " << cpp_strerror(http_ret
)
153 for (list
<string
>::iterator iter
= keys
.begin(); iter
!= keys
.end();
155 s
->formatter
->dump_string("key", *iter
);
159 } while (truncated
&& left
> 0);
161 s
->formatter
->close_section();
163 if (extended_response
) {
164 encode_json("truncated", truncated
, s
->formatter
);
165 encode_json("count", count
, s
->formatter
);
168 rgw::to_base64(meta_mgr
->get_marker(handle
));
169 encode_json("marker", esc_marker
, s
->formatter
);
171 s
->formatter
->close_section();
173 meta_mgr
->list_keys_complete(handle
);
178 int RGWOp_Metadata_Put::get_data(bufferlist
& bl
) {
184 cl
= atoll(s
->length
);
186 data
= (char *)malloc(cl
+ 1);
190 read_len
= recv_body(s
, data
, cl
);
191 if (cl
!= (size_t)read_len
) {
192 dout(10) << "recv_body incomplete" << dendl
;
198 bl
.append(data
, read_len
);
200 int chunk_size
= CEPH_PAGE_SIZE
;
201 const char *enc
= s
->info
.env
->get("HTTP_TRANSFER_ENCODING");
202 if (!enc
|| strcmp(enc
, "chunked")) {
203 return -ERR_LENGTH_REQUIRED
;
205 data
= (char *)malloc(chunk_size
);
210 read_len
= recv_body(s
, data
, chunk_size
);
215 bl
.append(data
, read_len
);
216 } while (read_len
== chunk_size
);
223 static bool string_to_sync_type(const string
& sync_string
,
224 RGWMDLogSyncType
& type
) {
225 if (sync_string
.compare("update-by-version") == 0)
226 type
= APPLY_UPDATES
;
227 else if (sync_string
.compare("update-by-timestamp") == 0)
229 else if (sync_string
.compare("always") == 0)
236 void RGWOp_Metadata_Put::execute() {
240 http_ret
= get_data(bl
);
245 http_ret
= do_aws4_auth_completion();
250 frame_metadata_key(s
, metadata_key
);
252 RGWMDLogSyncType sync_type
= RGWMDLogSyncType::APPLY_ALWAYS
;
254 bool mode_exists
= false;
255 string mode_string
= s
->info
.args
.get("update-type", &mode_exists
);
257 bool parsed
= string_to_sync_type(mode_string
,
265 http_ret
= store
->ctl()->meta
.mgr
->put(metadata_key
, bl
, s
->yield
, sync_type
,
268 dout(5) << "ERROR: can't put key: " << cpp_strerror(http_ret
) << dendl
;
271 // translate internal codes into return header
272 if (http_ret
== STATUS_NO_APPLY
)
273 update_status
= "skipped";
274 else if (http_ret
== STATUS_APPLIED
)
275 update_status
= "applied";
278 void RGWOp_Metadata_Put::send_response() {
279 int http_return_code
= http_ret
;
280 if ((http_ret
== STATUS_NO_APPLY
) || (http_ret
== STATUS_APPLIED
))
281 http_return_code
= STATUS_NO_CONTENT
;
282 set_req_state_err(s
, http_return_code
);
284 stringstream ver_stream
;
285 ver_stream
<< "ver:" << ondisk_version
.ver
286 <<",tag:" << ondisk_version
.tag
;
287 dump_header_if_nonempty(s
, "RGWX_UPDATE_STATUS", update_status
);
288 dump_header_if_nonempty(s
, "RGWX_UPDATE_VERSION", ver_stream
.str());
292 void RGWOp_Metadata_Delete::execute() {
295 frame_metadata_key(s
, metadata_key
);
296 http_ret
= store
->ctl()->meta
.mgr
->remove(metadata_key
, s
->yield
);
298 dout(5) << "ERROR: can't remove key: " << cpp_strerror(http_ret
) << dendl
;
304 RGWOp
*RGWHandler_Metadata::op_get() {
305 if (s
->info
.args
.exists("myself"))
306 return new RGWOp_Metadata_Get_Myself
;
307 if (s
->info
.args
.exists("key"))
308 return new RGWOp_Metadata_Get
;
310 return new RGWOp_Metadata_List
;
313 RGWOp
*RGWHandler_Metadata::op_put() {
314 return new RGWOp_Metadata_Put
;
317 RGWOp
*RGWHandler_Metadata::op_delete() {
318 return new RGWOp_Metadata_Delete
;