From: Yehuda Sadeh Date: Wed, 27 Jan 2016 19:07:43 +0000 (-0800) Subject: Merge branch 'wip-rgw-static-website-yehuda' X-Git-Tag: v10.0.4~152^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=bf9d1a067a3c3baeb50744e089c2d73d11c3e68b;p=ceph.git Merge branch 'wip-rgw-static-website-yehuda' Conflicts: src/rgw/rgw_common.h src/rgw/rgw_op.h src/rgw/rgw_rest_s3.cc src/rgw/rgw_rest_s3.h --- bf9d1a067a3c3baeb50744e089c2d73d11c3e68b diff --cc src/rgw/rgw_common.h index 585facd1079d,b5a4d4867b29..1034b57e49dc --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@@ -161,7 -169,8 +169,9 @@@ using ceph::crypto::MD5 #define ERR_INVALID_SECRET_KEY 2034 #define ERR_INVALID_KEY_TYPE 2035 #define ERR_INVALID_CAP 2036 -#define ERR_WEBSITE_REDIRECT 2037 -#define ERR_NO_SUCH_WEBSITE_CONFIGURATION 2038 +#define ERR_INVALID_TENANT_NAME 2037 ++#define ERR_WEBSITE_REDIRECT 2038 ++#define ERR_NO_SUCH_WEBSITE_CONFIGURATION 2039 #define ERR_USER_SUSPENDED 2100 #define ERR_INTERNAL_ERROR 2200 #define ERR_NOT_IMPLEMENTED 2201 diff --cc src/rgw/rgw_main.cc index 3a4ad478e933,5fbee746055c..181d943c921a --- a/src/rgw/rgw_main.cc +++ b/src/rgw/rgw_main.cc @@@ -573,10 -574,10 +574,10 @@@ static int process_request(RGWRados *st should_log = mgr->get_logging(); - req->log(s, "getting op"); + req->log_format(s, "getting op %d", s->op); op = handler->get_op(store); if (!op) { - abort_early(s, NULL, -ERR_METHOD_NOT_ALLOWED); + abort_early(s, NULL, -ERR_METHOD_NOT_ALLOWED, handler); goto done; } req->op = op; @@@ -589,19 -591,31 +591,39 @@@ goto done; } + req->log(s, "normalizing buckets and tenants"); + ret = handler->postauth_init(); + if (ret < 0) { + dout(10) << "failed to run post-auth init" << dendl; - abort_early(s, op, ret); ++ abort_early(s, op, ret, handler); + goto done; + } + if (s->user.suspended) { dout(10) << "user is suspended, uid=" << s->user.user_id << dendl; - abort_early(s, op, -ERR_USER_SUSPENDED); + abort_early(s, op, -ERR_USER_SUSPENDED, handler); goto done; } + + req->log(s, "init permissions"); + ret = handler->init_permissions(op); + if (ret < 0) { + abort_early(s, op, ret, handler); + goto done; + } + + /** + * Only some accesses support website mode, and website mode does NOT apply + * if you are using the REST endpoint either (ergo, no authenticated access) + */ + req->log(s, "recalculating target"); + ret = handler->retarget(op, &op); + if (ret < 0) { + abort_early(s, op, ret, handler); + goto done; + } + req->op = op; + req->log(s, "reading permissions"); ret = handler->read_permissions(op); if (ret < 0) { diff --cc src/rgw/rgw_op.h index 7051e79f96f7,7f96d25f4af6..148e75093e8b --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@@ -1302,9 -1320,16 +1320,17 @@@ public virtual RGWOp *get_op(RGWRados *store); virtual void put_op(RGWOp *op); + virtual int init_permissions(RGWOp *op) { + return 0; + } + virtual int retarget(RGWOp *op, RGWOp **new_op) { + *new_op = op; + return 0; + } virtual int read_permissions(RGWOp *op) = 0; virtual int authorize() = 0; + virtual int postauth_init() = 0; + virtual int error_handler(int err_no, string *error_content); }; #endif diff --cc src/rgw/rgw_rest.h index 188022db6466,3ddd1bfb0a9a..8f1c4edf361a --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@@ -356,10 -356,14 +356,15 @@@ protected public: RGWHandler_ObjStore() {} virtual ~RGWHandler_ObjStore() {} + int init_permissions(RGWOp *op); int read_permissions(RGWOp *op); + virtual int retarget(RGWOp *op, RGWOp **new_op) { + *new_op = op; + return 0; + } virtual int authorize() = 0; + // virtual int postauth_init(struct req_init_state *t) = 0; }; class RGWHandler_ObjStore_SWIFT; diff --cc src/rgw/rgw_rest_s3.cc index 5ea703c42929,91eb4652537d..40db6fcbed44 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@@ -2685,11 -2816,180 +2820,180 @@@ RGWHandler *RGWRESTMgr_S3::get_handler( if (ret < 0) return NULL; - if (s->init_state.url_bucket.empty()) - return new RGWHandler_ObjStore_Service_S3; + RGWHandler* handler; + // TODO: Make this more readable + if (is_s3website) { - if (s->bucket_name.empty()) { ++ if (s->init_state.url_bucket.empty()) { + handler = new RGWHandler_ObjStore_Service_S3Website; + } else if (s->object.empty()) { + handler = new RGWHandler_ObjStore_Bucket_S3Website; + } else { + handler = new RGWHandler_ObjStore_Obj_S3Website; + } + } else { - if (s->bucket_name.empty()) { ++ if (s->init_state.url_bucket.empty()) { + handler = new RGWHandler_ObjStore_Service_S3; + } else if (s->object.empty()) { + handler = new RGWHandler_ObjStore_Bucket_S3; + } else { + handler = new RGWHandler_ObjStore_Obj_S3; + } + } + + ldout(s->cct, 20) << __func__ << " handler=" << typeid(*handler).name() << dendl; + return handler; + } + + int RGWHandler_ObjStore_S3Website::retarget(RGWOp *op, RGWOp **new_op) { + *new_op = op; + ldout(s->cct, 10) << __func__ << "Starting retarget" << dendl; + + if (!(s->prot_flags & RGW_REST_WEBSITE)) + return 0; + + RGWObjectCtx& obj_ctx = *static_cast(s->obj_ctx); + int ret = store->get_bucket_info(obj_ctx, s->bucket_tenant, s->bucket_name, s->bucket_info, NULL, &s->bucket_attrs); + if (ret < 0) { + // TODO-FUTURE: if the bucket does not exist, maybe expose it here? + return -ERR_NO_SUCH_BUCKET; + } + if (!s->bucket_info.has_website) { + // TODO-FUTURE: if the bucket has no WebsiteConfig, expose it here + return -ERR_NO_SUCH_WEBSITE_CONFIGURATION; + } + + rgw_obj_key new_obj; + s->bucket_info.website_conf.get_effective_key(s->object.name, &new_obj.name); + ldout(s->cct, 10) << "retarget get_effective_key " << s->object << " -> " << new_obj << dendl; + + RGWBWRoutingRule rrule; + bool should_redirect = s->bucket_info.website_conf.should_redirect(new_obj.name, 0, &rrule); + + if (should_redirect) { + const string& hostname = s->info.env->get("HTTP_HOST", ""); + const string& protocol = (s->info.env->get("SERVER_PORT_SECURE") ? "https" : "http"); + int redirect_code = 0; + rrule.apply_rule(protocol, hostname, s->object.name, &s->redirect, &redirect_code); + // APply a custom HTTP response code + if (redirect_code > 0) + 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; + return -ERR_WEBSITE_REDIRECT; + } + + /* + * FIXME: if s->object != new_obj, drop op and create a new op to handle operation. Or + * remove this comment if it's not applicable anymore + */ + + s->object = new_obj; + + return 0; + } + + RGWOp *RGWHandler_ObjStore_S3Website::op_get() + { + return get_obj_op(true); + } - if (s->object.empty()) - return new RGWHandler_ObjStore_Bucket_S3; + RGWOp *RGWHandler_ObjStore_S3Website::op_head() + { + return get_obj_op(false); + } + + int RGWHandler_ObjStore_S3Website::get_errordoc(const string errordoc_key, string *error_content) { + ldout(s->cct, 20) << "TODO Serve Custom error page here if bucket has " << dendl; + *error_content = errordoc_key; + // 1. Check if errordoc exists + // 2. Check if errordoc is public + // 3. Fetch errordoc content + /* + * FIXME maybe: need to make sure all of the fields for conditional requests are cleared + */ + RGWGetObj_ObjStore_S3Website *getop = new RGWGetObj_ObjStore_S3Website(true); + getop->set_get_data(true); + getop->init(store, s, this); + + RGWGetObj_CB cb(getop); + rgw_obj obj(s->bucket, errordoc_key); + RGWObjectCtx rctx(store); + //RGWRados::Object op_target(store, s->bucket_info, *static_cast(s->obj_ctx), obj); + RGWRados::Object op_target(store, s->bucket_info, rctx, obj); + RGWRados::Object::Read read_op(&op_target); + + int ret; + int64_t ofs = 0; + int64_t end = -1; + ret = read_op.prepare(&ofs, &end); + if (ret < 0) { + goto done; + } - return new RGWHandler_ObjStore_Obj_S3; + ret = read_op.iterate(ofs, end, &cb); // FIXME: need to know the final size? + done: + delete getop; + return ret; + } + + int RGWHandler_ObjStore_S3Website::error_handler(int err_no, string *error_content) { + const struct rgw_http_errors *r; + int http_error_code = -1; + r = search_err(err_no, RGW_HTTP_ERRORS, ARRAY_LEN(RGW_HTTP_ERRORS)); + if (r) { + http_error_code = r->http_ret; + } + + RGWBWRoutingRule rrule; + bool should_redirect = s->bucket_info.website_conf.should_redirect(s->object.name, http_error_code, &rrule); + + if (should_redirect) { + const string& hostname = s->info.env->get("HTTP_HOST", ""); + const string& protocol = (s->info.env->get("SERVER_PORT_SECURE") ? "https" : "http"); + int redirect_code = 0; + rrule.apply_rule(protocol, hostname, s->object.name, &s->redirect, &redirect_code); + // APply a custom HTTP response code + if (redirect_code > 0) + 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; + return -ERR_WEBSITE_REDIRECT; + } else if (!s->bucket_info.website_conf.error_doc.empty()) { + RGWHandler_ObjStore_S3Website::get_errordoc(s->bucket_info.website_conf.error_doc, error_content); + } else { + ldout(s->cct, 20) << "No special error handling today!" << dendl; + } + + return err_no; + } + + RGWOp *RGWHandler_ObjStore_Obj_S3Website::get_obj_op(bool get_data) + { + /** If we are in website mode, then it is explicitly impossible to run GET or + * HEAD on the actual directory. We must convert the request to run on the + * suffix object instead! + */ + RGWGetObj_ObjStore_S3Website *op = new RGWGetObj_ObjStore_S3Website; + op->set_get_data(get_data); + return op; + } + + RGWOp *RGWHandler_ObjStore_Bucket_S3Website::get_obj_op(bool get_data) + { + /** If we are in website mode, then it is explicitly impossible to run GET or + * HEAD on the actual directory. We must convert the request to run on the + * suffix object instead! + */ + RGWGetObj_ObjStore_S3Website *op = new RGWGetObj_ObjStore_S3Website; + op->set_get_data(get_data); + return op; + } + + RGWOp *RGWHandler_ObjStore_Service_S3Website::get_obj_op(bool get_data) + { + /** If we are in website mode, then it is explicitly impossible to run GET or + * HEAD on the actual directory. We must convert the request to run on the + * suffix object instead! + */ + RGWGetObj_ObjStore_S3Website *op = new RGWGetObj_ObjStore_S3Website; + op->set_get_data(get_data); + return op; } diff --cc src/rgw/rgw_rest_s3.h index e3b6030e6f40,9176f00e8be1..9e7d15b20275 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@@ -397,7 -421,10 +422,11 @@@ public virtual int authorize() { return RGW_Auth_S3::authorize(store, s); } + int postauth_init(); + virtual int retarget(RGWOp *op, RGWOp **new_op) { + *new_op = op; + return 0; + } }; class RGWHandler_ObjStore_Service_S3 : public RGWHandler_ObjStore_S3 {