1
0
mirror of https://github.com/ceph/ceph synced 2024-12-26 05:25:09 +00:00

rgw: flexible attr fields

Fixes: 
Instead of having a few hard coded attrs that are
special cased, make it more generic. This allows supporting
more header fields, such as cache-control, expires, etc.

Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
This commit is contained in:
Yehuda Sadeh 2012-10-08 16:13:04 -07:00
parent d4725c06ab
commit f4a0b2d926
8 changed files with 155 additions and 52 deletions

View File

@ -119,7 +119,6 @@ req_state::req_state(CephContext *_cct, struct RGWEnv *e) : cct(_cct), cio(NULL)
host = NULL;
method = NULL;
length = NULL;
content_type = NULL;
copy_source = NULL;
http_auth = NULL;
}

View File

@ -44,6 +44,11 @@ using ceph::crypto::MD5;
#define RGW_ATTR_BUCKETS RGW_ATTR_PREFIX "buckets"
#define RGW_ATTR_META_PREFIX RGW_ATTR_PREFIX "x-amz-meta-"
#define RGW_ATTR_CONTENT_TYPE RGW_ATTR_PREFIX "content_type"
#define RGW_ATTR_CACHE_CONTROL RGW_ATTR_PREFIX "cache_control"
#define RGW_ATTR_CONTENT_DISP RGW_ATTR_PREFIX "content_disposition"
#define RGW_ATTR_CONTENT_ENC RGW_ATTR_PREFIX "content_encoding"
#define RGW_ATTR_CONTENT_LANG RGW_ATTR_PREFIX "content_language"
#define RGW_ATTR_EXPIRES RGW_ATTR_PREFIX "expires"
#define RGW_ATTR_ID_TAG RGW_ATTR_PREFIX "idtag"
#define RGW_ATTR_SHADOW_OBJ RGW_ATTR_PREFIX "shadow_name"
#define RGW_ATTR_MANIFEST RGW_ATTR_PREFIX "manifest"
@ -565,7 +570,7 @@ struct req_state {
const char *method;
const char *length;
uint64_t content_length;
const char *content_type;
map<string, string> generic_attrs;
struct rgw_err err;
bool expect_cont;
bool header_ended;

View File

@ -416,6 +416,8 @@ int main(int argc, const char **argv)
common_init_finish(g_ceph_context);
rgw_tools_init(g_ceph_context);
rgw_rest_init();
curl_global_init(CURL_GLOBAL_ALL);

View File

@ -1165,6 +1165,7 @@ void RGWPutObj::execute()
bufferlist bl, aclbl;
map<string, bufferlist> attrs;
int len;
map<string, string>::iterator iter;
perfcounter->inc(l_rgw_put);
@ -1260,10 +1261,10 @@ void RGWPutObj::execute()
attrs[RGW_ATTR_USER_MANIFEST] = manifest_bl;
}
if (s->content_type) {
bl.clear();
bl.append(s->content_type, strlen(s->content_type) + 1);
attrs[RGW_ATTR_CONTENT_TYPE] = bl;
for (iter = s->generic_attrs.begin(); iter != s->generic_attrs.end(); ++iter) {
bufferlist& attrbl = attrs[iter->first];
const string& val = iter->second;
attrbl.append(val.c_str(), val.size() + 1);
}
rgw_get_request_metadata(s, attrs);
@ -1453,12 +1454,12 @@ int RGWCopyObj::init_common()
attrs[RGW_ATTR_ACL] = aclbl;
rgw_get_request_metadata(s, attrs);
if (s->content_type) {
bufferlist bl;
bl.append(s->content_type, strlen(s->content_type) + 1);
attrs[RGW_ATTR_CONTENT_TYPE] = bl;
map<string, string>::iterator iter;
for (iter = s->generic_attrs.begin(); iter != s->generic_attrs.end(); ++iter) {
bufferlist& attrbl = attrs[iter->first];
const string& val = iter->second;
attrbl.append(val.c_str(), val.size() + 1);
}
return 0;
}
@ -1617,6 +1618,7 @@ void RGWInitMultipart::execute()
bufferlist aclbl;
map<string, bufferlist> attrs;
rgw_obj obj;
map<string, string>::iterator iter;
if (get_params() < 0)
return;
@ -1628,10 +1630,10 @@ void RGWInitMultipart::execute()
attrs[RGW_ATTR_ACL] = aclbl;
if (s->content_type) {
bufferlist bl;
bl.append(s->content_type, strlen(s->content_type) + 1);
attrs[RGW_ATTR_CONTENT_TYPE] = bl;
for (iter = s->generic_attrs.begin(); iter != s->generic_attrs.end(); ++iter) {
bufferlist& attrbl = attrs[iter->first];
const string& val = iter->second;
attrbl.append(val.c_str(), val.size() + 1);
}
rgw_get_request_metadata(s, attrs);

View File

@ -17,6 +17,53 @@
#define dout_subsys ceph_subsys_rgw
struct rgw_http_attr {
const char *rgw_attr;
const char *http_attr;
};
/*
* mapping between rgw object attrs and output http fields
*/
static struct rgw_http_attr rgw_to_http_attr_list[] = {
{ RGW_ATTR_CONTENT_TYPE, "Content-Type"},
{ RGW_ATTR_CONTENT_LANG, "Content-Language"},
{ RGW_ATTR_EXPIRES, "Expires"},
{ RGW_ATTR_CACHE_CONTROL, "Cache-Control"},
{ RGW_ATTR_CONTENT_DISP, "Content-Disposition"},
{ RGW_ATTR_CONTENT_ENC, "Content-Encoding"},
{ NULL, NULL},
};
map<string, string> rgw_to_http_attrs;
void rgw_rest_init()
{
for (struct rgw_http_attr *attr = rgw_to_http_attr_list; attr->rgw_attr; attr++) {
rgw_to_http_attrs[attr->rgw_attr] = attr->http_attr;
}
}
struct generic_attr {
const char *http_header;
const char *rgw_attr;
};
/*
* mapping between http env fields and rgw object attrs
*/
struct generic_attr generic_attrs[] = {
{ "CONTENT_TYPE", RGW_ATTR_CONTENT_TYPE },
{ "HTTP_CONTENT_LANGUAGE", RGW_ATTR_CONTENT_LANG },
{ "HTTP_EXPIRES", RGW_ATTR_EXPIRES },
{ "HTTP_CACHE_CONTROL", RGW_ATTR_CACHE_CONTROL },
{ "HTTP_CONTENT_DISPOSITION", RGW_ATTR_CONTENT_DISP },
{ "HTTP_CONTENT_ENCODING", RGW_ATTR_CONTENT_ENC },
{ NULL, NULL },
};
static void dump_status(struct req_state *s, const char *status)
{
int r = s->cio->print("Status: %s\n", status);
@ -964,7 +1011,13 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO *cio)
s->content_length = atoll(s->length);
}
s->content_type = s->env->get("CONTENT_TYPE");
for (int i = 0; generic_attrs[i].http_header; i++) {
const char *env = s->env->get(generic_attrs[i].http_header);
if (env) {
s->generic_attrs[generic_attrs[i].rgw_attr] = env;
}
}
s->http_auth = s->env->get("HTTP_AUTHORIZATION");
if (g_conf->rgw_print_continue) {

View File

@ -5,6 +5,11 @@
#include "rgw_op.h"
#include "rgw_formats.h"
extern std::map<std::string, std::string> rgw_to_http_attrs;
extern void rgw_rest_init();
extern void rgw_flush_formatter_and_reset(struct req_state *s,
ceph::Formatter *formatter);

View File

@ -49,11 +49,28 @@ void rgw_get_errno_s3(rgw_html_errors *e , int err_no)
}
}
struct response_attr_param {
const char *param;
const char *http_attr;
};
static struct response_attr_param resp_attr_params[] = {
{"response-content-type", "Content-Type"},
{"response-content-language", "Content-Language"},
{"response-expires", "Expires"},
{"response-cache-control", "Cache-Control"},
{"response-content-disposition", "Content-Disposition"},
{"response-content-encoding", "Content-Encoding"},
{NULL, NULL},
};
int RGWGetObj_ObjStore_S3::send_response(bufferlist& bl)
{
string content_type_str;
const char *content_type = NULL;
string content_type_str;
int orig_ret = ret;
map<string, string> response_attrs;
map<string, string>::iterator riter;
if (ret)
goto done;
@ -77,36 +94,37 @@ int RGWGetObj_ObjStore_S3::send_response(bufferlist& bl)
}
}
if (s->args.has_response_modifier()) {
for (struct response_attr_param *p = resp_attr_params; p->param; p++) {
bool exists;
content_type_str = s->args.get("response-content-type", &exists);
if (exists)
content_type = content_type_str.c_str();
string val = s->args.get("response-content-language", &exists);
if (exists)
s->cio->print("Content-Language: %s\n", val.c_str());
val = s->args.get("response-expires", &exists);
if (exists)
s->cio->print("Expires: %s\n", val.c_str());
val = s->args.get("response-cache-control", &exists);
if (exists)
s->cio->print("Cache-Control: %s\n", val.c_str());
val = s->args.get("response-content-disposition", &exists);
if (exists)
s->cio->print("Content-Disposition: %s\n", val.c_str());
val = s->args.get("response-content-encoding", &exists);
if (exists)
s->cio->print("Content-Encoding: %s\n", val.c_str());
string val = s->args.get(p->param, &exists);
if (exists) {
if (strcmp(p->param, "response-content-type") != 0) {
response_attrs[p->http_attr] = val;
} else {
content_type_str = val;
content_type = content_type_str.c_str();
}
}
}
for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
const char *name = iter->first.c_str();
if (strncmp(name, RGW_ATTR_META_PREFIX, sizeof(RGW_ATTR_META_PREFIX)-1) == 0) {
name += sizeof(RGW_ATTR_PREFIX) - 1;
s->cio->print("%s: %s\r\n", name, iter->second.c_str());
} else if (!content_type && strcmp(name, RGW_ATTR_CONTENT_TYPE) == 0) {
content_type = iter->second.c_str();
}
const char *name = iter->first.c_str();
map<string, string>::iterator aiter = rgw_to_http_attrs.find(name);
if (aiter != rgw_to_http_attrs.end()) {
if (response_attrs.count(aiter->second) > 0) // was already overridden by a response param
continue;
if ((!content_type) && aiter->first.compare(RGW_ATTR_CONTENT_TYPE) == 0) { // special handling for content_type
content_type = iter->second.c_str();
continue;
}
response_attrs[aiter->second] = iter->second.c_str();
} else {
if (strncmp(name, RGW_ATTR_META_PREFIX, sizeof(RGW_ATTR_META_PREFIX)-1) == 0) {
name += sizeof(RGW_ATTR_PREFIX) - 1;
s->cio->print("%s: %s\r\n", name, iter->second.c_str());
}
}
}
}
@ -116,6 +134,11 @@ done:
set_req_state_err(s, ret);
dump_errno(s);
for (riter = response_attrs.begin(); riter != response_attrs.end(); ++riter) {
s->cio->print("%s: %s\n", riter->first.c_str(), riter->second.c_str());
}
if (!content_type)
content_type = "binary/octet-stream";
end_header(s, content_type);

View File

@ -297,14 +297,14 @@ int RGWPutObj_ObjStore_SWIFT::get_params()
supplied_etag = s->env->get("HTTP_ETAG");
if (!s->content_type) {
if (!s->generic_attrs.count(RGW_ATTR_CONTENT_TYPE)) {
dout(5) << "content type wasn't provided, trying to guess" << dendl;
const char *suffix = strrchr(s->object, '.');
if (suffix) {
suffix++;
if (*suffix) {
string suffix_str(suffix);
s->content_type = rgw_find_mime_by_ext(suffix_str);
s->generic_attrs[RGW_ATTR_CONTENT_TYPE] = rgw_find_mime_by_ext(suffix_str);
}
}
}
@ -433,6 +433,8 @@ int RGWGetObj_ObjStore_SWIFT::send_response(bufferlist& bl)
{
const char *content_type = NULL;
int orig_ret = ret;
map<string, string> response_attrs;
map<string, string>::iterator riter;
if (sent_header)
goto send_data;
@ -454,13 +456,20 @@ int RGWGetObj_ObjStore_SWIFT::send_response(bufferlist& bl)
}
for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
const char *name = iter->first.c_str();
if (strncmp(name, RGW_ATTR_META_PREFIX, sizeof(RGW_ATTR_META_PREFIX)-1) == 0) {
name += sizeof(RGW_ATTR_META_PREFIX) - 1;
s->cio->print("X-%s-Meta-%s: %s\r\n", (s->object ? "Object" : "Container"), name, iter->second.c_str());
} else if (!content_type && strcmp(name, RGW_ATTR_CONTENT_TYPE) == 0) {
content_type = iter->second.c_str();
}
const char *name = iter->first.c_str();
map<string, string>::iterator aiter = rgw_to_http_attrs.find(name);
if (aiter != rgw_to_http_attrs.end()) {
if (aiter->first.compare(RGW_ATTR_CONTENT_TYPE) == 0) { // special handling for content_type
content_type = iter->second.c_str();
continue;
}
response_attrs[aiter->second] = iter->second.c_str();
} else {
if (strncmp(name, RGW_ATTR_META_PREFIX, sizeof(RGW_ATTR_META_PREFIX)-1) == 0) {
name += sizeof(RGW_ATTR_META_PREFIX) - 1;
s->cio->print("X-%s-Meta-%s: %s\r\n", (s->object ? "Object" : "Container"), name, iter->second.c_str());
}
}
}
}
@ -470,6 +479,11 @@ int RGWGetObj_ObjStore_SWIFT::send_response(bufferlist& bl)
if (ret)
set_req_state_err(s, ret);
dump_errno(s);
for (riter = response_attrs.begin(); riter != response_attrs.end(); ++riter) {
s->cio->print("%s: %s\n", riter->first.c_str(), riter->second.c_str());
}
if (!content_type)
content_type = "binary/octet-stream";
end_header(s, content_type);