From ac908e4efdbadadfbb180903d25e65db3bdfa0f3 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Mon, 24 Oct 2016 12:51:21 +0200 Subject: [PATCH] Fixed expiration, and cache-control: max-age implementation. Also use `FILE.date` instead of `FILE.change_date` (`change_date` is the date of the last status change, quite often same as creation date, while `date` is the last modification date). --- .../protocol/http/src/http_header_modifier.e | 11 ++++- .../wsf/router/wsf_file_system_handler.e | 31 +++++++----- .../wsf/src/response/wsf_file_response.e | 49 ++++++++++++------- 3 files changed, 59 insertions(+), 32 deletions(-) diff --git a/library/network/protocol/http/src/http_header_modifier.e b/library/network/protocol/http/src/http_header_modifier.e index 44ccd191..9c06a9f9 100644 --- a/library/network/protocol/http/src/http_header_modifier.e +++ b/library/network/protocol/http/src/http_header_modifier.e @@ -508,9 +508,16 @@ feature -- Others put_expires (a_seconds: INTEGER) -- Put "Expires" header to `a_seconds' seconds + -- and also "Cache-Control: max-age=.." . + -- To be supported by most browser. + local + dt: DATE_TIME do - put_expires_string (a_seconds.out) - end + create dt.make_now_utc + dt.second_add (a_seconds) + put_expires_date (dt) + put_cache_control ("max-age=" + a_seconds.out) + end put_expires_string (a_expires: STRING) -- Put "Expires" header with `a_expires' string value diff --git a/library/server/wsf/router/wsf_file_system_handler.e b/library/server/wsf/router/wsf_file_system_handler.e index 9a17cb7c..9cd4f647 100644 --- a/library/server/wsf/router/wsf_file_system_handler.e +++ b/library/server/wsf/router/wsf_file_system_handler.e @@ -39,6 +39,7 @@ feature {NONE} -- Initialization make_with_path (d: like document_root) do + max_age := -1 if d.is_empty then document_root := execution_environment.current_working_path else @@ -87,6 +88,7 @@ feature -- Access document_root: PATH max_age: INTEGER + -- Max age, initialized at -1 by default. index_disabled: BOOLEAN -- Index disabled? @@ -367,15 +369,17 @@ feature -- Execution create fres.make_with_content_type (ct, f.path.name) fres.set_status_code ({HTTP_STATUS_CODE}.ok) - -- cache control + -- cache control create dt.make_now_utc - fres.header.put_cache_control ("private, max-age=" + max_age.out) fres.header.put_utc_date (dt) - if max_age > 0 then - dt := dt.twin - dt.second_add (max_age) + if max_age >= 0 then + fres.set_max_age (max_age) + if max_age > 0 then + dt := dt.twin + dt.second_add (max_age) + end + fres.set_expires_date (dt) end - fres.header.put_expires_date (dt) fres.set_answer_head_request_method (req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head)) res.send (fres) @@ -388,14 +392,15 @@ feature -- Execution do create dt.make_now_utc create h.make - h.put_cache_control ("private, max-age=" + max_age.out) h.put_utc_date (dt) - if max_age > 0 then - dt := dt.twin - dt.second_add (max_age) + if max_age >= 0 then + h.put_cache_control ("max-age=" + max_age.out) + if max_age > 0 then + dt := dt.twin + dt.second_add (max_age) + end + h.put_expires_date (dt) end - h.put_expires_date (dt) - if a_utc_date /= Void then h.put_last_modified (a_utc_date) end @@ -637,7 +642,7 @@ feature {NONE} -- implementation: date time end note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" + copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/src/response/wsf_file_response.e b/library/server/wsf/src/response/wsf_file_response.e index 28b21ff2..6005d860 100644 --- a/library/server/wsf/src/response/wsf_file_response.e +++ b/library/server/wsf/src/response/wsf_file_response.e @@ -1,8 +1,7 @@ note - description : "Objects that ..." - author : "$Author$" - date : "$Date$" - revision : "$Revision$" + description: "Response to send a file back to the client" + date: "$Date$" + revision: "$Revision$" class WSF_FILE_RESPONSE @@ -105,22 +104,46 @@ feature {NONE} -- Initialization feature -- Element change - set_expires_in_seconds (sec: INTEGER) + set_max_age (sec: INTEGER) do - set_expires (sec.out) + header.put_cache_control ("max-age=" + sec.out) + end + + set_public_max_age (sec: INTEGER) + do + header.put_cache_control ("public, max-age=" + sec.out) + end + + set_private_max_age (sec: INTEGER) + do + header.put_cache_control ("private, max-age=" + sec.out) + end + + set_expires_in_seconds (sec: INTEGER) + -- Set Expires and Cache-control: max-age... to value related `sec' seconds. + do + header.put_expires (sec) end set_expires (s: STRING) + -- Set Expires header value to `s'. do header.put_expires_string (s) end + set_expires_date (dt: DATE_TIME) + -- Set Expires header value to date time `dt'. + do + header.put_expires_date (dt) + end + set_no_cache local h: like header do h := header h.put_expires (0) + h.put_cache_control ("max-age=0") h.put_cache_control ("no-cache, must-revalidate") h.put_pragma_no_cache end @@ -250,7 +273,7 @@ feature {NONE} -- Implementation: file system helper f: RAW_FILE do create f.make_with_path (file_path) - create Result.make_from_epoch (f.change_date) + create Result.make_from_epoch (f.date) end file_extension (fn: PATH): STRING_32 @@ -293,19 +316,11 @@ feature {NONE} -- Implementation: output create f.make_with_path (fn) check f.is_readable end - f.open_read - from - until - f.exhausted - loop - f.read_stream (4_096) - res.put_string (f.last_string) - end - f.close + res.put_file_content (f, 0, f.count) end note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software