From 234b6916a47869d84a705ea09d0c1646222f314d Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Fri, 23 Jul 2010 15:39:49 +0200 Subject: [PATCH] We shoud always return the Accept-Ranges header, with a GET or HEAD request, even when the client is not requesting for partial content. This is to let the client know we accept requests for partial content. On HEAD requests we should also return the Content-Length header. And we should also return the Last-Modified header with GET and HEAD requests, this way browsers and proxy's can cache content. --- src/rgw/rgw_access.h | 1 + src/rgw/rgw_fs.cc | 4 +++- src/rgw/rgw_fs.h | 1 + src/rgw/rgw_op.cc | 2 +- src/rgw/rgw_op.h | 1 + src/rgw/rgw_rados.cc | 5 ++++- src/rgw/rgw_rados.h | 1 + src/rgw/rgw_rest.cc | 28 +++++++++++++++++++++------- src/rgw/rgw_rest.h | 1 + src/rgw/rgw_user.cc | 5 +++-- 10 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/rgw/rgw_access.h b/src/rgw/rgw_access.h index ad8a895affadd..01a15f1766526 100644 --- a/src/rgw/rgw_access.h +++ b/src/rgw/rgw_access.h @@ -122,6 +122,7 @@ public: map *attrs, const time_t *mod_ptr, const time_t *unmod_ptr, + time_t *lastmod, const char *if_match, const char *if_nomatch, size_t *total_size, diff --git a/src/rgw/rgw_fs.cc b/src/rgw/rgw_fs.cc index c71d657652c90..b4c5de5bbf4ac 100644 --- a/src/rgw/rgw_fs.cc +++ b/src/rgw/rgw_fs.cc @@ -274,9 +274,10 @@ int RGWFS::copy_obj(std::string& id, std::string& dest_bucket, std::string& dest void *handle; off_t ofs = 0, end = -1; size_t total_len; + time_t lastmod; map attrset; - ret = prepare_get_obj(src_bucket, src_obj, 0, &end, &attrset, mod_ptr, unmod_ptr, + ret = prepare_get_obj(src_bucket, src_obj, 0, &end, &attrset, mod_ptr, unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &handle, err); if (ret < 0) return ret; @@ -421,6 +422,7 @@ int RGWFS::prepare_get_obj(std::string& bucket, std::string& obj, map *attrs, const time_t *mod_ptr, const time_t *unmod_ptr, + time_t *lastmod, const char *if_match, const char *if_nomatch, size_t *total_size, diff --git a/src/rgw/rgw_fs.h b/src/rgw/rgw_fs.h index d35ab13e2be94..5010bb21ed9d8 100644 --- a/src/rgw/rgw_fs.h +++ b/src/rgw/rgw_fs.h @@ -45,6 +45,7 @@ public: map *attrs, const time_t *mod_ptr, const time_t *unmod_ptr, + time_t *lastmod, const char *if_match, const char *if_nomatch, size_t *size, diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 54a2c94fb4bd6..c8e4fbe42ded3 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -142,7 +142,7 @@ void RGWGetObj::execute() init_common(); ret = rgwstore->prepare_get_obj(s->bucket_str, s->object_str, ofs, &end, &attrs, mod_ptr, - unmod_ptr, if_match, if_nomatch, &total_len, &handle, &err); + unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &handle, &err); if (ret < 0) goto done; diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h index 054d6eaf3faaf..2b74569908b7c 100644 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@ -54,6 +54,7 @@ protected: size_t total_len; off_t end; time_t mod_time; + time_t lastmod; time_t unmod_time; time_t *mod_ptr; time_t *unmod_ptr; diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index 257e3118d4b8c..cda70ab0c2d99 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -344,6 +344,7 @@ int RGWRados::copy_obj(std::string& id, std::string& dest_bucket, std::string& d char *data; off_t ofs = 0, end = -1; size_t total_len; + time_t lastmod; map::iterator iter; cerr << "copy " << src_bucket << ":" << src_obj << " => " << dest_bucket << ":" << dest_obj << std::endl; @@ -352,7 +353,7 @@ int RGWRados::copy_obj(std::string& id, std::string& dest_bucket, std::string& d map attrset; ret = prepare_get_obj(src_bucket, src_obj, ofs, &end, &attrset, - mod_ptr, unmod_ptr, if_match, if_nomatch, &total_len, &handle, err); + mod_ptr, unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &handle, err); if (ret < 0) return ret; @@ -511,6 +512,7 @@ int RGWRados::prepare_get_obj(std::string& bucket, std::string& oid, map *attrs, const time_t *mod_ptr, const time_t *unmod_ptr, + time_t *lastmod, const char *if_match, const char *if_nomatch, size_t *total_size, @@ -595,6 +597,7 @@ int RGWRados::prepare_get_obj(std::string& bucket, std::string& oid, *end = size - 1; *total_size = (ofs <= *end ? *end + 1 - ofs : 0); + *lastmod = mtime; return 0; diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h index f8bd34b42c72e..22d331ca4eb7e 100644 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@ -73,6 +73,7 @@ public: map *attrs, const time_t *mod_ptr, const time_t *unmod_ptr, + time_t *lastmod, const char *if_match, const char *if_nomatch, size_t *total_size, diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index 78e782a447b2c..8bf59f781dbae 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -85,6 +85,7 @@ void close_section(struct req_state *s, const char *name) static void dump_content_length(struct req_state *s, int len) { CGI_PRINTF(s->fcgx->out, "Content-Length: %d\n", len); + CGI_PRINTF(s->fcgx->out, "Accept-Ranges: %s\n", "bytes"); } static void dump_etag(struct req_state *s, const char *etag) @@ -92,6 +93,19 @@ static void dump_etag(struct req_state *s, const char *etag) CGI_PRINTF(s->fcgx->out,"ETag: \"%s\"\n", etag); } +static void dump_last_modified(struct req_state *s, time_t t) { + + char timestr[TIME_BUF_SIZE]; + struct tm *tmp = localtime(&t); + if (tmp == NULL) + return; + + if (strftime(timestr, sizeof(timestr), "%a, %d %b %Y %H:%M:%S %Z", tmp) == 0) + return; + + CGI_PRINTF(s->fcgx->out, "Last-Modified: %s\n", timestr); +} + void dump_value(struct req_state *s, const char *name, const char *fmt, ...) { #define LARGE_SIZE 8192 @@ -116,7 +130,6 @@ static void dump_entry(struct req_state *s, const char *val) void dump_time(struct req_state *s, const char *name, time_t *t) { -#define TIME_BUF_SIZE 128 char buf[TIME_BUF_SIZE]; struct tm *tmp = localtime(t); if (tmp == NULL) @@ -187,7 +200,6 @@ void abort_early(struct req_state *s, int err) void dump_range(struct req_state *s, off_t ofs, off_t end) { - CGI_PRINTF(s->fcgx->out,"Accept-Ranges: bytes\n", ""); CGI_PRINTF(s->fcgx->out,"Content-Range: bytes %d-%d/%d\n", (int)ofs, (int)end, (int)end + 1); } @@ -209,11 +221,12 @@ int RGWGetObj_REST::send_response(void *handle) if (sent_header) goto send_data; - if (get_data && !ret) { - if (range_str) - dump_range(s, ofs, end); - dump_content_length(s, total_len); - } + if (range_str) + dump_range(s, ofs, end); + + dump_content_length(s, total_len); + dump_last_modified(s, lastmod); + if (!ret) { map::iterator iter = attrs.find(RGW_ATTR_ETAG); if (iter != attrs.end()) { @@ -223,6 +236,7 @@ int RGWGetObj_REST::send_response(void *handle) dump_etag(s, etag); } } + for (iter = attrs.begin(); iter != attrs.end(); ++iter) { const char *name = iter->first.c_str(); if (strncmp(name, RGW_ATTR_META_PREFIX, sizeof(RGW_ATTR_META_PREFIX)-1) == 0) { diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h index dda33d4db0996..65495d343bef2 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -1,5 +1,6 @@ #ifndef CEPH_RGW_REST_H #define CEPH_RGW_REST_H +#define TIME_BUF_SIZE 128 #include "rgw_op.h" diff --git a/src/rgw/rgw_user.cc b/src/rgw/rgw_user.cc index 2a1c4404b729f..9749ebd43cfd4 100644 --- a/src/rgw/rgw_user.cc +++ b/src/rgw/rgw_user.cc @@ -28,9 +28,10 @@ int rgw_get_user_info(string user_id, RGWUserInfo& info) void *handle = NULL; off_t ofs = 0, end = -1; size_t total_len; + time_t lastmod; bufferlist::iterator iter; - ret = rgwstore->prepare_get_obj(ui_bucket, user_id, ofs, &end, NULL, NULL, NULL, NULL, NULL, &total_len, &handle, &err); + ret = rgwstore->prepare_get_obj(ui_bucket, user_id, ofs, &end, NULL, NULL, NULL, &lastmod, NULL, NULL, &total_len, &handle, &err); if (ret < 0) return ret; do { @@ -121,7 +122,7 @@ int rgw_get_uid_by_email(string& email, string& user_id) size_t total_len; ret = rgwstore->prepare_get_obj(ui_email_bucket, email, ofs, &end, NULL, NULL, - NULL, NULL, NULL, &total_len, &handle, &err); + NULL, NULL, NULL, NULL, &total_len, &handle, &err); if (ret < 0) return ret; do { -- 2.39.5