COUCHDB-627 - Support all timezones Some timezones are incorrectly handled by OTP's calendar module. The ironic thing is that we only ever need the time in GMT (for HTTP response headers and the log file).
This patch duplicates httpd_util:rfc1123_date/0 and /1 but uses universal time everywhere, avoiding the broken conversion code. Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/d881aa32 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/d881aa32 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/d881aa32 Branch: refs/heads/COUCHDB-2734-header-date Commit: d881aa324fa9be686ac4f6f60a59d86374a4f8ff Parents: 8eb1f22 Author: Robert Newson <rnew...@apache.org> Authored: Wed Aug 15 12:34:48 2012 +0100 Committer: Robert Newson <robert.new...@uk.ibm.com> Committed: Thu Apr 17 19:13:02 2014 +0100 ---------------------------------------------------------------------- src/mochiweb_cookies.erl | 33 ++++++--------------------------- src/mochiweb_request.erl | 25 ++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/d881aa32/src/mochiweb_cookies.erl ---------------------------------------------------------------------- diff --git a/src/mochiweb_cookies.erl b/src/mochiweb_cookies.erl index 1cc4e91..5e474df 100644 --- a/src/mochiweb_cookies.erl +++ b/src/mochiweb_cookies.erl @@ -50,9 +50,9 @@ cookie(Key, Value, Options) -> RawAge -> When = case proplists:get_value(local_time, Options) of undefined -> - calendar:local_time(); + calendar:universal_time(); LocalTime -> - LocalTime + erlang:localtime_to_universaltime(LocalTime) end, Age = case RawAge < 0 of true -> @@ -116,33 +116,12 @@ quote(V0) -> orelse erlang:error({cookie_quoting_required, V}), V. - -%% Return a date in the form of: Wdy, DD-Mon-YYYY HH:MM:SS GMT -%% See also: rfc2109: 10.1.2 -rfc2109_cookie_expires_date(LocalTime) -> - {{YYYY,MM,DD},{Hour,Min,Sec}} = - case calendar:local_time_to_universal_time_dst(LocalTime) of - [] -> - {Date, {Hour1, Min1, Sec1}} = LocalTime, - LocalTime2 = {Date, {Hour1 + 1, Min1, Sec1}}, - case calendar:local_time_to_universal_time_dst(LocalTime2) of - [Gmt] -> Gmt; - [_,Gmt] -> Gmt - end; - [Gmt] -> Gmt; - [_,Gmt] -> Gmt - end, - DayNumber = calendar:day_of_the_week({YYYY,MM,DD}), - lists:flatten( - io_lib:format("~s, ~2.2.0w-~3.s-~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT", - [httpd_util:day(DayNumber),DD,httpd_util:month(MM),YYYY,Hour,Min,Sec])). - -add_seconds(Secs, LocalTime) -> - Greg = calendar:datetime_to_gregorian_seconds(LocalTime), +add_seconds(Secs, UniversalTime) -> + Greg = calendar:datetime_to_gregorian_seconds(UniversalTime), calendar:gregorian_seconds_to_datetime(Greg + Secs). -age_to_cookie_date(Age, LocalTime) -> - rfc2109_cookie_expires_date(add_seconds(Age, LocalTime)). +age_to_cookie_date(Age, UniversalTime) -> + couch_util:rfc1123_date(add_seconds(Age, UniversalTime)). %% @spec parse_cookie(string()) -> [{K::string(), V::string()}] %% @doc Parse the contents of a Cookie header field, ignoring cookie http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/d881aa32/src/mochiweb_request.erl ---------------------------------------------------------------------- diff --git a/src/mochiweb_request.erl b/src/mochiweb_request.erl index 859e2d6..d078e59 100644 --- a/src/mochiweb_request.erl +++ b/src/mochiweb_request.erl @@ -621,9 +621,9 @@ maybe_redirect(RelPath, FullPath, ExtraHeaders, end. maybe_serve_file(File, ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) -> - case file:read_file_info(File) of + case read_file_info(File) of {ok, FileInfo} -> - LastModified = httpd_util:rfc1123_date(FileInfo#file_info.mtime), + LastModified = couch_util:rfc1123_date(FileInfo#file_info.mtime), case get_header_value("if-modified-since", THIS) of LastModified -> respond({304, ExtraHeaders, ""}, THIS); @@ -645,9 +645,28 @@ maybe_serve_file(File, ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Ver not_found(ExtraHeaders, THIS) end. +read_file_info(File) -> + try + file:read_file_info(File, [{time, universal}]) + catch error:undef -> + case file:read_file_info(File) of + {ok, FileInfo} -> + {ok, FileInfo#file_info{ + atime=to_universal(FileInfo#file_info.atime), + mtime=to_universal(FileInfo#file_info.mtime), + ctime=to_universal(FileInfo#file_info.ctime) + }}; + Else -> + Else + end + end. + +to_universal(LocalTime) -> + erlang:localtime_to_universaltime(LocalTime). + server_headers() -> [{"Server", "MochiWeb/1.0 (" ++ ?QUIP ++ ")"}, - {"Date", httpd_util:rfc1123_date()}]. + {"Date", couch_util:rfc1123_date()}]. make_code(X) when is_integer(X) -> [integer_to_list(X), [" " | httpd_util:reason_phrase(X)]];