]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
polymorphic error codes.
authorMarcus Watts <mwatts@redhat.com>
Tue, 3 Nov 2015 00:43:36 +0000 (19:43 -0500)
committerPritha Srivastava <prsrivas@redhat.com>
Tue, 16 May 2017 04:35:56 +0000 (10:05 +0530)
make set_req_state_err a method of req_state

get rid of params.perr; it's never used

rgw - polymorphic error object.

polymorphic error object: this way sts, which has additional error fields,
and its own xml format for how errors should be produced, can overload
the base rgw_err class.

STL fixup: use real mappings for error mappings, not a linear search.
insubstantiate error mappings exactly once in src/rgw/rgw_common.cc, instead
of multiple copies from every source file that includes src/rgw/rgw_http_errors.h.

remove dump_errno(s, err) - it was never used, and the code looked bogus.

move rgw_http_error_to_errno from header to rgw_rest_client.cc,
the only place it's used.
move rgw_http_status_code and http_codes to rgw_rest.cc,
the only place it's used.

base class (rgw_err) implements s3 errors; swift & sts errors use
the base class and overlay their own additional error codes to
the ones recognized by the base class.

For a while, I was trying to just have a "generic" abort_early() that
used dump_more.  Now, I have an op aware form that works the old way.
I would like the http routines to known less about "op" structures,
which is why I'm making this distinction.

Splitting up generic and s3 flavors of some things:
rgw_rest_init() - split into s3 and generic forms.
end_header: s3 vs generic forms: generic form uses dump_more.
abort_early: s3 vs generic forms: generic form uses dump_more, error_content.

And fixing some mistakes from the merge:
Fixup: should not have deleted dump_errno() local storage forms.
Fixup:RGWRESTFlusher  - take a dump_more to make it generic.
Fixup: need RGWRESTOp::send_response()

Move swift_err up; use it in bulkdelete_respond
I Think I don't need s->prot_flags when using swift_err.

Signed-off-by: Marcus Watts <mwatts@redhat.com>
25 files changed:
src/rgw/librgw.cc
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_cr_rados.cc
src/rgw/rgw_http_errors.h
src/rgw/rgw_log.cc
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_process.cc
src/rgw/rgw_rados.cc
src/rgw/rgw_rados.h
src/rgw/rgw_rest.cc
src/rgw/rgw_rest.h
src/rgw/rgw_rest_config.cc
src/rgw/rgw_rest_log.cc
src/rgw/rgw_rest_metadata.cc
src/rgw/rgw_rest_opstate.cc
src/rgw/rgw_rest_realm.cc
src/rgw/rgw_rest_replica_log.cc
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h
src/rgw/rgw_rest_swift.cc
src/rgw/rgw_rest_swift.h
src/rgw/rgw_swift_auth.cc
src/rgw/rgw_tools.cc

index f7bb502fa0060b70184dcf49b6ab9ab2fea51afc..befceea3858d19de9ece0e603b90b8bf90ff3ee5 100644 (file)
@@ -312,7 +312,7 @@ namespace rgw {
                 (op ? op->name() : "unknown"), olog);
     }
 
-    int http_ret = s->err.http_ret;
+    int http_ret = s->err->http_ret;
 
     req->log_format(s, "http status=%d", http_ret);
 
@@ -321,7 +321,7 @@ namespace rgw {
            << http_ret
            << " ======" << dendl;
 
-    return (ret < 0 ? ret : s->err.ret);
+    return (ret < 0 ? ret : s->err->ret);
   } /* process_request */
 
   int RGWLibProcess::start_request(RGWLibContinuedReq* req)
@@ -414,7 +414,7 @@ namespace rgw {
     req->exec_start();
 
   done:
-    return (ret < 0 ? ret : s->err.ret);
+    return (ret < 0 ? ret : s->err->ret);
   }
 
   int RGWLibProcess::finish_request(RGWLibContinuedReq* req)
index fbff872ee21de3443aa7c997a246f5f331e1e807..71e424878023248edd161a63e3382836ded3ed40 100644 (file)
@@ -15,6 +15,7 @@
 #include "rgw_acl.h"
 #include "rgw_string.h"
 #include "rgw_rados.h"
+#include "rgw_http_errors.h"
 
 #include "common/ceph_crypto.h"
 #include "common/armor.h"
@@ -41,6 +42,75 @@ PerfCounters *perfcounter = NULL;
 
 const uint32_t RGWBucketInfo::NUM_SHARDS_BLIND_BUCKET(UINT32_MAX);
 
+rgw_http_errors rgw_http_s3_errors({
+    { 0, {200, "" }},
+    { STATUS_CREATED, {201, "Created" }},
+    { STATUS_ACCEPTED, {202, "Accepted" }},
+    { STATUS_NO_CONTENT, {204, "NoContent" }},
+    { STATUS_PARTIAL_CONTENT, {206, "" }},
+    { ERR_PERMANENT_REDIRECT, {301, "PermanentRedirect" }},
+    { ERR_WEBSITE_REDIRECT, {301, "WebsiteRedirect" }},
+    { STATUS_REDIRECT, {303, "" }},
+    { ERR_NOT_MODIFIED, {304, "NotModified" }},
+    { EINVAL, {400, "InvalidArgument" }},
+    { ERR_INVALID_REQUEST, {400, "InvalidRequest" }},
+    { ERR_INVALID_DIGEST, {400, "InvalidDigest" }},
+    { ERR_BAD_DIGEST, {400, "BadDigest" }},
+    { ERR_INVALID_BUCKET_NAME, {400, "InvalidBucketName" }},
+    { ERR_INVALID_OBJECT_NAME, {400, "InvalidObjectName" }},
+    { ERR_UNRESOLVABLE_EMAIL, {400, "UnresolvableGrantByEmailAddress" }},
+    { ERR_INVALID_PART, {400, "InvalidPart" }},
+    { ERR_INVALID_PART_ORDER, {400, "InvalidPartOrder" }},
+    { ERR_REQUEST_TIMEOUT, {400, "RequestTimeout" }},
+    { ERR_TOO_LARGE, {400, "EntityTooLarge" }},
+    { ERR_TOO_SMALL, {400, "EntityTooSmall" }},
+    { ERR_TOO_MANY_BUCKETS, {400, "TooManyBuckets" }},
+    { ERR_MALFORMED_XML, {400, "MalformedXML" }},
+    { ERR_AMZ_CONTENT_SHA256_MISMATCH, {400, "XAmzContentSHA256Mismatch" }},
+    { ERR_LENGTH_REQUIRED, {411, "MissingContentLength" }},
+    { EACCES, {403, "AccessDenied" }},
+    { EPERM, {403, "AccessDenied" }},
+    { ERR_SIGNATURE_NO_MATCH, {403, "SignatureDoesNotMatch" }},
+    { ERR_INVALID_ACCESS_KEY, {403, "InvalidAccessKeyId" }},
+    { ERR_USER_SUSPENDED, {403, "UserSuspended" }},
+    { ERR_REQUEST_TIME_SKEWED, {403, "RequestTimeTooSkewed" }},
+    { ERR_QUOTA_EXCEEDED, {403, "QuotaExceeded" }},
+    { ENOENT, {404, "NoSuchKey" }},
+    { ERR_NO_SUCH_BUCKET, {404, "NoSuchBucket" }},
+    { ERR_NO_SUCH_WEBSITE_CONFIGURATION, {404, "NoSuchWebsiteConfiguration" }},
+    { ERR_NO_SUCH_UPLOAD, {404, "NoSuchUpload" }},
+    { ERR_NOT_FOUND, {404, "Not Found"}},
+    { ERR_NO_SUCH_LC, {404, "NoSuchLifecycleConfiguration"}},
+    { ERR_METHOD_NOT_ALLOWED, {405, "MethodNotAllowed" }},
+    { ETIMEDOUT, {408, "RequestTimeout" }},
+    { EEXIST, {409, "BucketAlreadyExists" }},
+    { ERR_USER_EXIST, {409, "UserAlreadyExists" }},
+    { ERR_EMAIL_EXIST, {409, "EmailExists" }},
+    { ERR_KEY_EXIST, {409, "KeyExists"}},
+    { ERR_INVALID_SECRET_KEY, {400, "InvalidSecretKey"}},
+    { ERR_INVALID_KEY_TYPE, {400, "InvalidKeyType"}},
+    { ERR_INVALID_CAP, {400, "InvalidCapability"}},
+    { ERR_INVALID_TENANT_NAME, {400, "InvalidTenantName" }},
+    { ENOTEMPTY, {409, "BucketNotEmpty" }},
+    { ERR_PRECONDITION_FAILED, {412, "PreconditionFailed" }},
+    { ERANGE, {416, "InvalidRange" }},
+    { ERR_UNPROCESSABLE_ENTITY, {422, "UnprocessableEntity" }},
+    { ERR_LOCKED, {423, "Locked" }},
+    { ERR_INTERNAL_ERROR, {500, "InternalError" }},
+    { ERR_NOT_IMPLEMENTED, {501, "NotImplemented" }},
+    { ERR_SERVICE_UNAVAILABLE, {503, "ServiceUnavailable"}},
+});
+
+rgw_http_errors rgw_http_swift_errors({
+    { EACCES, {403, "AccessDenied" }},
+    { EPERM, {401, "AccessDenied" }},
+    { ERR_USER_SUSPENDED, {401, "UserSuspended" }},
+    { ERR_INVALID_UTF8, {412, "Invalid UTF8" }},
+    { ERR_BAD_URL, {412, "Bad URL" }},
+    { ERR_NOT_SLO_MANIFEST, {400, "Not an SLO manifest" }},
+    { ERR_QUOTA_EXCEEDED, {413, "QuotaExceeded" }},
+});
+
 int rgw_perf_start(CephContext *cct)
 {
   PerfCountersBuilder plb(cct, cct->_conf->name.to_str(), l_rgw_first, l_rgw_last);
@@ -79,17 +149,11 @@ void rgw_perf_stop(CephContext *cct)
 using namespace ceph::crypto;
 
 rgw_err::
-rgw_err()
+rgw_err(req_state *s) : s(*s)
 {
   clear();
 }
 
-rgw_err::
-rgw_err(int http, const std::string& s3)
-    : http_ret(http), ret(0), s3_code(s3)
-{
-}
-
 void rgw_err::
 clear()
 {
@@ -184,7 +248,7 @@ void req_info::rebuild_from(req_info& src)
 
 
 req_state::req_state(CephContext* _cct, RGWEnv* e, RGWUserInfo* u)
-  : cct(_cct), cio(NULL), op(OP_UNKNOWN), user(u), has_acl_header(false),
+  : cct(_cct), cio(NULL), op(OP_UNKNOWN), err(0), user(u), has_acl_header(false),
     info(_cct, e)
 {
   enable_ops_log = e->conf.enable_ops_log;
@@ -220,10 +284,42 @@ req_state::req_state(CephContext* _cct, RGWEnv* e, RGWUserInfo* u)
 
 req_state::~req_state() {
   delete formatter;
+  delete err;
   delete bucket_acl;
   delete object_acl;
 }
 
+void set_req_state_err(struct rgw_err& err,    /* out */
+                       int err_no,             /* in  */
+                       const int prot_flags)   /* in  */
+{
+  if (err_no < 0)
+    err_no = -err_no;
+
+  err.ret = -err_no;
+  err.is_website_redirect |= (prot_flags & RGW_REST_WEBSITE)
+               && err_no == ERR_WEBSITE_REDIRECT && err.is_clear();
+  if (err.set_rgw_err(err_no))
+    return;
+  dout(0) << "WARNING: set_req_state_err err_no=" << err_no
+       << " resorting to 500" << dendl;
+
+  err.http_ret = 500;
+  err.s3_code = "UnknownError";
+}
+
+void req_state::set_req_state_err(int err_no)
+{
+  if (!err) err = new rgw_err(this);
+  ::set_req_state_err(*err, err_no, prot_flags);
+}
+
+void req_state::set_req_state_err(int err_no, const string &err_msg)
+{
+   set_req_state_err(err_no);
+   err->message = err_msg;
+}
+
 struct str_len {
   const char *str;
   int len;
@@ -299,6 +395,37 @@ std::ostream& operator<<(std::ostream& oss, const rgw_err &err)
   return oss;
 }
 
+void rgw_err::dump() const
+{
+  if (s.format != RGW_FORMAT_HTML)
+    s.formatter->open_object_section("Error");
+  if (!s3_code.empty())
+    s.formatter->dump_string("Code", s3_code);
+  if (!message.empty())
+    s.formatter->dump_string("Message", message);
+  if (!s.bucket_name.empty())  // TODO: connect to expose_bucket
+    s.formatter->dump_string("BucketName", s.bucket_name);
+  if (!s.trans_id.empty())     // TODO: connect to expose_bucket or another toggle
+    s.formatter->dump_string("RequestId", s.trans_id);
+  s.formatter->dump_string("HostId", s.host_id);
+  if (s.format != RGW_FORMAT_HTML)
+    s.formatter->close_section();
+}
+
+bool rgw_err::set_rgw_err(int err_no)
+{
+  rgw_http_errors::const_iterator r;
+
+  r = rgw_http_s3_errors.find(err_no);
+  if (r != rgw_http_s3_errors.end()) {
+    if (!is_website_redirect)
+      http_ret = r->second.first;
+    s3_code = r->second.second;
+    return true;
+  }
+  return false;
+}
+
 string rgw_string_unquote(const string& s)
 {
   if (s[0] != '"' || s.size() < 2)
index 5ad7637b44c731895891967aac99a8e4a6b5e3cf..37e25a0840cf0f0d8d91ab2fd5fba18460eff0e2 100644 (file)
@@ -202,6 +202,8 @@ using ceph::crypto::MD5;
 #define UINT32_MAX (0xffffffffu)
 #endif
 
+struct req_state;
+
 typedef void *RGWAccessHandle;
 
 
@@ -262,13 +264,17 @@ enum RGWObjCategory {
 
 /** Store error returns for output at a different point in the program */
 struct rgw_err {
-  rgw_err();
-  rgw_err(int http, const std::string &s3);
+  rgw_err(req_state *s);
+  virtual ~rgw_err() { };
   void clear();
   bool is_clear() const;
   bool is_err() const;
   friend std::ostream& operator<<(std::ostream& oss, const rgw_err &err);
+  virtual void dump() const;
+  virtual bool set_rgw_err(int);
 
+  req_state &s;
+  bool is_website_redirect;
   int http_ret;
   int ret;
   std::string s3_code;
@@ -1338,8 +1344,6 @@ struct RGWStorageStats
   void dump(Formatter *f) const;
 };
 
-struct req_state;
-
 class RGWEnv;
 
 /* Namespaced forward declarations. */
@@ -1701,7 +1705,7 @@ struct req_state {
   const char *length;
   int64_t content_length;
   map<string, string> generic_attrs;
-  struct rgw_err err;
+  rgw_err *err;
   bool expect_cont;
   bool header_ended;
   uint64_t obj_size;
@@ -1805,7 +1809,12 @@ struct req_state {
 
   req_state(CephContext* _cct, RGWEnv* e, RGWUserInfo* u);
   ~req_state();
+
+  void set_req_state_err(int err_no);
+  void set_req_state_err(int err_no, const string &err_msg);
+  bool is_err() const { return err && err->is_err(); }
 };
+void set_req_state_err(struct rgw_err&, int, const int);
 
 /** Store basic data on bucket */
 struct RGWBucketEnt {
index 353deaa67ecfbf2a2aca15b1a2b5f45539476344..0e0be84c82ca4fa075f9f6df8c7c035b61e629fc 100644 (file)
@@ -541,7 +541,6 @@ int RGWAsyncFetchRemoteObj::_send_request()
                        &key.instance, /* string *version_id, */
                        NULL, /* string *ptag, */
                        NULL, /* string *petag, */
-                       NULL, /* struct rgw_err *err, */
                        NULL, /* void (*progress_cb)(off_t, void *), */
                        NULL); /* void *progress_data*); */
 
index a0423bb48fd3c9be08e9ae7e3128e660903898af..e2aec310c88b331c2bedbd4d291d076a021501ba 100644 (file)
 
 #include "rgw_common.h"
 
-struct rgw_http_errors {
-  int err_no;
-  int http_ret;
-  const char *s3_code;
-};
+typedef const std::map<int,const std::pair<int, const char*>> rgw_http_errors;
 
-const static struct rgw_http_errors RGW_HTTP_ERRORS[] = {
-    { 0, 200, "" },
-    { STATUS_CREATED, 201, "Created" },
-    { STATUS_ACCEPTED, 202, "Accepted" },
-    { STATUS_NO_CONTENT, 204, "NoContent" },
-    { STATUS_PARTIAL_CONTENT, 206, "" },
-    { ERR_PERMANENT_REDIRECT, 301, "PermanentRedirect" },
-    { ERR_WEBSITE_REDIRECT, 301, "WebsiteRedirect" },
-    { STATUS_REDIRECT, 303, "" },
-    { ERR_NOT_MODIFIED, 304, "NotModified" },
-    { EINVAL, 400, "InvalidArgument" },
-    { ERR_INVALID_REQUEST, 400, "InvalidRequest" },
-    { ERR_INVALID_DIGEST, 400, "InvalidDigest" },
-    { ERR_BAD_DIGEST, 400, "BadDigest" },
-    { ERR_INVALID_BUCKET_NAME, 400, "InvalidBucketName" },
-    { ERR_INVALID_OBJECT_NAME, 400, "InvalidObjectName" },
-    { ERR_UNRESOLVABLE_EMAIL, 400, "UnresolvableGrantByEmailAddress" },
-    { ERR_INVALID_PART, 400, "InvalidPart" },
-    { ERR_INVALID_PART_ORDER, 400, "InvalidPartOrder" },
-    { ERR_REQUEST_TIMEOUT, 400, "RequestTimeout" },
-    { ERR_TOO_LARGE, 400, "EntityTooLarge" },
-    { ERR_TOO_SMALL, 400, "EntityTooSmall" },
-    { ERR_TOO_MANY_BUCKETS, 400, "TooManyBuckets" },
-    { ERR_MALFORMED_XML, 400, "MalformedXML" },
-    { ERR_AMZ_CONTENT_SHA256_MISMATCH, 400, "XAmzContentSHA256Mismatch" },
-    { ERR_MALFORMED_DOC, 400, "MalformedPolicyDocument" },
-    { ERR_LENGTH_REQUIRED, 411, "MissingContentLength" },
-    { EACCES, 403, "AccessDenied" },
-    { EPERM, 403, "AccessDenied" },
-    { ERR_SIGNATURE_NO_MATCH, 403, "SignatureDoesNotMatch" },
-    { ERR_INVALID_ACCESS_KEY, 403, "InvalidAccessKeyId" },
-    { ERR_USER_SUSPENDED, 403, "UserSuspended" },
-    { ERR_REQUEST_TIME_SKEWED, 403, "RequestTimeTooSkewed" },
-    { ERR_QUOTA_EXCEEDED, 403, "QuotaExceeded" },
-    { ENOENT, 404, "NoSuchKey" },
-    { ERR_NO_SUCH_BUCKET, 404, "NoSuchBucket" },
-    { ERR_NO_SUCH_WEBSITE_CONFIGURATION, 404, "NoSuchWebsiteConfiguration" },
-    { ERR_NO_SUCH_UPLOAD, 404, "NoSuchUpload" },
-    { ERR_NOT_FOUND, 404, "Not Found"},
-    { ERR_NO_SUCH_LC, 404, "NoSuchLifecycleConfiguration"},
-    { ERR_NO_ROLE_FOUND, 404, "NoSuchEntity"},
-    { ERR_METHOD_NOT_ALLOWED, 405, "MethodNotAllowed" },
-    { ETIMEDOUT, 408, "RequestTimeout" },
-    { EEXIST, 409, "BucketAlreadyExists" },
-    { ERR_USER_EXIST, 409, "UserAlreadyExists" },
-    { ERR_EMAIL_EXIST, 409, "EmailExists" },
-    { ERR_KEY_EXIST, 409, "KeyExists"},
-    { ERR_ROLE_EXISTS, 409, "EntityAlreadyExists"},
-    { ERR_DELETE_CONFLICT, 409, "DeleteConflict"},
-    { ERR_INVALID_SECRET_KEY, 400, "InvalidSecretKey"},
-    { ERR_INVALID_KEY_TYPE, 400, "InvalidKeyType"},
-    { ERR_INVALID_CAP, 400, "InvalidCapability"},
-    { ERR_INVALID_TENANT_NAME, 400, "InvalidTenantName" },
-    { ENOTEMPTY, 409, "BucketNotEmpty" },
-    { ERR_PRECONDITION_FAILED, 412, "PreconditionFailed" },
-    { ERANGE, 416, "InvalidRange" },
-    { ERR_UNPROCESSABLE_ENTITY, 422, "UnprocessableEntity" },
-    { ERR_LOCKED, 423, "Locked" },
-    { ERR_INTERNAL_ERROR, 500, "InternalError" },
-    { ERR_NOT_IMPLEMENTED, 501, "NotImplemented" },
-    { ERR_SERVICE_UNAVAILABLE, 503, "ServiceUnavailable"}
-};
-
-const static struct rgw_http_errors RGW_HTTP_SWIFT_ERRORS[] = {
-    { EACCES, 403, "AccessDenied" },
-    { EPERM, 401, "AccessDenied" },
-    { ERR_USER_SUSPENDED, 401, "UserSuspended" },
-    { ERR_INVALID_UTF8, 412, "Invalid UTF8" },
-    { ERR_BAD_URL, 412, "Bad URL" },
-    { ERR_NOT_SLO_MANIFEST, 400, "Not an SLO manifest" },
-    { ERR_QUOTA_EXCEEDED, 413, "QuotaExceeded" }
-};
-
-struct rgw_http_status_code {
-  int code;
-  const char *name;
-};
-
-const static struct rgw_http_status_code http_codes[] = {
-  { 100, "Continue" },
-  { 200, "OK" },
-  { 201, "Created" },
-  { 202, "Accepted" },
-  { 204, "No Content" },
-  { 205, "Reset Content" },
-  { 206, "Partial Content" },
-  { 207, "Multi Status" },
-  { 208, "Already Reported" },
-  { 300, "Multiple Choices" },
-  { 301, "Moved Permanently" },
-  { 302, "Found" },
-  { 303, "See Other" },
-  { 304, "Not Modified" },
-  { 305, "User Proxy" },
-  { 306, "Switch Proxy" },
-  { 307, "Temporary Redirect" },
-  { 308, "Permanent Redirect" },
-  { 400, "Bad Request" },
-  { 401, "Unauthorized" },
-  { 402, "Payment Required" },
-  { 403, "Forbidden" },
-  { 404, "Not Found" },
-  { 405, "Method Not Allowed" },
-  { 406, "Not Acceptable" },
-  { 407, "Proxy Authentication Required" },
-  { 408, "Request Timeout" },
-  { 409, "Conflict" },
-  { 410, "Gone" },
-  { 411, "Length Required" },
-  { 412, "Precondition Failed" },
-  { 413, "Request Entity Too Large" },
-  { 414, "Request-URI Too Long" },
-  { 415, "Unsupported Media Type" },
-  { 416, "Requested Range Not Satisfiable" },
-  { 417, "Expectation Failed" },
-  { 422, "Unprocessable Entity" },
-  { 500, "Internal Server Error" },
-  { 501, "Not Implemented" },
-  { 0, NULL },
-};
-
-#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
-
-static inline const struct rgw_http_errors *search_err(int err_no, const struct rgw_http_errors *errs, int len)
-{
-  for (int i = 0; i < len; ++i, ++errs) {
-    if (err_no == errs->err_no)
-      return errs;
-  }
-  return NULL;
-}
+extern rgw_http_errors rgw_http_s3_errors;
 
+extern rgw_http_errors rgw_http_swift_errors;
 
 static inline int rgw_http_error_to_errno(int http_err)
 {
index 153ddb060d708cd55a15b26fadbc357b20bf038d..6fc90372b6e75ac9c4d5102fe73bccd70451f085 100644 (file)
@@ -203,8 +203,8 @@ static void log_usage(struct req_state *s, const string& op_name)
       user = s->user->user_id;
   }
 
-  bool error = s->err.is_err();
-  if (error && s->err.http_ret == 404) {
+  bool error = s->err->is_err();
+  if (error && s->err->http_ret == 404) {
     bucket_name = "-"; /* bucket not found, use the invalid '-' as bucket name */
   }
 
@@ -218,7 +218,7 @@ static void log_usage(struct req_state *s, const string& op_name)
   rgw_usage_data data(bytes_sent, bytes_received);
 
   data.ops = 1;
-  if (!error)
+  if (!s->is_err())
     data.successful_ops = 1;
 
   entry.add(op_name, data);
@@ -316,7 +316,7 @@ int rgw_log_op(RGWRados *store, RGWREST* const rest, struct req_state *s,
     ldout(s->cct, 5) << "nothing to log for operation" << dendl;
     return -EINVAL;
   }
-  if (s->err.ret == -ERR_NO_SUCH_BUCKET) {
+  if (s->err->ret == -ERR_NO_SUCH_BUCKET) {
     if (!s->cct->_conf->rgw_log_nonexistent_bucket) {
       ldout(s->cct, 5) << "bucket " << s->bucket << " doesn't exist, not logging" << dendl;
       return 0;
@@ -374,14 +374,14 @@ int rgw_log_op(RGWRados *store, RGWREST* const rest, struct req_state *s,
   entry.total_time = ceph_clock_now() - s->time;
   entry.bytes_sent = bytes_sent;
   entry.bytes_received = bytes_received;
-  if (s->err.http_ret) {
+  if (s->err->http_ret) {
     char buf[16];
-    snprintf(buf, sizeof(buf), "%d", s->err.http_ret);
+    snprintf(buf, sizeof(buf), "%d", s->err->http_ret);
     entry.http_status = buf;
   } else
     entry.http_status = "200"; // default
 
-  entry.error_code = s->err.s3_code;
+  entry.error_code = s->err->s3_code;
   entry.bucket_id = bucket_id;
 
   bufferlist bl;
index 844b1dad5b020fdd3aedea13a20b18579f9caaca..7278283ddb180ce8ead1386d3021719f9053ab7d 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional.hpp>
+#include <boost/utility/in_place_factory.hpp>
+#include <boost/bind.hpp>
 
 #include "common/Clock.h"
 #include "common/armor.h"
@@ -241,7 +243,6 @@ static int get_obj_attrs(RGWRados *store, struct req_state *s, rgw_obj& obj, map
   RGWRados::Object::Read read_op(&op_target);
 
   read_op.params.attrs = &attrs;
-  read_op.params.perr = &s->err;
 
   return read_op.prepare();
 }
@@ -792,6 +793,15 @@ bool RGWOp::generate_cors_headers(string& origin, string& method, string& header
   return true;
 }
 
+/**
+ * Return a callable that can invoke dump_access_control().
+ */
+
+boost::function<void()> RGWOp::dump_access_control_f()
+{
+  return boost::bind(dump_access_control, s, this);
+}
+
 int RGWGetObj::read_user_manifest_part(rgw_bucket& bucket,
                                        const rgw_bucket_dir_entry& ent,
                                        RGWAccessControlPolicy * const bucket_policy,
@@ -825,7 +835,6 @@ int RGWGetObj::read_user_manifest_part(rgw_bucket& bucket,
   read_op.conds.if_match = ent.meta.etag.c_str();
   read_op.params.attrs = &attrs;
   read_op.params.obj_size = &obj_size;
-  read_op.params.perr = &s->err;
 
   op_ret = read_op.prepare();
   if (op_ret < 0)
@@ -1385,7 +1394,6 @@ void RGWGetObj::execute()
   read_op.params.attrs = &attrs;
   read_op.params.lastmod = &lastmod;
   read_op.params.obj_size = &s->obj_size;
-  read_op.params.perr = &s->err;
 
   op_ret = read_op.prepare();
   if (op_ret < 0)
@@ -4097,7 +4105,6 @@ void RGWCopyObj::execute()
                           (version_id.empty() ? NULL : &version_id),
                           &s->req_id, /* use req_id as tag */
                           &etag,
-                          &s->err,
                           copy_obj_progress_cb, (void *)this
     );
 }
index 1fcf4c30120f4fe63e99689afb67e9e1f4c5c0f5..827ae1c6c1acb274ff1556f0f5c786a69c406901 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <boost/optional.hpp>
 #include <boost/utility/in_place_factory.hpp>
+#include <boost/function.hpp>
 
 #include "common/armor.h"
 #include "common/mime.h"
@@ -172,6 +173,8 @@ public:
   virtual uint32_t op_mask() { return 0; }
 
   virtual int error_handler(int err_no, string *error_content);
+
+  boost::function<void()> dump_access_control_f();
 };
 
 class RGWGetObj : public RGWOp {
index 6fbf2fdb594f005b5fdcb63a1457a96db1dc7327..333ee1ef3fdac74df4f0388dd73d0b52d7ba3955 100644 (file)
@@ -151,6 +151,7 @@ int process_request(RGWRados* const store,
                                                auth_registry,
                                                frontend_prefix,
                                                client_io, &mgr, &init_error);
+  if (!s->err) s->err = new rgw_err(s);
   if (init_error != 0) {
     abort_early(s, NULL, init_error, NULL);
     goto done;
@@ -216,7 +217,7 @@ done:
     rgw_log_op(store, rest, s, (op ? op->name() : "unknown"), olog);
   }
 
-  int http_ret = s->err.http_ret;
+  int http_ret = s->err->http_ret;
   int op_ret = 0;
   if (op) {
     op_ret = op->get_ret();
@@ -235,5 +236,5 @@ done:
          << " ======"
          << dendl;
 
-  return (ret < 0 ? ret : s->err.ret);
+  return (ret < 0 ? ret : s->err->ret);
 } /* process_request */
index 562b067beb23530d8de9b0aba5aa85aed9df08c8..f3fb6dc2ea3f4a85308a0163171681bc4d48b72b 100644 (file)
@@ -6271,7 +6271,6 @@ int RGWRados::swift_versioning_copy(RGWObjectCtx& obj_ctx,
                NULL, /* string *version_id */
                NULL, /* string *ptag */
                NULL, /* string *petag */
-               NULL, /* struct rgw_err *err */
                NULL, /* void (*progress_cb)(off_t, void *) */
                NULL); /* void *progress_data */
   if (r == -ECANCELED || r == -ENOENT) {
@@ -6361,7 +6360,6 @@ int RGWRados::swift_versioning_restore(RGWObjectCtx& obj_ctx,
                        nullptr,       /* string *version_id */
                        nullptr,       /* string *ptag */
                        nullptr,       /* string *petag */
-                       nullptr,       /* struct rgw_err *err */
                        nullptr,       /* void (*progress_cb)(off_t, void *) */
                        nullptr);      /* void *progress_data */
     if (ret == -ECANCELED || ret == -ENOENT) {
@@ -7006,7 +7004,7 @@ int RGWRados::rewrite_obj(RGWBucketInfo& dest_bucket_info, rgw_obj& obj)
   }
 
   return copy_obj_data(rctx, dest_bucket_info, read_op, obj_size - 1, obj, obj, max_chunk_size, NULL, mtime, attrset,
-                       RGW_OBJ_CATEGORY_MAIN, 0, real_time(), NULL, NULL, NULL, NULL);
+                       RGW_OBJ_CATEGORY_MAIN, 0, real_time(), NULL, NULL, NULL);
 }
 
 struct obj_time_weight {
@@ -7225,7 +7223,6 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx,
                string *version_id,
                string *ptag,
                ceph::buffer::list *petag,
-               struct rgw_err *err,
                void (*progress_cb)(off_t, void *),
                void *progress_data)
 {
@@ -7523,7 +7520,6 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
                string *version_id,
                string *ptag,
                ceph::buffer::list *petag,
-               struct rgw_err *err,
                void (*progress_cb)(off_t, void *),
                void *progress_data)
 {
@@ -7553,7 +7549,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
                dest_obj, src_obj, dest_bucket_info, src_bucket_info, src_mtime, mtime, mod_ptr,
                unmod_ptr, high_precision_time,
                if_match, if_nomatch, attrs_mod, copy_if_newer, attrs, category,
-               olh_epoch, delete_at, version_id, ptag, petag, err, progress_cb, progress_data);
+               olh_epoch, delete_at, version_id, ptag, petag, progress_cb, progress_data);
   }
 
   map<string, bufferlist> src_attrs;
@@ -7568,7 +7564,6 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
   read_op.params.attrs = &src_attrs;
   read_op.params.lastmod = src_mtime;
   read_op.params.obj_size = &obj_size;
-  read_op.params.perr = err;
 
   ret = read_op.prepare();
   if (ret < 0) {
@@ -7648,7 +7643,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
   if (copy_data) { /* refcounting tail wouldn't work here, just copy the data */
     return copy_obj_data(obj_ctx, dest_bucket_info, read_op, obj_size - 1, dest_obj, src_obj,
                          max_chunk_size, mtime, real_time(), attrs, category, olh_epoch, delete_at,
-                         version_id, ptag, petag, err);
+                         version_id, ptag, petag);
   }
 
   RGWObjManifest::obj_iterator miter = astate->manifest.obj_begin();
@@ -7784,8 +7779,7 @@ int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx,
               real_time delete_at,
                string *version_id,
                string *ptag,
-               ceph::buffer::list *petag,
-               struct rgw_err *err)
+               ceph::buffer::list *petag)
 {
   bufferlist first_chunk;
   RGWObjManifest manifest;
index cbb6610235ecbc5cfd9e6f9bd342c213e79ee683..e60ccbdf0be1f8289fa2cd699f537a4d3b9a011e 100644 (file)
@@ -2595,9 +2595,8 @@ public:
         ceph::real_time *lastmod;
         uint64_t *obj_size;
         map<string, bufferlist> *attrs;
-        struct rgw_err *perr;
 
-        StatParams() : lastmod(NULL), obj_size(NULL), attrs(NULL), perr(NULL) {}
+        StatParams() : lastmod(NULL), obj_size(NULL), attrs(NULL) {}
       } stat_params;
 
       struct ReadParams {
@@ -2708,9 +2707,8 @@ public:
         ceph::real_time *lastmod;
         uint64_t *obj_size;
         map<string, bufferlist> *attrs;
-        struct rgw_err *perr;
 
-        Params() : lastmod(NULL), obj_size(NULL), attrs(NULL), perr(NULL) {}
+        Params() : lastmod(NULL), obj_size(NULL), attrs(NULL) {}
       } params;
 
       explicit Read(RGWRados::Object *_source) : source(_source) {}
@@ -3023,7 +3021,6 @@ public:
                        string *version_id,
                        string *ptag,
                        ceph::buffer::list *petag,
-                       struct rgw_err *err,
                        void (*progress_cb)(off_t, void *),
                        void *progress_data);
   /**
@@ -3038,7 +3035,6 @@ public:
    *                               parameter, source object attributes are not copied;
    *            ATTRSMOD_MERGE - any conflicting meta keys on the source object's attributes
    *                             are overwritten by values contained in attrs parameter.
-   * err: stores any errors resulting from the get of the original object
    * Returns: 0 on success, -ERR# otherwise.
    */
   int copy_obj(RGWObjectCtx& obj_ctx,
@@ -3067,7 +3063,6 @@ public:
                string *version_id,
                string *ptag,
                ceph::buffer::list *petag,
-               struct rgw_err *err,
                void (*progress_cb)(off_t, void *),
                void *progress_data);
 
@@ -3085,8 +3080,7 @@ public:
               ceph::real_time delete_at,
                string *version_id,
                string *ptag,
-               ceph::buffer::list *petag,
-               struct rgw_err *err);
+               ceph::buffer::list *petag);
   
   int check_bucket_empty(RGWBucketInfo& bucket_info);
 
index 040f972467c8c896afa151aaf6cf873b38f75154..6063212436f9e2ce23c2af92a7db60edcd1e42c1 100644 (file)
@@ -1,6 +1,7 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 // vim: ts=8 sw=2 smarttab
 
+
 #include <errno.h>
 #include <limits.h>
 
@@ -18,8 +19,7 @@
 #include "rgw_rest_s3.h"
 #include "rgw_swift_auth.h"
 #include "rgw_cors_s3.h"
-#include "rgw_http_errors.h"
-#include "rgw_lib.h"
+// #include "rgw_lib.h"        // XXX mdw is this necessary?
 
 #include "rgw_client_io.h"
 #include "rgw_resolve.h"
 
 #define dout_subsys ceph_subsys_rgw
 
+struct rgw_http_status_code {
+  int code;
+  const char *name;
+};
+
+const static struct rgw_http_status_code http_codes[] = {
+  { 100, "Continue" },
+  { 200, "OK" },
+  { 201, "Created" },
+  { 202, "Accepted" },
+  { 204, "No Content" },
+  { 205, "Reset Content" },
+  { 206, "Partial Content" },
+  { 207, "Multi Status" },
+  { 208, "Already Reported" },
+  { 300, "Multiple Choices" },
+  { 301, "Moved Permanently" },
+  { 302, "Found" },
+  { 303, "See Other" },
+  { 304, "Not Modified" },
+  { 305, "User Proxy" },
+  { 306, "Switch Proxy" },
+  { 307, "Temporary Redirect" },
+  { 308, "Permanent Redirect" },
+  { 400, "Bad Request" },
+  { 401, "Unauthorized" },
+  { 402, "Payment Required" },
+  { 403, "Forbidden" },
+  { 404, "Not Found" },
+  { 405, "Method Not Allowed" },
+  { 406, "Not Acceptable" },
+  { 407, "Proxy Authentication Required" },
+  { 408, "Request Timeout" },
+  { 409, "Conflict" },
+  { 410, "Gone" },
+  { 411, "Length Required" },
+  { 412, "Precondition Failed" },
+  { 413, "Request Entity Too Large" },
+  { 414, "Request-URI Too Long" },
+  { 415, "Unsupported Media Type" },
+  { 416, "Requested Range Not Satisfiable" },
+  { 417, "Expectation Failed" },
+  { 422, "Unprocessable Entity" },
+  { 500, "Internal Server Error" },
+  { 501, "Not Implemented" },
+  { 0, NULL },
+};
 
 struct rgw_http_attr {
   const char *rgw_attr;
@@ -176,10 +223,8 @@ string camelcase_dash_http_attr(const string& orig)
 static set<string> hostnames_set;
 static set<string> hostnames_s3website_set;
 
-void rgw_rest_init(CephContext *cct, RGWRados *store, RGWZoneGroup& zone_group)
+void rgw_rest_init(CephContext *cct)
 {
-  store->init_host_id();
-
   for (const auto& rgw2http : base_rgw_to_http_attrs)  {
     rgw_to_http_attrs[rgw2http.rgw_attr] = rgw2http.http_attr;
   }
@@ -209,6 +254,12 @@ void rgw_rest_init(CephContext *cct, RGWRados *store, RGWZoneGroup& zone_group)
   }
 
   hostnames_set.insert(cct->_conf->rgw_dns_name);
+}
+
+void rgw_rest_init(CephContext *cct, RGWRados *store, RGWZoneGroup& zone_group)
+{
+  store->init_host_id();
+  rgw_rest_init(cct);
   hostnames_set.insert(zone_group.hostnames.begin(), zone_group.hostnames.end());
   hostnames_set.erase(""); // filter out empty hostnames
   ldout(cct, 20) << "RGW hostnames: " << hostnames_set << dendl;
@@ -309,45 +360,6 @@ void rgw_flush_formatter(struct req_state *s, Formatter *formatter)
   }
 }
 
-void set_req_state_err(struct rgw_err& err,     /* out */
-                       int err_no,              /* in  */
-                       const int prot_flags)    /* in  */
-{
-  const struct rgw_http_errors *r;
-
-  if (err_no < 0)
-    err_no = -err_no;
-  err.ret = -err_no;
-  if (prot_flags & RGW_REST_SWIFT) {
-    r = search_err(err_no, RGW_HTTP_SWIFT_ERRORS,
-                  ARRAY_LEN(RGW_HTTP_SWIFT_ERRORS));
-    if (r) {
-      err.http_ret = r->http_ret;
-      err.s3_code = r->s3_code;
-      return;
-    }
-  }
-
-  r = search_err(err_no, RGW_HTTP_ERRORS, ARRAY_LEN(RGW_HTTP_ERRORS));
-  if (r) {
-    err.http_ret = r->http_ret;
-    err.s3_code = r->s3_code;
-    return;
-  }
-  dout(0) << "WARNING: set_req_state_err err_no=" << err_no
-         << " resorting to 500" << dendl;
-
-  err.http_ret = 500;
-  err.s3_code = "UnknownError";
-}
-
-void set_req_state_err(struct req_state * const s, const int err_no)
-{
-  if (s) {
-    set_req_state_err(s->err, err_no, s->prot_flags);
-  }
-}
-
 void dump_errno(int http_ret, string& out) {
   stringstream ss;
 
@@ -361,7 +373,7 @@ void dump_errno(const struct rgw_err &err, string& out) {
 
 void dump_errno(struct req_state *s)
 {
-  dump_status(s, s->err.http_ret, http_status_names[s->err.http_ret]);
+  dump_status(s, s->err->http_ret, http_status_names[s->err->http_ret]);
 }
 
 void dump_errno(struct req_state *s, int http_ret)
@@ -650,22 +662,22 @@ void dump_trans_id(req_state *s)
   }
 }
 
-void end_header(struct req_state* s, RGWOp* op, const char *content_type,
-               const int64_t proposed_content_length, bool force_content_type,
-               bool force_no_error)
+void end_header(struct req_state* s, boost::function<void()> dump_more,
+               const char *content_type, const int64_t proposed_content_length,
+               bool force_content_type, bool force_no_error)
 {
   string ctype;
 
   dump_trans_id(s);
 
-  if ((!s->err.is_err()) &&
+  if ((!s->is_err()) &&
       (s->bucket_info.owner != s->user->user_id) &&
       (s->bucket_info.requester_pays)) {
     dump_header(s, "x-amz-request-charged", "requester");
   }
 
-  if (op) {
-    dump_access_control(s, op);
+  if (dump_more) {
+    dump_more();
   }
 
   if (s->prot_flags & RGW_REST_SWIFT && !content_type) {
@@ -675,7 +687,7 @@ void end_header(struct req_state* s, RGWOp* op, const char *content_type,
   /* do not send content type if content length is zero
      and the content type was not set by the user */
   if (force_content_type ||
-      (!content_type &&  s->formatter->get_len()  != 0) || s->err.is_err()){
+      (!content_type &&  s->formatter->get_len()  != 0) || s->is_err()){
     switch (s->format) {
     case RGW_FORMAT_XML:
       ctype = "application/xml";
@@ -694,24 +706,9 @@ void end_header(struct req_state* s, RGWOp* op, const char *content_type,
       ctype.append("; charset=utf-8");
     content_type = ctype.c_str();
   }
-  if (!force_no_error && s->err.is_err()) {
+  if (!force_no_error && s->is_err()) {
     dump_start(s);
-    if (s->format != RGW_FORMAT_HTML) {
-      s->formatter->open_object_section("Error");
-    }
-    if (!s->err.s3_code.empty())
-      s->formatter->dump_string("Code", s->err.s3_code);
-    if (!s->err.message.empty())
-      s->formatter->dump_string("Message", s->err.message);
-    if (!s->bucket_name.empty()) // TODO: connect to expose_bucket
-      s->formatter->dump_string("BucketName", s->bucket_name);
-    if (!s->trans_id.empty()) // TODO: connect to expose_bucket or another toggle
-      s->formatter->dump_string("RequestId", s->trans_id);
-    s->formatter->dump_string("HostId", s->host_id);
-    if (s->format != RGW_FORMAT_HTML) {
-      s->formatter->close_section();
-    }
-    s->formatter->output_footer();
+    s->err->dump();
     dump_content_length(s, s->formatter->get_len());
   } else {
     if (proposed_content_length == CHUNKED_TRANSFER_ENCODING) {
@@ -736,45 +733,38 @@ void end_header(struct req_state* s, RGWOp* op, const char *content_type,
   rgw_flush_formatter_and_reset(s, s->formatter);
 }
 
-void abort_early(struct req_state *s, RGWOp *op, int err_no,
-                RGWHandler* handler)
+void end_header(struct req_state* s, RGWOp* op, const char *content_type,
+               const int64_t proposed_content_length, bool force_content_type,
+               bool force_no_error)
+{
+  boost::function<void()> dump_more;
+
+  if (op) dump_more = op->dump_access_control_f();
+  end_header(s, dump_more, content_type,
+       proposed_content_length, force_content_type, force_no_error);
+}
+
+void abort_early(struct req_state *s, boost::function<void()> dump_more,
+               string& error_content, int err_no)
 {
-  string error_content("");
   if (!s->formatter) {
     s->formatter = new JSONFormatter;
     s->format = RGW_FORMAT_JSON;
   }
 
-  // op->error_handler is responsible for calling it's handler error_handler
-  if (op != NULL) {
-    int new_err_no;
-    new_err_no = op->error_handler(err_no, &error_content);
-    ldout(s->cct, 20) << "op->ERRORHANDLER: err_no=" << err_no
-                     << " new_err_no=" << new_err_no << dendl;
-    err_no = new_err_no;
-  } else if (handler != NULL) {
-    int new_err_no;
-    new_err_no = handler->error_handler(err_no, &error_content);
-    ldout(s->cct, 20) << "handler->ERRORHANDLER: err_no=" << err_no
-                     << " new_err_no=" << new_err_no << dendl;
-    err_no = new_err_no;
-  }
-
   // If the error handler(s) above dealt with it completely, they should have
   // returned 0. If non-zero, we need to continue here.
   if (err_no) {
     // Watch out, we might have a custom error state already set!
-    if (s->err.http_ret && s->err.http_ret != 200) {
-      dump_errno(s);
-    } else {
-      set_req_state_err(s, err_no);
-      dump_errno(s);
+    if (!s->err->http_ret || s->err->http_ret == 200) {
+      s->set_req_state_err(err_no);
     }
+    dump_errno(s);
     dump_bucket_from_state(s);
     if (err_no == -ERR_PERMANENT_REDIRECT || err_no == -ERR_WEBSITE_REDIRECT) {
       string dest_uri;
       if (!s->redirect.empty()) {
-        dest_uri = s->redirect;
+       dest_uri = s->redirect;
       } else if (!s->zonegroup_endpoint.empty()) {
         dest_uri = s->zonegroup_endpoint;
         /*
@@ -803,15 +793,39 @@ void abort_early(struct req_state *s, RGWOp *op, int err_no,
        *   x-amz-error-message: The specified key does not exist.
        *   x-amz-error-detail-Key: foo
        */
-      end_header(s, op, NULL, error_content.size(), false, true);
+      end_header(s, dump_more, NULL, error_content.size(), false, true);
       RESTFUL_IO(s)->send_body(error_content.c_str(), error_content.size());
     } else {
-      end_header(s, op);
+      end_header(s, dump_more);
     }
   }
   perfcounter->inc(l_rgw_failed_req);
 }
 
+void abort_early(struct req_state *s, RGWOp* op, int err_no,
+               RGWHandler* handler)
+{
+  string error_content("");
+  boost::function<void()> dump_more;
+
+  // op->error_handler is responsible for calling it's handler error_handler
+  if (op != NULL) {
+    int new_err_no;
+    new_err_no = op->error_handler(err_no, &error_content);
+    ldout(s->cct, 20) << "op->ERRORHANDLER: err_no=" << err_no
+                     << " new_err_no=" << new_err_no << dendl;
+    err_no = new_err_no;
+  } else if (handler != NULL) {
+    int new_err_no;
+    new_err_no = handler->error_handler(err_no, &error_content);
+    ldout(s->cct, 20) << "handler->ERRORHANDLER: err_no=" << err_no
+                     << " new_err_no=" << new_err_no << dendl;
+    err_no = new_err_no;
+  }
+  if (op) dump_more = op->dump_access_control_f();
+  abort_early(s, dump_more, error_content, err_no);
+}
+
 void dump_continue(struct req_state * const s)
 {
   try {
@@ -1091,7 +1105,7 @@ int RESTArgs::get_bool(struct req_state *s, const string& name, bool def_val, bo
 
 void RGWRESTFlusher::do_start(int ret)
 {
-  set_req_state_err(s, ret); /* no going back from here */
+  s->set_req_state_err(ret); /* no going back from here */
   dump_errno(s);
   dump_start(s);
   end_header(s, op);
@@ -1785,7 +1799,7 @@ int RGWDeleteMultiObj_ObjStore::get_params()
 void RGWRESTOp::send_response()
 {
   if (!flusher.did_start()) {
-    set_req_state_err(s, http_ret);
+    s->set_req_state_err(http_ret);
     dump_errno(s);
     end_header(s, this);
   }
index 4b092935e4652821da2b4527a39350da27abfab8..0a9f0b9db7a902c15d6d6bc7ec7250e76389044f 100644 (file)
@@ -20,6 +20,7 @@ extern std::map<std::string, std::string> rgw_to_http_attrs;
 extern string camelcase_dash_http_attr(const string& orig);
 extern string lowercase_dash_http_attr(const string& orig);
 
+extern void rgw_rest_init(CephContext *cct);
 extern void rgw_rest_init(CephContext *cct, RGWRados *store, RGWZoneGroup& zone_group);
 
 extern void rgw_flush_formatter_and_reset(struct req_state *s,
@@ -130,16 +131,16 @@ public:
 
 class RGWRESTFlusher : public RGWFormatterFlusher {
   struct req_state *s;
-  RGWOp *op;
+  boost::function<void()> op;
 protected:
   void do_flush() override;
   void do_start(int ret) override;
 public:
-  RGWRESTFlusher(struct req_state *_s, RGWOp *_op) :
+  RGWRESTFlusher(struct req_state *_s, boost::function<void()> _op) :
     RGWFormatterFlusher(_s->formatter), s(_s), op(_op) {}
   RGWRESTFlusher() : RGWFormatterFlusher(NULL), s(NULL), op(NULL) {}
 
-  void init(struct req_state *_s, RGWOp *_op) {
+  void init(struct req_state *_s, boost::function<void()> _op) {
     s = _s;
     op = _op;
     set_formatter(s->formatter);
@@ -462,7 +463,7 @@ public:
   void init(RGWRados *store, struct req_state *s,
             RGWHandler *dialect_handler) override {
     RGWOp::init(store, s, dialect_handler);
-    flusher.init(s, this);
+    flusher.init(s, dump_access_control_f());
   }
   void send_response() override;
   virtual int check_caps(RGWUserCaps& caps)
@@ -626,8 +627,6 @@ public:
 static constexpr int64_t NO_CONTENT_LENGTH = -1;
 static constexpr int64_t CHUNKED_TRANSFER_ENCODING = -2;
 
-extern void set_req_state_err(struct rgw_err &err, int err_no, int prot_flags);
-extern void set_req_state_err(struct req_state *s, int err_no);
 extern void dump_errno(int http_ret, string& out);
 extern void dump_errno(const struct rgw_err &err, string& out);
 extern void dump_errno(struct req_state *s);
@@ -639,6 +638,13 @@ extern void end_header(struct req_state *s,
                       NO_CONTENT_LENGTH,
                       bool force_content_type = false,
                       bool force_no_error = false);
+extern void end_header(struct req_state *s,
+                       boost::function<void()> dump_more,
+                       const char *content_type = nullptr,
+                       const int64_t proposed_content_length =
+                      NO_CONTENT_LENGTH,
+                      bool force_content_type = false,
+                      bool force_no_error = false);
 extern void dump_start(struct req_state *s);
 extern void list_all_buckets_start(struct req_state *s);
 extern void dump_owner(struct req_state *s, const rgw_user& id, string& name,
@@ -702,6 +708,8 @@ extern void dump_time_header(struct req_state *s, const char *name, real_time t)
 extern void dump_last_modified(struct req_state *s, real_time t);
 extern void abort_early(struct req_state* s, RGWOp* op, int err,
                        RGWHandler* handler);
+extern void abort_early(struct req_state* s, boost::function<void()> dump_more,
+                       string& error_content, int err);
 extern void dump_range(struct req_state* s, uint64_t ofs, uint64_t end,
                       uint64_t total_size);
 extern void dump_continue(struct req_state *s);
index 3770cec15dedeaea04cbaa93cafeab69fedae63f..4a4cb3901f7f97005a0de0af16ba25869f0d075f 100644 (file)
@@ -33,7 +33,7 @@ void RGWOp_ZoneGroupMap_Get::execute() {
 }
 
 void RGWOp_ZoneGroupMap_Get::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
index 5ba563f4c40195d63a3c9814ad684c18ee8a8996..2e933c2ddc094f8a7f2a61eb363868d6ee2cec0a 100644 (file)
@@ -20,6 +20,7 @@
 #include "rgw_client_io.h"
 #include "rgw_sync.h"
 #include "rgw_data_sync.h"
+#include "rgw_common.h"
 #include "common/errno.h"
 #include "include/assert.h"
 
@@ -108,7 +109,7 @@ void RGWOp_MDLog_List::execute() {
 }
 
 void RGWOp_MDLog_List::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -139,7 +140,7 @@ void RGWOp_MDLog_Info::execute() {
 }
 
 void RGWOp_MDLog_Info::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -181,7 +182,7 @@ void RGWOp_MDLog_ShardInfo::execute() {
 }
 
 void RGWOp_MDLog_ShardInfo::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -434,7 +435,7 @@ void RGWOp_BILog_List::send_response() {
   if (sent_header)
     return;
 
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -504,7 +505,7 @@ void RGWOp_BILog_Info::execute() {
 }
 
 void RGWOp_BILog_Info::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -620,7 +621,7 @@ void RGWOp_DATALog_List::execute() {
 }
 
 void RGWOp_DATALog_List::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -655,7 +656,7 @@ void RGWOp_DATALog_Info::execute() {
 }
 
 void RGWOp_DATALog_Info::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -680,7 +681,7 @@ void RGWOp_DATALog_ShardInfo::execute() {
 }
 
 void RGWOp_DATALog_ShardInfo::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -868,7 +869,7 @@ void RGWOp_MDLog_Status::execute()
 
 void RGWOp_MDLog_Status::send_response()
 {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -907,7 +908,7 @@ void RGWOp_DATALog_Status::execute()
 
 void RGWOp_DATALog_Status::send_response()
 {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
index 272e304f17ebf086dca7e878389d50821e726110..792f49ab64d195a3d1810b824659f65c7d876fee 100644 (file)
@@ -201,7 +201,7 @@ void RGWOp_Metadata_Put::send_response() {
   int http_return_code = http_ret;
   if ((http_ret == STATUS_NO_APPLY) || (http_ret == STATUS_APPLIED))
     http_return_code = STATUS_NO_CONTENT;
-  set_req_state_err(s, http_return_code);
+  s->set_req_state_err(http_return_code);
   dump_errno(s);
   stringstream ver_stream;
   ver_stream << "ver:" << ondisk_version.ver
index af9c024e13f7ba91ce0123c0fa25884e25aa2bd2..af07980333325a2b5c5a5c939477336bf5bf4249 100644 (file)
@@ -75,7 +75,7 @@ void RGWOp_Opstate_List::send_response() {
   if (sent_header)
     return;
 
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
index d5ef848b805cb9b810cd2956019f1c459a1c76c3..3dde7803cbd97f2f87f3ca8f4ea225604c775955 100644 (file)
@@ -26,15 +26,13 @@ class RGWOp_Period_Base : public RGWRESTOp {
 // reply with the period object on success
 void RGWOp_Period_Base::send_response()
 {
-  s->err.message = error_stream.str();
-
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret, error_stream.str());
   dump_errno(s);
 
   if (http_ret < 0) {
-    if (!s->err.message.empty()) {
+    if (!s->err->message.empty()) {
       ldout(s->cct, 4) << "Request failed with " << http_ret
-          << ": " << s->err.message << dendl;
+          << ": " << s->err->message << dendl;
     }
     end_header(s);
     return;
@@ -265,7 +263,7 @@ void RGWOp_Realm_Get::execute()
 
 void RGWOp_Realm_Get::send_response()
 {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
 
   if (http_ret < 0) {
index 919815f572366027caa65dd53f79e99bf9c9266a..dd40c34286a23130a90c2487119bd68cf50dfd19 100644 (file)
@@ -108,7 +108,7 @@ void RGWOp_OBJLog_GetBounds::execute() {
 }
 
 void RGWOp_OBJLog_GetBounds::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
@@ -230,7 +230,7 @@ void RGWOp_BILog_GetBounds::execute() {
 }
 
 void RGWOp_BILog_GetBounds::send_response() {
-  set_req_state_err(s, http_ret);
+  s->set_req_state_err(http_ret);
   dump_errno(s);
   end_header(s);
 
index b41441160f58f5a32134a2ada39f8755cabc5699..9c7ac61b0c9222bfa780fa0b2aa41d58621bd0e2 100644 (file)
@@ -65,14 +65,13 @@ void dump_bucket(struct req_state *s, RGWBucketEnt& obj)
   s->formatter->close_section();
 }
 
-void rgw_get_errno_s3(rgw_http_errors *e , int err_no)
+void rgw_get_errno_s3(rgw_http_error *e , int err_no)
 {
-  const struct rgw_http_errors *r;
-  r = search_err(err_no, RGW_HTTP_ERRORS, ARRAY_LEN(RGW_HTTP_ERRORS));
+  rgw_http_errors::const_iterator r = rgw_http_s3_errors.find(err_no);
 
-  if (r) {
-    e->http_ret = r->http_ret;
-    e->s3_code = r->s3_code;
+  if (r != rgw_http_s3_errors.end()) {
+    e->http_ret = r->second.first;
+    e->s3_code = r->second.second;
   } else {
     e->http_ret = 500;
     e->s3_code = "UnknownError";
@@ -100,10 +99,10 @@ int RGWGetObj_ObjStore_S3Website::send_response_data(bufferlist& bl, off_t bl_of
   if (iter != attrs.end()) {
     bufferlist &bl = iter->second;
     s->redirect = string(bl.c_str(), bl.length());
-    s->err.http_ret = 301;
+    s->err->http_ret = 301;
     ldout(s->cct, 20) << __CEPH_ASSERT_FUNCTION << " redirecting per x-amz-website-redirect-location=" << s->redirect << dendl;
     op_ret = -ERR_WEBSITE_REDIRECT;
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
     dump_errno(s);
     dump_content_length(s, 0);
     dump_redirect(s, s->redirect);
@@ -169,10 +168,10 @@ int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs,
     goto send_data;
 
   if (custom_http_ret) {
-    set_req_state_err(s, 0);
+    s->set_req_state_err(0);
     dump_errno(s, custom_http_ret);
   } else {
-    set_req_state_err(s, (partial_content && !op_ret) ? STATUS_PARTIAL_CONTENT
+    s->set_req_state_err((partial_content && !op_ret) ? STATUS_PARTIAL_CONTENT
                  : op_ret);
     dump_errno(s);
   }
@@ -341,7 +340,7 @@ int RGWGetObj_ObjStore_S3::get_decrypt_filter(std::unique_ptr<RGWGetDataCB> *fil
 void RGWListBuckets_ObjStore_S3::send_response_begin(bool has_buckets)
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   dump_start(s);
   end_header(s, NULL, "application/xml");
@@ -407,7 +406,7 @@ static void dump_usage_categories_info(Formatter *formatter, const rgw_usage_log
 void RGWGetUsage_ObjStore_S3::send_response()
 {
   if (op_ret < 0)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
 
   end_header(s, this, "application/xml");
@@ -619,7 +618,7 @@ void RGWListBucket_ObjStore_S3::send_versioned_response()
 void RGWListBucket_ObjStore_S3::send_response()
 {
   if (op_ret < 0)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
 
   end_header(s, this, "application/xml");
@@ -817,7 +816,7 @@ int RGWSetBucketVersioning_ObjStore_S3::get_params()
 void RGWSetBucketVersioning_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s);
 }
@@ -868,7 +867,7 @@ int RGWSetBucketWebsite_ObjStore_S3::get_params()
 void RGWSetBucketWebsite_ObjStore_S3::send_response()
 {
   if (op_ret < 0)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s);
 }
@@ -878,7 +877,7 @@ void RGWDeleteBucketWebsite_ObjStore_S3::send_response()
   if (op_ret == 0) {
     op_ret = STATUS_NO_CONTENT;
   }
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s);
 }
@@ -886,7 +885,7 @@ void RGWDeleteBucketWebsite_ObjStore_S3::send_response()
 void RGWGetBucketWebsite_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this, "application/xml");
   dump_start(s);
@@ -915,7 +914,7 @@ void RGWStatBucket_ObjStore_S3::send_response()
     dump_bucket_metadata(s, bucket);
   }
 
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
 
   end_header(s, this);
@@ -1055,7 +1054,7 @@ void RGWCreateBucket_ObjStore_S3::send_response()
   if (op_ret == -ERR_BUCKET_EXISTS)
     op_ret = 0;
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s);
 
@@ -1080,7 +1079,7 @@ void RGWDeleteBucket_ObjStore_S3::send_response()
   if (!r)
     r = STATUS_NO_CONTENT;
 
-  set_req_state_err(s, r);
+  s->set_req_state_err(r);
   dump_errno(s);
   end_header(s, this);
 
@@ -1360,13 +1359,13 @@ static int get_success_retcode(int code)
 void RGWPutObj_ObjStore_S3::send_response()
 {
   if (op_ret) {
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
     dump_errno(s);
   } else {
     if (s->cct->_conf->rgw_s3_success_create_obj_status) {
       op_ret = get_success_retcode(
        s->cct->_conf->rgw_s3_success_create_obj_status);
-      set_req_state_err(s, op_ret);
+      s->set_req_state_err(op_ret);
     }
     if (!copy_source) {
       dump_errno(s);
@@ -1888,8 +1887,8 @@ done:
     s->formatter->dump_string("Key", s->object.name);
     s->formatter->close_section();
   }
-  s->err.message = err_msg;
-  set_req_state_err(s, op_ret);
+  s->err->message = err_msg;
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   if (op_ret >= 0) {
     dump_content_length(s, s->formatter->get_len());
@@ -1948,7 +1947,7 @@ void RGWDeleteObj_ObjStore_S3::send_response()
   if (!r)
     r = STATUS_NO_CONTENT;
 
-  set_req_state_err(s, r);
+  s->set_req_state_err(r);
   dump_errno(s);
   if (!version_id.empty()) {
     dump_header(s, "x-amz-version-id", version_id);
@@ -2037,7 +2036,7 @@ void RGWCopyObj_ObjStore_S3::send_partial_response(off_t ofs)
 {
   if (! sent_header) {
     if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
     dump_errno(s);
 
     end_header(s, this, "application/xml");
@@ -2073,7 +2072,7 @@ void RGWCopyObj_ObjStore_S3::send_response()
 void RGWGetACLs_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this, "application/xml");
   dump_start(s);
@@ -2119,7 +2118,7 @@ int RGWPutACLs_ObjStore_S3::get_policy_from_state(RGWRados *store,
 void RGWPutACLs_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this, "application/xml");
   dump_start(s);
@@ -2149,9 +2148,9 @@ void RGWGetLC_ObjStore_S3::send_response()
 {
   if (op_ret) {
     if (op_ret == -ENOENT) {   
-      set_req_state_err(s, ERR_NO_SUCH_LC);
+      s->set_req_state_err(ERR_NO_SUCH_LC);
     } else {
-      set_req_state_err(s, op_ret);
+      s->set_req_state_err(op_ret);
     }
   }
   dump_errno(s);
@@ -2168,7 +2167,7 @@ void RGWGetLC_ObjStore_S3::send_response()
 void RGWPutLC_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this, "application/xml");
   dump_start(s);
@@ -2179,7 +2178,7 @@ void RGWDeleteLC_ObjStore_S3::send_response()
   if (op_ret == 0)
       op_ret = STATUS_NO_CONTENT;
   if (op_ret) {   
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   }
   dump_errno(s);
   end_header(s, this, "application/xml");
@@ -2190,9 +2189,9 @@ void RGWGetCORS_ObjStore_S3::send_response()
 {
   if (op_ret) {
     if (op_ret == -ENOENT)
-      set_req_state_err(s, ERR_NOT_FOUND);
+      s->set_req_state_err(ERR_NOT_FOUND);
     else
-      set_req_state_err(s, op_ret);
+      s->set_req_state_err(op_ret);
   }
   dump_errno(s);
   end_header(s, NULL, "application/xml");
@@ -2260,7 +2259,7 @@ int RGWPutCORS_ObjStore_S3::get_params()
 void RGWPutCORS_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, NULL, "application/xml");
   dump_start(s);
@@ -2272,7 +2271,7 @@ void RGWDeleteCORS_ObjStore_S3::send_response()
   if (!r || r == -ENOENT)
     r = STATUS_NO_CONTENT;
 
-  set_req_state_err(s, r);
+  s->set_req_state_err(r);
   dump_errno(s);
   end_header(s, NULL);
 }
@@ -2287,7 +2286,7 @@ void RGWOptionsCORS_ObjStore_S3::send_response()
   if (op_ret == -ENOENT)
     op_ret = -EACCES;
   if (op_ret < 0) {
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
     dump_errno(s);
     end_header(s, NULL);
     return;
@@ -2382,7 +2381,7 @@ done:
 void RGWSetRequestPayment_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s);
 }
@@ -2402,7 +2401,7 @@ int RGWInitMultipart_ObjStore_S3::get_params()
 void RGWInitMultipart_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   for (auto &it : crypt_http_responses)
      dump_header(s, it.first, it.second);
@@ -2446,7 +2445,7 @@ int RGWCompleteMultipart_ObjStore_S3::get_params()
 void RGWCompleteMultipart_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this, "application/xml");
   if (op_ret == 0) { 
@@ -2481,7 +2480,7 @@ void RGWAbortMultipart_ObjStore_S3::send_response()
   if (!r)
     r = STATUS_NO_CONTENT;
 
-  set_req_state_err(s, r);
+  s->set_req_state_err(r);
   dump_errno(s);
   end_header(s, this);
 }
@@ -2489,7 +2488,7 @@ void RGWAbortMultipart_ObjStore_S3::send_response()
 void RGWListMultipart_ObjStore_S3::send_response()
 {
   if (op_ret)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this, "application/xml");
 
@@ -2539,7 +2538,7 @@ void RGWListMultipart_ObjStore_S3::send_response()
 void RGWListBucketMultiparts_ObjStore_S3::send_response()
 {
   if (op_ret < 0)
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   dump_errno(s);
 
   end_header(s, this, "application/xml");
@@ -2617,7 +2616,7 @@ void RGWDeleteMultiObj_ObjStore_S3::send_status()
 {
   if (! status_dumped) {
     if (op_ret < 0)
-      set_req_state_err(s, op_ret);
+      s->set_req_state_err(op_ret);
     dump_errno(s);
     status_dumped = true;
   }
@@ -2654,7 +2653,7 @@ void RGWDeleteMultiObj_ObjStore_S3::send_partial_response(rgw_obj_key& key,
       }
       s->formatter->close_section();
     } else if (op_ret < 0) {
-      struct rgw_http_errors r;
+      struct rgw_http_error r;
       int err_no;
 
       s->formatter->open_object_section("Error");
@@ -3868,7 +3867,7 @@ int RGWHandler_REST_S3Website::retarget(RGWOp* op, RGWOp** new_op) {
                    &redirect_code);
     // APply a custom HTTP response code
     if (redirect_code > 0)
-      s->err.http_ret = redirect_code; // Apply a custom HTTP response code
+      s->err->http_ret = redirect_code; // Apply a custom HTTP response code
     ldout(s->cct, 10) << "retarget redirect code=" << redirect_code
                      << " proto+host:" << protocol << "://" << hostname
                      << " -> " << s->redirect << dendl;
@@ -3969,11 +3968,11 @@ int RGWHandler_REST_S3Website::serve_errordoc(int http_ret, const string& errord
 int RGWHandler_REST_S3Website::error_handler(int err_no,
                                            string* error_content) {
   int new_err_no = -1;
-  const struct rgw_http_errors* r;
+  rgw_http_errors::const_iterator r = rgw_http_s3_errors.find(err_no > 0 ? err_no : -err_no);
   int http_error_code = -1;
-  r = search_err(err_no > 0 ? err_no : -err_no, RGW_HTTP_ERRORS, ARRAY_LEN(RGW_HTTP_ERRORS));
-  if (r) {
-    http_error_code = r->http_ret;
+
+  if (r != rgw_http_s3_errors.end()) {
+    http_error_code = r->second.first;
   }
   ldout(s->cct, 10) << "RGWHandler_REST_S3Website::error_handler err_no=" << err_no << " http_ret=" << http_error_code << dendl;
 
@@ -3991,7 +3990,7 @@ int RGWHandler_REST_S3Website::error_handler(int err_no,
                    &redirect_code);
     // Apply a custom HTTP response code
     if (redirect_code > 0)
-      s->err.http_ret = redirect_code; // Apply a custom HTTP response code
+      s->err->http_ret = redirect_code; // Apply a custom HTTP response code
     ldout(s->cct, 10) << "error handler redirect code=" << redirect_code
                      << " proto+host:" << protocol << "://" << hostname
                      << " -> " << s->redirect << dendl;
index 1e100efb2c596316825d51d7e2acd6673608f0ca..072717a6822a2ecb75dcb89205908828de623d4b 100644 (file)
 
 #define RGW_AUTH_GRACE_MINS 15
 
-void rgw_get_errno_s3(struct rgw_http_errors *e, int err_no);
+struct rgw_http_error {
+  int http_ret;
+  const char *s3_code;
+};
+
+void rgw_get_errno_s3(struct rgw_http_error *e, int err_no);
 
 class RGWGetObj_ObjStore_S3 : public RGWGetObj_ObjStore
 {
index f778d87c412ac447fd4f0b2bb1a8c7be39d4414e..f05ced9e28228ceda9af68f62f8a97650c57f91d 100644 (file)
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_rgw
 
+struct swift_err : public rgw_err {
+  swift_err(struct req_state *s) : rgw_err(s) {};
+
+  virtual bool set_rgw_err(int err_no) {
+    rgw_http_errors::const_iterator r;
+
+    r = rgw_http_swift_errors.find(err_no);
+    if (r != rgw_http_swift_errors.end()) {
+      http_ret = r->second.first;
+      s3_code = r->second.second;
+      return true;
+    }
+    return rgw_err::set_rgw_err(err_no);
+  }
+};
+
 int RGWListBuckets_ObjStore_SWIFT::get_params()
 {
   prefix = s->info.args.get("prefix");
@@ -140,10 +156,10 @@ static void dump_account_metadata(struct req_state * const s,
 void RGWListBuckets_ObjStore_SWIFT::send_response_begin(bool has_buckets)
 {
   if (op_ret) {
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   } else if (!has_buckets && s->format == RGW_FORMAT_PLAIN) {
     op_ret = STATUS_NO_CONTENT;
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
   }
 
   if (! s->cct->_conf->rgw_swift_enforce_content_length) {
@@ -360,7 +376,7 @@ next:
     op_ret = 0;
   }
 
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this, NULL, content_len);
   if (op_ret < 0) {
@@ -477,7 +493,7 @@ void RGWStatAccount_ObjStore_SWIFT::send_response()
             static_cast<RGWAccessControlPolicy_SWIFTAcct&>(*s->user_acl));
   }
 
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
 
   end_header(s, NULL, NULL, 0,  true);
@@ -493,7 +509,7 @@ void RGWStatBucket_ObjStore_SWIFT::send_response()
                             s->bucket_info.website_conf);
   }
 
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
 
   end_header(s, this, NULL, 0, true);
@@ -652,7 +668,7 @@ void RGWCreateBucket_ObjStore_SWIFT::send_response()
     op_ret = STATUS_CREATED;
   else if (op_ret == -ERR_BUCKET_EXISTS)
     op_ret = STATUS_ACCEPTED;
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   /* Propose ending HTTP header with 0 Content-Length header. */
   end_header(s, NULL, NULL, 0);
@@ -665,7 +681,7 @@ void RGWDeleteBucket_ObjStore_SWIFT::send_response()
   if (!r)
     r = STATUS_NO_CONTENT;
 
-  set_req_state_err(s, r);
+  s->set_req_state_err(r);
   dump_errno(s);
   end_header(s, this, NULL, 0);
   rgw_flush_formatter_and_reset(s, s->formatter);
@@ -838,7 +854,7 @@ void RGWPutObj_ObjStore_SWIFT::send_response()
   }
 
   dump_last_modified(s, mtime);
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this);
   rgw_flush_formatter_and_reset(s, s->formatter);
@@ -895,7 +911,7 @@ void RGWPutMetadataAccount_ObjStore_SWIFT::send_response()
   if (! op_ret) {
     op_ret = STATUS_NO_CONTENT;
   }
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this);
   rgw_flush_formatter_and_reset(s, s->formatter);
@@ -925,7 +941,7 @@ void RGWPutMetadataBucket_ObjStore_SWIFT::send_response()
   if (!op_ret && (op_ret != -EINVAL)) {
     op_ret = STATUS_NO_CONTENT;
   }
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this);
   rgw_flush_formatter_and_reset(s, s->formatter);
@@ -955,8 +971,8 @@ void RGWPutMetadataObject_ObjStore_SWIFT::send_response()
   if (! op_ret) {
     op_ret = STATUS_ACCEPTED;
   }
-  set_req_state_err(s, op_ret);
-  if (!s->err.is_err()) {
+  s->set_req_state_err(op_ret);
+  if (!s->is_err()) {
     dump_content_length(s, 0);
   }
   dump_errno(s);
@@ -967,10 +983,9 @@ void RGWPutMetadataObject_ObjStore_SWIFT::send_response()
 static void bulkdelete_respond(const unsigned num_deleted,
                                const unsigned int num_unfound,
                                const std::list<RGWBulkDelete::fail_desc_t>& failures,
-                               const int prot_flags,                  /* in  */
-                               ceph::Formatter& formatter)            /* out */
+                               struct req_state *s)                  /* out */
 {
-  formatter.open_object_section("delete");
+  s->formatter->open_object_section("delete");
 
   string resp_status;
   string resp_body;
@@ -983,8 +998,8 @@ static void bulkdelete_respond(const unsigned num_deleted,
       }
     }
 
-    rgw_err err;
-    set_req_state_err(err, reason, prot_flags);
+    swift_err err(s);
+    err.set_rgw_err(reason);
     dump_errno(err, resp_status);
   } else if (0 == num_deleted && 0 == num_unfound) {
     /* 400 Bad Request */
@@ -995,29 +1010,29 @@ static void bulkdelete_respond(const unsigned num_deleted,
     dump_errno(200, resp_status);
   }
 
-  encode_json("Number Deleted", num_deleted, &formatter);
-  encode_json("Number Not Found", num_unfound, &formatter);
-  encode_json("Response Body", resp_body, &formatter);
-  encode_json("Response Status", resp_status, &formatter);
+  encode_json("Number Deleted", num_deleted, s->formatter);
+  encode_json("Number Not Found", num_unfound, s->formatter);
+  encode_json("Response Body", resp_body, s->formatter);
+  encode_json("Response Status", resp_status, s->formatter);
 
-  formatter.open_array_section("Errors");
+  s->formatter->open_array_section("Errors");
   for (const auto fail_desc : failures) {
-    formatter.open_array_section("object");
+    s->formatter->open_array_section("object");
 
     stringstream ss_name;
     ss_name << fail_desc.path;
-    encode_json("Name", ss_name.str(), &formatter);
+    encode_json("Name", ss_name.str(), s->formatter);
 
-    rgw_err err;
-    set_req_state_err(err, fail_desc.err, prot_flags);
+    swift_err err(s);
+    err.set_rgw_err(fail_desc.err);
     string status;
     dump_errno(err, status);
-    encode_json("Status", status, &formatter);
-    formatter.close_section();
+    encode_json("Status", status, s->formatter);
+    s->formatter->close_section();
   }
-  formatter.close_section();
+  s->formatter->close_section();
 
-  formatter.close_section();
+  s->formatter->close_section();
 }
 
 int RGWDeleteObj_ObjStore_SWIFT::verify_permission()
@@ -1052,7 +1067,7 @@ void RGWDeleteObj_ObjStore_SWIFT::send_response()
     r = STATUS_NO_CONTENT;
   }
 
-  set_req_state_err(s, r);
+  s->set_req_state_err(r);
   dump_errno(s);
 
   if (multipart_delete) {
@@ -1063,10 +1078,9 @@ void RGWDeleteObj_ObjStore_SWIFT::send_response()
       bulkdelete_respond(deleter->get_num_deleted(),
                          deleter->get_num_unfound(),
                          deleter->get_failures(),
-                         s->prot_flags,
-                         *s->formatter);
+                         s);
     } else if (-ENOENT == op_ret) {
-      bulkdelete_respond(0, 1, {}, s->prot_flags, *s->formatter);
+      bulkdelete_respond(0, 1, {}, s);
     } else {
       RGWBulkDelete::acct_path_t path;
       path.bucket_name = s->bucket_name;
@@ -1076,7 +1090,7 @@ void RGWDeleteObj_ObjStore_SWIFT::send_response()
       fail_desc.err = op_ret;
       fail_desc.path = path;
 
-      bulkdelete_respond(0, 0, { fail_desc }, s->prot_flags, *s->formatter);
+      bulkdelete_respond(0, 0, { fail_desc }, s);
     }
   } else {
     end_header(s, this);
@@ -1190,7 +1204,7 @@ void RGWCopyObj_ObjStore_SWIFT::send_partial_response(off_t ofs)
   if (! sent_header) {
     if (! op_ret)
       op_ret = STATUS_CREATED;
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
     dump_errno(s);
     end_header(s, this);
 
@@ -1227,7 +1241,7 @@ void RGWCopyObj_ObjStore_SWIFT::send_response()
     string content_type;
     if (! op_ret)
       op_ret = STATUS_CREATED;
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
     dump_errno(s);
     dump_etag(s, etag);
     dump_last_modified(s, mtime);
@@ -1289,14 +1303,14 @@ int RGWGetObj_ObjStore_SWIFT::send_response_data(bufferlist& bl,
   }
 
   if (custom_http_ret) {
-    set_req_state_err(s, 0);
+    s->set_req_state_err(0);
     dump_errno(s, custom_http_ret);
   } else {
-    set_req_state_err(s, (partial_content && !op_ret) ? STATUS_PARTIAL_CONTENT
+    s->set_req_state_err((partial_content && !op_ret) ? STATUS_PARTIAL_CONTENT
                    : op_ret);
     dump_errno(s);
 
-    if (s->err.is_err()) {
+    if (s->is_err()) {
       end_header(s, NULL);
       return 0;
     }
@@ -1306,7 +1320,7 @@ int RGWGetObj_ObjStore_SWIFT::send_response_data(bufferlist& bl,
     dump_range(s, ofs, end, s->obj_size);
   }
 
-  if (s->err.is_err()) {
+  if (s->is_err()) {
     end_header(s, NULL);
     return 0;
   }
@@ -1359,7 +1373,7 @@ void RGWOptionsCORS_ObjStore_SWIFT::send_response()
   if (op_ret == -ENOENT)
     op_ret = -EACCES;
   if (op_ret < 0) {
-    set_req_state_err(s, op_ret);
+    s->set_req_state_err(op_ret);
     dump_errno(s);
     end_header(s, NULL);
     return;
@@ -1426,7 +1440,7 @@ int RGWBulkDelete_ObjStore_SWIFT::get_data(
 
 void RGWBulkDelete_ObjStore_SWIFT::send_response()
 {
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this /* RGWOp */, nullptr /* contype */,
              CHUNKED_TRANSFER_ENCODING);
@@ -1434,8 +1448,7 @@ void RGWBulkDelete_ObjStore_SWIFT::send_response()
   bulkdelete_respond(deleter->get_num_deleted(),
                      deleter->get_num_unfound(),
                      deleter->get_failures(),
-                     s->prot_flags,
-                     *s->formatter);
+                     s);
   rgw_flush_formatter_and_reset(s, s->formatter);
 }
 
@@ -1571,7 +1584,7 @@ void RGWBulkUploadOp_ObjStore_SWIFT::send_response()
 
 void RGWGetCrossDomainPolicy_ObjStore_SWIFT::send_response()
 {
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this, "application/xml");
 
@@ -1589,7 +1602,7 @@ void RGWGetCrossDomainPolicy_ObjStore_SWIFT::send_response()
 
 void RGWGetHealthCheck_ObjStore_SWIFT::send_response()
 {
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this, "application/xml");
 
@@ -1647,7 +1660,7 @@ void RGWInfo_ObjStore_SWIFT::send_response()
   if (op_ret <  0) {
     op_ret = STATUS_NO_CONTENT;
   }
-  set_req_state_err(s, op_ret);
+  s->set_req_state_err(op_ret);
   dump_errno(s);
   end_header(s, this);
   rgw_flush_formatter_and_reset(s, s->formatter);
@@ -2073,7 +2086,7 @@ int RGWSwiftWebsiteHandler::error_handler(const int err_no,
   const auto& ws_conf = s->bucket_info.website_conf;
 
   if (can_be_website_req() && ! ws_conf.error_doc.empty()) {
-    struct rgw_err err;
+    struct rgw_err err(s);
     set_req_state_err(err, err_no, s->prot_flags);
     return serve_errordoc(err.http_ret, ws_conf.error_doc);
   }
@@ -2131,7 +2144,7 @@ RGWOp* RGWSwiftWebsiteHandler::get_ws_redirect_op()
     }
 
     void send_response() override {
-      set_req_state_err(s, op_ret);
+      s->set_req_state_err(op_ret);
       dump_errno(s);
       dump_content_length(s, 0);
       dump_redirect(s, location);
@@ -2176,7 +2189,7 @@ RGWOp* RGWSwiftWebsiteHandler::get_ws_listing_op()
 
     void send_response() override {
       /* Generate the header now. */
-      set_req_state_err(s, op_ret);
+      s->set_req_state_err(op_ret);
       dump_errno(s);
       dump_container_metadata(s, bucket, bucket_quota,
                               s->bucket_info.website_conf);
@@ -2612,6 +2625,8 @@ int RGWHandler_REST_SWIFT::init_from_header(struct req_state* const s,
   string req;
   string first;
 
+  assert(!s->err);
+  s->err = new swift_err(s);
   s->prot_flags |= RGW_REST_SWIFT;
 
   char reqbuf[frontend_prefix.length() + s->decoded_uri.length() + 1];
index 9f38209deb36d5553454b5a0317be1dfaf84badd..0b1293e286f3c027ba7989c6ecf427b79ef241bb 100644 (file)
@@ -11,6 +11,7 @@
 #include "rgw_op.h"
 #include "rgw_rest.h"
 #include "rgw_swift_auth.h"
+#include "rgw_http_errors.h"
 
 #include <boost/utility/string_ref.hpp>
 
index cc26db4fcce50526f3a2f725d1931a1716c6af6a..4365385d8e5a3aae50b464fadef132f7d75f5edf 100644 (file)
@@ -627,7 +627,7 @@ void RGW_SWIFT_Auth_Get::execute()
   ret = STATUS_NO_CONTENT;
 
 done:
-  set_req_state_err(s, ret);
+  s->set_req_state_err(ret);
   dump_errno(s);
   end_header(s);
 }
index 79bffb2018f858e69ac90d445ebccafb24e5f2b2..b79fecb6a8567d09837fe12953e723eb0bbdba7d 100644 (file)
@@ -42,7 +42,6 @@ int rgw_get_system_obj(RGWRados *rgwstore, RGWObjectCtx& obj_ctx, const rgw_pool
                        RGWObjVersionTracker *objv_tracker, real_time *pmtime, map<string, bufferlist> *pattrs,
                        rgw_cache_entry_info *cache_info)
 {
-  struct rgw_err err;
   bufferlist::iterator iter;
   int request_len = READ_CHUNK_LEN;
   rgw_raw_obj obj(pool, key);
@@ -58,7 +57,6 @@ int rgw_get_system_obj(RGWRados *rgwstore, RGWObjectCtx& obj_ctx, const rgw_pool
 
     rop.stat_params.attrs = pattrs;
     rop.stat_params.lastmod = pmtime;
-    rop.stat_params.perr = &err;
 
     int ret = rop.stat(objv_tracker);
     if (ret < 0)