From dd3282c1f2346f9b799c0dd9dbaccdd9a91a49b0 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Fri, 14 Oct 2011 13:20:20 -0700 Subject: [PATCH] rgw: multiple swift fixes and cleanups --- src/rgw/rgw_common.cc | 39 ++++++++++++++++++++++++++++--- src/rgw/rgw_common.h | 12 +++++++++- src/rgw/rgw_formats.cc | 8 ++++++- src/rgw/rgw_op.cc | 7 +++++- src/rgw/rgw_rados.cc | 17 +++++--------- src/rgw/rgw_rest.cc | 48 ++++++++++++++++++++++++++------------- src/rgw/rgw_rest_s3.cc | 41 ++++----------------------------- src/rgw/rgw_rest_swift.cc | 20 ++++++++-------- src/rgw/rgw_swift_auth.cc | 2 +- 9 files changed, 113 insertions(+), 81 deletions(-) diff --git a/src/rgw/rgw_common.cc b/src/rgw/rgw_common.cc index 23a2e7de0f363..20fb7a0f88d79 100644 --- a/src/rgw/rgw_common.cc +++ b/src/rgw/rgw_common.cc @@ -92,14 +92,47 @@ std::ostream& operator<<(std::ostream& oss, const rgw_err &err) return oss; } +static bool check_str_end(const char *s) +{ + if (!s) + return false; + + while (*s) { + if (!isspace(*s)) + return false; + s++; + } + return true; +} + +static bool parse_rfc850(const char *s, struct tm *t) +{ + return check_str_end(strptime(s, "%A, %d-%b-%y %H:%M:%S GMT", t)); +} + +static bool parse_asctime(const char *s, struct tm *t) +{ + return check_str_end(strptime(s, "%a %b %d %H:%M:%S %Y", t)); +} + +static bool parse_rfc1123(const char *s, struct tm *t) +{ + return check_str_end(strptime(s, "%a, %d %b %Y %H:%M:%S GMT", t)); +} + +bool parse_rfc2616(const char *s, struct tm *t) +{ + return parse_rfc850(s, t) || parse_asctime(s, t) || parse_rfc1123(s, t); +} + int parse_time(const char *time_str, time_t *time) { struct tm tm; - memset(&tm, 0, sizeof(struct tm)); - if (!strptime(time_str, "%a, %d %b %Y %H:%M:%S %Z", &tm)) + + if (!parse_rfc2616(time_str, &tm)) return -EINVAL; - *time = mktime(&tm); + *time = timegm(&tm); return 0; } diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 8b88fc1a438d1..de8980f285492 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -96,6 +96,11 @@ using ceph::crypto::MD5; state->bytes_received += olen; \ } while (0) +#define STATUS_CREATED 1900 +#define STATUS_ACCEPTED 1901 +#define STATUS_NO_CONTENT 1902 +#define STATUS_PARTIAL_CONTENT 1903 + #define ERR_INVALID_BUCKET_NAME 2000 #define ERR_INVALID_OBJECT_NAME 2001 #define ERR_NO_SUCH_BUCKET 2002 @@ -110,6 +115,9 @@ using ceph::crypto::MD5; #define ERR_LENGTH_REQUIRED 2011 #define ERR_REQUEST_TIME_SKEWED 2012 #define ERR_BUCKET_EXISTS 2013 +#define ERR_BAD_URL 2014 +#define ERR_PRECONDITION_FAILED 2015 +#define ERR_NOT_MODIFIED 2016 #define ERR_USER_SUSPENDED 2100 #define ERR_INTERNAL_ERROR 2200 @@ -828,8 +836,10 @@ static inline const char *rgw_obj_category_name(RGWObjCategory category) return "unknown"; } -/** */ +/** time parsing */ extern int parse_time(const char *time_str, time_t *time); +extern bool parse_rfc2616(const char *s, struct tm *t); + /** Check if a user has a permission on that ACL */ extern bool verify_permission(RGWAccessControlPolicy *policy, string& uid, int user_perm_mask, int perm); /** Check if the req_state's user has the necessary permissions diff --git a/src/rgw/rgw_formats.cc b/src/rgw/rgw_formats.cc index b392224555ebb..092cc028df71d 100644 --- a/src/rgw/rgw_formats.cc +++ b/src/rgw/rgw_formats.cc @@ -118,6 +118,7 @@ void RGWFormatter_Plain::dump_format(const char *name, const char *fmt, ...) { char buf[LARGE_SIZE]; va_list ap; + const char *format; struct plain_stack_entry& entry = stack.back(); @@ -133,7 +134,12 @@ void RGWFormatter_Plain::dump_format(const char *name, const char *fmt, ...) va_start(ap, fmt); vsnprintf(buf, LARGE_SIZE, fmt, ap); va_end(ap); - write_data("%s\n", buf); + if (len) + format = "\n%s"; + else + format = "%s"; + + write_data(format, buf); } int RGWFormatter_Plain::get_len() const diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index cd4eb9194a26d..e4ee1b7f19a4b 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -267,7 +267,10 @@ void RGWGetObj::execute() if (ret < 0) goto done; - init_common(); + ret = init_common(); + if (ret < 0) + goto done; +dout(0) << __FILE__ << ":" << __LINE__ << " unmod_ptr=" << (void *)unmod_ptr << dendl; obj.init(s->bucket, s->object_str); rgwstore->set_atomic(s->obj_ctx, obj); @@ -315,10 +318,12 @@ int RGWGetObj::init_common() mod_ptr = &mod_time; } +dout(0) << __FILE__ << ":" << __LINE__ << " if_unmod=" << (void *)if_unmod << dendl; if (if_unmod) { if (parse_time(if_unmod, &unmod_time) < 0) return -EINVAL; unmod_ptr = &unmod_time; +dout(0) << __FILE__ << ":" << __LINE__ << " unmod_ptr=" << (void *)unmod_ptr << dendl; } return 0; diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index 815fcb586f43e..293a30fb574f4 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -1399,6 +1399,8 @@ int RGWRados::prepare_get_obj(void *ctx, rgw_obj& obj, goto done_err; } + dout(0) << __FILE__ << ":" << __LINE__ << " mod_ptr=" << (void *)mod_ptr << " unmod_ptr=" << (void *)unmod_ptr << dendl; + /* Convert all times go GMT to make them compatible */ if (mod_ptr || unmod_ptr) { struct tm mtm; @@ -1410,13 +1412,10 @@ int RGWRados::prepare_get_obj(void *ctx, rgw_obj& obj, } ctime = mktime(gmtm); - r = -ECANCELED; if (mod_ptr) { dout(10) << "If-Modified-Since: " << *mod_ptr << " Last-Modified: " << ctime << dendl; if (ctime < *mod_ptr) { - err->http_ret = 304; - err->s3_code = "NotModified"; - + r = -ERR_NOT_MODIFIED; goto done_err; } } @@ -1424,8 +1423,7 @@ int RGWRados::prepare_get_obj(void *ctx, rgw_obj& obj, if (unmod_ptr) { dout(10) << "If-UnModified-Since: " << *unmod_ptr << " Last-Modified: " << ctime << dendl; if (ctime > *unmod_ptr) { - err->http_ret = 412; - err->s3_code = "PreconditionFailed"; + r = -ERR_PRECONDITION_FAILED; goto done_err; } } @@ -1435,12 +1433,10 @@ int RGWRados::prepare_get_obj(void *ctx, rgw_obj& obj, if (r < 0) goto done_err; - r = -ECANCELED; if (if_match) { dout(10) << "ETag: " << etag.c_str() << " " << " If-Match: " << if_match << dendl; if (strcmp(if_match, etag.c_str())) { - err->http_ret = 412; - err->s3_code = "PreconditionFailed"; + r = -ERR_PRECONDITION_FAILED; goto done_err; } } @@ -1448,8 +1444,7 @@ int RGWRados::prepare_get_obj(void *ctx, rgw_obj& obj, if (if_nomatch) { dout(10) << "ETag: " << etag.c_str() << " " << " If-NoMatch: " << if_nomatch << dendl; if (strcmp(if_nomatch, etag.c_str()) == 0) { - err->http_ret = 304; - err->s3_code = "NotModified"; + r = -ERR_NOT_MODIFIED; goto done_err; } } diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index 14dd3a9224ff1..e562593e9fe99 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -28,10 +28,11 @@ struct rgw_html_errors { const static struct rgw_html_errors RGW_HTML_ERRORS[] = { { 0, 200, "" }, - { 201, 201, "Created" }, - { 202, 202, "Accepted" }, - { 204, 204, "NoContent" }, - { 206, 206, "" }, + { STATUS_CREATED, 201, "Created" }, + { STATUS_ACCEPTED, 202, "Accepted" }, + { STATUS_NO_CONTENT, 204, "NoContent" }, + { STATUS_PARTIAL_CONTENT, 206, "" }, + { ERR_NOT_MODIFIED, 304, "NotModified" }, { EINVAL, 400, "InvalidArgument" }, { ERR_INVALID_DIGEST, 400, "InvalidDigest" }, { ERR_BAD_DIGEST, 400, "BadDigest" }, @@ -53,6 +54,7 @@ const static struct rgw_html_errors RGW_HTML_ERRORS[] = { { ETIMEDOUT, 408, "RequestTimeout" }, { EEXIST, 409, "BucketAlreadyExists" }, { ENOTEMPTY, 409, "BucketNotEmpty" }, + { ERR_PRECONDITION_FAILED, 412, "PreconditionFailed" }, { ERANGE, 416, "InvalidRange" }, { ERR_INTERNAL_ERROR, 500, "InternalError" }, }; @@ -61,6 +63,7 @@ const static struct rgw_html_errors RGW_HTML_SWIFT_ERRORS[] = { { EACCES, 401, "AccessDenied" }, { EPERM, 401, "AccessDenied" }, { ERR_USER_SUSPENDED, 401, "UserSuspended" }, + { ERR_BAD_URL, 412, "Bad URL" }, }; #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0])) @@ -202,7 +205,7 @@ void end_header(struct req_state *s, const char *content_type) dump_start(s); s->formatter->open_object_section("Error"); if (!s->err.s3_code.empty()) - s->formatter->dump_format("Code", "%s", s->err.s3_code.c_str()); + s->formatter->dump_string("Code", s->err.s3_code.c_str()); if (!s->err.message.empty()) s->formatter->dump_format("Message", s->err.message.c_str()); s->formatter->close_section(); @@ -237,6 +240,7 @@ int RGWGetObj_REST::get_params() range_str = s->env->get("HTTP_RANGE"); if_mod = s->env->get("HTTP_IF_MODIFIED_SINCE"); if_unmod = s->env->get("HTTP_IF_UNMODIFIED_SINCE"); +dout(0) << __FILE__ << ":" << __LINE__ << " if_unmod=" << (void *)if_unmod << dendl; if_match = s->env->get("HTTP_IF_MATCH"); if_nomatch = s->env->get("HTTP_IF_NONE_MATCH"); @@ -396,7 +400,7 @@ static void next_tok(string& str, string& tok, char delim) } } -void init_entities_from_header(struct req_state *s) +static int init_entities_from_header(struct req_state *s) { string req; string first; @@ -430,7 +434,8 @@ void init_entities_from_header(struct req_state *s) } else { s->host_bucket = NULL; } - } else s->host_bucket = NULL; + } else + s->host_bucket = NULL; const char *req_name = s->path_name; const char *p; @@ -465,10 +470,25 @@ void init_entities_from_header(struct req_state *s) } } } else { + if (req.compare(g_conf->rgw_swift_url_prefix) == 0) { + s->prot_flags |= RGW_REST_SWIFT; + delete s->formatter; + s->format = 0; + s->formatter = new RGWFormatter_Plain; + return -ERR_BAD_URL; + } first = req; } if (s->prot_flags & RGW_REST_SWIFT) { + /* verify that the request_uri conforms with what's expected */ + char buf[g_conf->rgw_swift_url_prefix.length() + 16]; + int blen = sprintf(buf, "/%s/v1", g_conf->rgw_swift_url_prefix.c_str()); + if (s->path_name_url[0] != '/' || + s->path_name_url.compare(0, blen, buf) != 0) { + return -ENOENT; + } + s->format = 0; delete s->formatter; s->formatter = new RGWFormatter_Plain; @@ -529,6 +549,7 @@ void init_entities_from_header(struct req_state *s) } done: s->formatter->reset(); + return 0; } static void line_unfold(const char *line, string& sdest) @@ -747,7 +768,10 @@ int RGWHandler_REST::preprocess(struct req_state *s, FCGX_Request *fcgx) else s->op = OP_UNKNOWN; - init_entities_from_header(s); + ret = init_entities_from_header(s); + if (ret) + return ret; + switch (s->op) { case OP_PUT: if (s->object && !s->args.sub_resource_exists("acl")) { @@ -765,14 +789,6 @@ int RGWHandler_REST::preprocess(struct req_state *s, FCGX_Request *fcgx) break; } - if (s->prot_flags & RGW_REST_SWIFT) { - char buf[g_conf->rgw_swift_url_prefix.length() + 16]; - int blen = sprintf(buf, "/%s/v1", g_conf->rgw_swift_url_prefix.c_str()); - if (s->path_name_url[0] != '/' || - s->path_name_url.compare(0, blen, buf) != 0) - ret = -ENOENT; - } - if (ret) return ret; diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index f8c63b95bbd01..e79ff7240fa8f 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -72,7 +72,7 @@ int RGWGetObj_REST_S3::send_response(void *handle) } if (range_str && !ret) - ret = 206; /* partial content */ + ret = STATUS_PARTIAL_CONTENT; done: set_req_state_err(s, ret); @@ -177,7 +177,7 @@ void RGWDeleteBucket_REST_S3::send_response() { int r = ret; if (!r) - r = 204; + r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); @@ -200,7 +200,7 @@ void RGWDeleteObj_REST_S3::send_response() { int r = ret; if (!r) - r = 204; + r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); @@ -291,7 +291,7 @@ void RGWAbortMultipart_REST_S3::send_response() { int r = ret; if (!r) - r = 204; + r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); @@ -528,39 +528,6 @@ static void get_canon_resource(struct req_state *s, string& dest) dout(10) << "get_canon_resource(): dest=" << dest << dendl; } -static bool check_str_end(const char *s) -{ - if (!s) - return false; - - while (*s) { - if (!isspace(*s)) - return false; - s++; - } - return true; -} - -static bool parse_rfc850(const char *s, struct tm *t) -{ - return check_str_end(strptime(s, "%A, %d-%b-%y %H:%M:%S GMT", t)); -} - -static bool parse_asctime(const char *s, struct tm *t) -{ - return check_str_end(strptime(s, "%a %b %d %H:%M:%S %Y", t)); -} - -static bool parse_rfc1123(const char *s, struct tm *t) -{ - return check_str_end(strptime(s, "%a, %d %b %Y %H:%M:%S GMT", t)); -} - -static bool parse_rfc2616(const char *s, struct tm *t) -{ - return parse_rfc850(s, t) || parse_asctime(s, t) || parse_rfc1123(s, t); -} - static inline bool is_base64_for_content_md5(unsigned char c) { return (isalnum(c) || isspace(c) || (c == '+') || (c == '/') || (c == '=')); } diff --git a/src/rgw/rgw_rest_swift.cc b/src/rgw/rgw_rest_swift.cc index 67a2a33275f76..cf2dc4c188d8d 100644 --- a/src/rgw/rgw_rest_swift.cc +++ b/src/rgw/rgw_rest_swift.cc @@ -40,7 +40,7 @@ void RGWListBuckets_REST_SWIFT::send_response() s->formatter->close_section(); if (!ret && s->formatter->get_len() == 0) - ret = 204; + ret = STATUS_NO_CONTENT; set_req_state_err(s, ret); dump_errno(s); @@ -100,7 +100,7 @@ void RGWListBucket_REST_SWIFT::send_response() s->formatter->close_section(); if (!ret && s->formatter->get_len() == 0) - ret = 204; + ret = STATUS_NO_CONTENT; else if (ret > 0) ret = 0; @@ -140,7 +140,7 @@ static void dump_account_metadata(struct req_state *s, uint32_t buckets_count, void RGWStatAccount_REST_SWIFT::send_response() { if (ret >= 0) { - ret = 204; + ret = STATUS_NO_CONTENT; dump_account_metadata(s, buckets_count, buckets_objcount, buckets_size); } @@ -154,7 +154,7 @@ void RGWStatAccount_REST_SWIFT::send_response() void RGWStatBucket_REST_SWIFT::send_response() { if (ret >= 0) { - ret = 204; + ret = STATUS_NO_CONTENT; dump_container_metadata(s, bucket); } @@ -168,9 +168,9 @@ void RGWStatBucket_REST_SWIFT::send_response() void RGWCreateBucket_REST_SWIFT::send_response() { if (!ret) - ret = 201; // "created" + ret = STATUS_CREATED; else if (ret == -ERR_BUCKET_EXISTS) - ret = 202; + ret = STATUS_ACCEPTED; set_req_state_err(s, ret); dump_errno(s); end_header(s); @@ -181,7 +181,7 @@ void RGWDeleteBucket_REST_SWIFT::send_response() { int r = ret; if (!r) - r = 204; + r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); @@ -192,7 +192,7 @@ void RGWDeleteBucket_REST_SWIFT::send_response() void RGWPutObj_REST_SWIFT::send_response() { if (!ret) - ret = 201; // "created" + ret = STATUS_CREATED; dump_etag(s, etag.c_str()); set_req_state_err(s, ret); dump_errno(s); @@ -204,7 +204,7 @@ void RGWDeleteObj_REST_SWIFT::send_response() { int r = ret; if (!r) - r = 204; + r = STATUS_NO_CONTENT; set_req_state_err(s, r); dump_errno(s); @@ -248,7 +248,7 @@ int RGWGetObj_REST_SWIFT::send_response(void *handle) } if (range_str && !ret) - ret = 206; /* partial content */ + ret = -STATUS_PARTIAL_CONTENT; if (ret) set_req_state_err(s, ret); diff --git a/src/rgw/rgw_swift_auth.cc b/src/rgw/rgw_swift_auth.cc index 8305a0299c372..fe85b436673d1 100644 --- a/src/rgw/rgw_swift_auth.cc +++ b/src/rgw/rgw_swift_auth.cc @@ -178,7 +178,7 @@ void RGW_SWIFT_Auth_Get::execute() CGI_PRINTF(s, "X-Storage-Token: AUTH_rgwtk%s\n", buf); } - ret = 204; + ret = STATUS_NO_CONTENT; done: set_req_state_err(s, ret); -- 2.39.5