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;
goto done;
}
- abort_early(s, op, ret);
+ 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, 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) {
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<RGWObjectCtx *>(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 <Error>" << 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<RGWObjectCtx *>(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;
}