]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: flexible attr fields
authorYehuda Sadeh <yehuda@inktank.com>
Mon, 8 Oct 2012 23:13:04 +0000 (16:13 -0700)
committerYehuda Sadeh <yehuda@inktank.com>
Mon, 8 Oct 2012 23:14:17 +0000 (16:14 -0700)
Fixes: #3114
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>
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_main.cc
src/rgw/rgw_op.cc
src/rgw/rgw_rest.cc
src/rgw/rgw_rest.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_swift.cc

index 5acf80f60d6b2aeab76d601b9e46781b0a09e10b..efb3623ded48c83440cbac857ff8ddf89be560fd 100644 (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;
 }
index 76dbb26052992b27ce76a677b8e6eb066fee913e..f4a02eedcf4e37b6796f4778cb2da53431d49e68 100644 (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;
index 07b45c71436f6ac58ad7e0b2d9415bca5ed5a03d..50b05e5840d84d58ef0b9ba3838aeef338c679c6 100644 (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);
   
index d289b2249c24f890724ae220fa66fd5245dd9ed4..bf4de3f2ea842fd901572064066ef400b66efe19 100644 (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);
index 80a080b342d384229bbaef62cf2ea270875e7771..53bbeca8a8b45016fb968314a5316cc074c7e261 100644 (file)
 
 #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) {
index c225aa1490a75cc57644f354edff15e0f74da439..69056cb2a251bd4ea3001416ba5520645f3b9f06 100644 (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);
 
index 277cd9ac89f191808b8c7d890291c7586c3a50dc..995894b23976b15485ea7a358f7483eb86906054 100644 (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);
index 88fc3e300e139f606e622d84bad6792f9aff0b5c..d3d45e5525c318265f8a6eccdb84606d08895f0a 100644 (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);