diff options
author | Adrian Villin <avillin@cisco.com> | 2024-08-16 15:23:28 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2024-08-22 06:09:43 +0000 |
commit | 7e6606ab4ea9501195b234fb14077ef4950f8d4e (patch) | |
tree | dabd65e48f4d17a07dc700a323e1b516a198c0e3 | |
parent | 8792e5c5c5e8e4f6c514ff81c97a7fb31890d657 (diff) |
http_static: added last-modified header
Type: improvement
Change-Id: I492df92ef25f9c0cd57fc8980500b58bebaa94c6
Signed-off-by: Adrian Villin <avillin@cisco.com>
-rw-r--r-- | extras/hs-test/http_test.go | 13 | ||||
-rw-r--r-- | src/plugins/http_static/http_cache.c | 22 | ||||
-rw-r--r-- | src/plugins/http_static/http_cache.h | 7 | ||||
-rw-r--r-- | src/plugins/http_static/static_server.c | 12 |
4 files changed, 42 insertions, 12 deletions
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index ffdcf930b8e..872f4c234b3 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -553,6 +553,8 @@ func HttpStaticFileHandlerTestFunction(s *NoTopoSuite, max_age string) { content := "<html><body><p>Hello</p></body></html>" content2 := "<html><body><p>Page</p></body></html>" + currentDate := time.Now().In(time.FixedZone("GMT", 0)).Format(http.TimeFormat)[:17] + vpp := s.GetContainerByName("vpp").VppInstance vpp.Container.Exec("mkdir -p " + wwwRootPath) err := vpp.Container.CreateFile(wwwRootPath+"/index.html", content) @@ -568,11 +570,16 @@ func HttpStaticFileHandlerTestFunction(s *NoTopoSuite, max_age string) { resp, err := client.Do(req) s.AssertNil(err, fmt.Sprint(err)) defer resp.Body.Close() + s.Log(DumpHttpResp(resp, true)) s.AssertEqual(200, resp.StatusCode) s.AssertContains(resp.Header.Get("Content-Type"), "html") s.AssertContains(resp.Header.Get("Cache-Control"), "max-age="+max_age) + // only checking date + s.AssertContains(resp.Header.Get("Last-Modified"), currentDate) + s.AssertEqual(len(resp.Header.Get("Last-Modified")), 29) s.AssertEqual(int64(len([]rune(content))), resp.ContentLength) + body, err := io.ReadAll(resp.Body) s.AssertNil(err, fmt.Sprint(err)) s.AssertEqual(string(body), content) @@ -589,6 +596,7 @@ func HttpStaticFileHandlerTestFunction(s *NoTopoSuite, max_age string) { s.AssertContains(resp.Header.Get("Content-Type"), "html") s.AssertContains(resp.Header.Get("Cache-Control"), "max-age="+max_age) s.AssertEqual(int64(len([]rune(content))), resp.ContentLength) + body, err = io.ReadAll(resp.Body) s.AssertNil(err, fmt.Sprint(err)) s.AssertEqual(string(body), content) @@ -603,6 +611,7 @@ func HttpStaticFileHandlerTestFunction(s *NoTopoSuite, max_age string) { s.AssertContains(resp.Header.Get("Content-Type"), "html") s.AssertContains(resp.Header.Get("Cache-Control"), "max-age="+max_age) s.AssertEqual(int64(len([]rune(content2))), resp.ContentLength) + body, err = io.ReadAll(resp.Body) s.AssertNil(err, fmt.Sprint(err)) s.AssertEqual(string(body), content2) @@ -828,7 +837,7 @@ func HttpStaticBuildInUrlPostIfStatsTest(s *NoTopoSuite) { } func HttpStaticMacTimeTest(s *NoTopoSuite) { - currentDate := time.Now().In(time.FixedZone("GMT", 0)).Format(http.TimeFormat) + currentDate := time.Now().In(time.FixedZone("GMT", 0)).Format(http.TimeFormat)[:17] vpp := s.GetContainerByName("vpp").VppInstance serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString() s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug")) @@ -848,6 +857,8 @@ func HttpStaticMacTimeTest(s *NoTopoSuite) { s.AssertContains(string(data), s.GetInterfaceByName(TapInterfaceName).Ip4AddressString()) s.AssertContains(string(data), s.GetInterfaceByName(TapInterfaceName).HwAddress.String()) s.AssertContains(resp.Header.Get("Content-Type"), "json") + s.AssertEqual(len(resp.Header.Get("Date")), 29) + // only checking date s.AssertContains(resp.Header.Get("Date"), currentDate) } diff --git a/src/plugins/http_static/http_cache.c b/src/plugins/http_static/http_cache.c index 7a069dace00..2e63e335d47 100644 --- a/src/plugins/http_static/http_cache.c +++ b/src/plugins/http_static/http_cache.c @@ -17,6 +17,8 @@ #include <vppinfra/bihash_template.c> #include <vppinfra/unix.h> #include <vlib/vlib.h> +#include <sys/stat.h> +#include <vppinfra/time_range.h> static void hss_cache_lock (hss_cache_t *hc) @@ -153,7 +155,7 @@ lru_update (hss_cache_t *hc, hss_cache_entry_t *ep, f64 now) static void hss_cache_attach_entry (hss_cache_t *hc, u32 ce_index, u8 **data, - u64 *data_len) + u64 *data_len, u8 **last_modified) { hss_cache_entry_t *ce; @@ -162,6 +164,7 @@ hss_cache_attach_entry (hss_cache_t *hc, u32 ce_index, u8 **data, ce->inuse++; *data = ce->data; *data_len = vec_len (ce->data); + *last_modified = ce->last_modified; /* Update the cache entry, mark it in-use */ lru_update (hc, ce, vlib_time_now (vlib_get_main ())); @@ -209,16 +212,15 @@ hss_cache_lookup (hss_cache_t *hc, u8 *path) u32 hss_cache_lookup_and_attach (hss_cache_t *hc, u8 *path, u8 **data, - u64 *data_len) + u64 *data_len, u8 **last_modified) { u32 ce_index; - /* Make sure nobody removes the entry while we look it up */ hss_cache_lock (hc); ce_index = hss_cache_lookup (hc, path); if (ce_index != ~0) - hss_cache_attach_entry (hc, ce_index, data, data_len); + hss_cache_attach_entry (hc, ce_index, data, data_len, last_modified); hss_cache_unlock (hc); @@ -260,6 +262,7 @@ hss_cache_do_evictions (hss_cache_t *hc) hc->cache_evictions++; vec_free (ce->filename); vec_free (ce->data); + vec_free (ce->last_modified); if (hc->debug_level > 1) clib_warning ("pool put index %d", ce - hc->cache_pool); @@ -271,13 +274,15 @@ hss_cache_do_evictions (hss_cache_t *hc) } u32 -hss_cache_add_and_attach (hss_cache_t *hc, u8 *path, u8 **data, u64 *data_len) +hss_cache_add_and_attach (hss_cache_t *hc, u8 *path, u8 **data, u64 *data_len, + u8 **last_modified) { BVT (clib_bihash_kv) kv; hss_cache_entry_t *ce; clib_error_t *error; u8 *file_data; u32 ce_index; + struct stat dm; hss_cache_lock (hc); @@ -298,11 +303,17 @@ hss_cache_add_and_attach (hss_cache_t *hc, u8 *path, u8 **data, u64 *data_len) pool_get_zero (hc->cache_pool, ce); ce->filename = vec_dup (path); ce->data = file_data; + if (stat ((char *) path, &dm) == 0) + { + ce->last_modified = + format (0, "%U GMT", format_clib_timebase_time, (f64) dm.st_mtime); + } /* Attach cache entry without additional lock */ ce->inuse++; *data = file_data; *data_len = vec_len (file_data); + *last_modified = ce->last_modified; lru_add (hc, ce, vlib_time_now (vlib_get_main ())); hc->cache_size += vec_len (ce->data); @@ -364,6 +375,7 @@ hss_cache_clear (hss_cache_t *hc) hc->cache_evictions++; vec_free (ce->filename); vec_free (ce->data); + vec_free (ce->last_modified); if (hc->debug_level > 1) clib_warning ("pool put index %d", ce - hc->cache_pool); pool_put (hc->cache_pool, ce); diff --git a/src/plugins/http_static/http_cache.h b/src/plugins/http_static/http_cache.h index a89ed5e7e94..21f71a924d5 100644 --- a/src/plugins/http_static/http_cache.h +++ b/src/plugins/http_static/http_cache.h @@ -22,6 +22,9 @@ typedef struct hss_cache_entry_ { /** Name of the file */ u8 *filename; + /** Last modified date, format: + * <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT */ + u8 *last_modified; /** Contents of the file, as a u8 * vector */ u8 *data; /** Last time the cache entry was used */ @@ -58,9 +61,9 @@ typedef struct hss_cache_ } hss_cache_t; u32 hss_cache_lookup_and_attach (hss_cache_t *hc, u8 *path, u8 **data, - u64 *data_len); + u64 *data_len, u8 **last_modified); u32 hss_cache_add_and_attach (hss_cache_t *hc, u8 *path, u8 **data, - u64 *data_len); + u64 *data_len, u8 **last_modified); void hss_cache_detach_entry (hss_cache_t *hc, u32 ce_index); u32 hss_cache_clear (hss_cache_t *hc); void hss_cache_init (hss_cache_t *hc, uword cache_size, u8 debug_level); diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c index 40de6cb578d..674ce8a0580 100644 --- a/src/plugins/http_static/static_server.c +++ b/src/plugins/http_static/static_server.c @@ -411,6 +411,7 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, u8 *path, *sanitized_path; u32 ce_index; http_content_type_t type; + u8 *last_modified; /* Feature not enabled */ if (!hsm->www_root) @@ -435,8 +436,8 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, hs->data_offset = 0; - ce_index = - hss_cache_lookup_and_attach (&hsm->cache, path, &hs->data, &hs->data_len); + ce_index = hss_cache_lookup_and_attach (&hsm->cache, path, &hs->data, + &hs->data_len, &last_modified); if (ce_index == ~0) { if (!file_path_is_valid (path)) @@ -455,8 +456,8 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, sc = try_index_file (hsm, hs, path); goto done; } - ce_index = - hss_cache_add_and_attach (&hsm->cache, path, &hs->data, &hs->data_len); + ce_index = hss_cache_add_and_attach (&hsm->cache, path, &hs->data, + &hs->data_len, &last_modified); if (ce_index == ~0) { sc = HTTP_STATUS_INTERNAL_ERROR; @@ -478,6 +479,9 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, http_add_header ( &hs->resp_headers, http_header_name_token (HTTP_HEADER_CACHE_CONTROL), (const char *) hsm->max_age_formatted, vec_len (hsm->max_age_formatted)); + http_add_header (&hs->resp_headers, + http_header_name_token (HTTP_HEADER_LAST_MODIFIED), + (const char *) last_modified, vec_len (last_modified)); done: vec_free (sanitized_path); |