Skip to content

Commit

Permalink
COUCHDB-627 - Support all timezones
Browse files Browse the repository at this point in the history
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.

Also relates to COUCHDB-1513, a duplicate of COUCHDB-627.
  • Loading branch information
rnewson committed Aug 15, 2012
1 parent f5341a7 commit b1a049b
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 16 deletions.
4 changes: 2 additions & 2 deletions src/couch_replicator/src/couch_replicator.erl
Expand Up @@ -553,7 +553,7 @@ init_state(Rep) ->
committed_seq = StartSeq, committed_seq = StartSeq,
source_log = SourceLog, source_log = SourceLog,
target_log = TargetLog, target_log = TargetLog,
rep_starttime = httpd_util:rfc1123_date(), rep_starttime = couch_util:rfc1123_date(),
src_starttime = get_value(<<"instance_start_time">>, SourceInfo), src_starttime = get_value(<<"instance_start_time">>, SourceInfo),
tgt_starttime = get_value(<<"instance_start_time">>, TargetInfo), tgt_starttime = get_value(<<"instance_start_time">>, TargetInfo),
session_id = couch_uuids:random(), session_id = couch_uuids:random(),
Expand Down Expand Up @@ -706,7 +706,7 @@ do_checkpoint(State) ->
?LOG_INFO("recording a checkpoint for `~s` -> `~s` at source update_seq ~p", ?LOG_INFO("recording a checkpoint for `~s` -> `~s` at source update_seq ~p",
[SourceName, TargetName, NewSeq]), [SourceName, TargetName, NewSeq]),
StartTime = ?l2b(ReplicationStartTime), StartTime = ?l2b(ReplicationStartTime),
EndTime = ?l2b(httpd_util:rfc1123_date()), EndTime = ?l2b(couch_util:rfc1123_date()),
NewHistoryEntry = {[ NewHistoryEntry = {[
{<<"session_id">>, SessionId}, {<<"session_id">>, SessionId},
{<<"start_time">>, StartTime}, {<<"start_time">>, StartTime},
Expand Down
6 changes: 3 additions & 3 deletions src/couchdb/couch_httpd_misc_handlers.erl
Expand Up @@ -44,12 +44,12 @@ handle_welcome_req(Req, _) ->
send_method_not_allowed(Req, "GET,HEAD"). send_method_not_allowed(Req, "GET,HEAD").


handle_favicon_req(#httpd{method='GET'}=Req, DocumentRoot) -> handle_favicon_req(#httpd{method='GET'}=Req, DocumentRoot) ->
{{Year,Month,Day},Time} = erlang:localtime(), {{Year,Month,Day},Time} = erlang:universatime(),
OneYearFromNow = {{Year+1,Month,Day},Time}, OneYearFromNow = {{Year+1,Month,Day},Time},
CachingHeaders = [ CachingHeaders = [
%favicon should expire a year from now %favicon should expire a year from now
{"Cache-Control", "public, max-age=31536000"}, {"Cache-Control", "public, max-age=31536000"},
{"Expires", httpd_util:rfc1123_date(OneYearFromNow)} {"Expires", couch_util:rfc1123_date(OneYearFromNow)}
], ],
couch_httpd:serve_file(Req, "favicon.ico", DocumentRoot, CachingHeaders); couch_httpd:serve_file(Req, "favicon.ico", DocumentRoot, CachingHeaders);


Expand Down Expand Up @@ -103,7 +103,7 @@ handle_uuids_req(#httpd{method='GET'}=Req) ->
Etag = couch_httpd:make_etag(UUIDs), Etag = couch_httpd:make_etag(UUIDs),
couch_httpd:etag_respond(Req, Etag, fun() -> couch_httpd:etag_respond(Req, Etag, fun() ->
CacheBustingHeaders = [ CacheBustingHeaders = [
{"Date", httpd_util:rfc1123_date()}, {"Date", couch_util:rfc1123_date()},
{"Cache-Control", "no-cache"}, {"Cache-Control", "no-cache"},
% Past date, ON PURPOSE! % Past date, ON PURPOSE!
{"Expires", "Fri, 01 Jan 1990 00:00:00 GMT"}, {"Expires", "Fri, 01 Jan 1990 00:00:00 GMT"},
Expand Down
2 changes: 1 addition & 1 deletion src/couchdb/couch_log.erl
Expand Up @@ -159,7 +159,7 @@ log(#state{fd = Fd}, ConsoleMsg, FileMsg) ->
get_log_messages(Pid, Level, Format, Args) -> get_log_messages(Pid, Level, Format, Args) ->
ConsoleMsg = unicode:characters_to_binary(io_lib:format( ConsoleMsg = unicode:characters_to_binary(io_lib:format(
"[~s] [~p] " ++ Format ++ "~n", [Level, Pid | Args])), "[~s] [~p] " ++ Format ++ "~n", [Level, Pid | Args])),
FileMsg = ["[", httpd_util:rfc1123_date(), "] ", ConsoleMsg], FileMsg = ["[", couch_util:rfc1123_date(), "] ", ConsoleMsg],
{ConsoleMsg, iolist_to_binary(FileMsg)}. {ConsoleMsg, iolist_to_binary(FileMsg)}.




Expand Down
2 changes: 1 addition & 1 deletion src/couchdb/couch_server.erl
Expand Up @@ -170,7 +170,7 @@ init([]) ->
{ok, #server{root_dir=RootDir, {ok, #server{root_dir=RootDir,
dbname_regexp=RegExp, dbname_regexp=RegExp,
max_dbs_open=MaxDbsOpen, max_dbs_open=MaxDbsOpen,
start_time=httpd_util:rfc1123_date()}}. start_time=couch_util:rfc1123_date()}}.


terminate(_Reason, _Srv) -> terminate(_Reason, _Srv) ->
lists:foreach( lists:foreach(
Expand Down
42 changes: 42 additions & 0 deletions src/couchdb/couch_util.erl
Expand Up @@ -28,6 +28,7 @@
-export([url_strip_password/1]). -export([url_strip_password/1]).
-export([encode_doc_id/1]). -export([encode_doc_id/1]).
-export([with_db/2]). -export([with_db/2]).
-export([rfc1123_date/0, rfc1123_date/1]).


-include("couch_db.hrl"). -include("couch_db.hrl").


Expand Down Expand Up @@ -445,3 +446,44 @@ with_db(DbName, Fun) ->
Else -> Else ->
throw(Else) throw(Else)
end. end.

rfc1123_date() ->
{{YYYY,MM,DD},{Hour,Min,Sec}} = calendar:universal_time(),
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",
[day(DayNumber),DD,month(MM),YYYY,Hour,Min,Sec])).

rfc1123_date(undefined) ->
undefined;
rfc1123_date(UniversalTime) ->
{{YYYY,MM,DD},{Hour,Min,Sec}} = UniversalTime,
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",
[day(DayNumber),DD,month(MM),YYYY,Hour,Min,Sec])).

%% day

day(1) -> "Mon";
day(2) -> "Tue";
day(3) -> "Wed";
day(4) -> "Thu";
day(5) -> "Fri";
day(6) -> "Sat";
day(7) -> "Sun".

%% month

month(1) -> "Jan";
month(2) -> "Feb";
month(3) -> "Mar";
month(4) -> "Apr";
month(5) -> "May";
month(6) -> "Jun";
month(7) -> "Jul";
month(8) -> "Aug";
month(9) -> "Sep";
month(10) -> "Oct";
month(11) -> "Nov";
month(12) -> "Dec".
12 changes: 6 additions & 6 deletions src/mochiweb/mochiweb_cookies.erl
Expand Up @@ -49,9 +49,9 @@ cookie(Key, Value, Options) ->
RawAge -> RawAge ->
When = case proplists:get_value(local_time, Options) of When = case proplists:get_value(local_time, Options) of
undefined -> undefined ->
calendar:local_time(); calendar:universal_time();
LocalTime -> LocalTime ->
LocalTime calendar:local_time_to_universal_time_dst(LocalTime)
end, end,
Age = case RawAge < 0 of Age = case RawAge < 0 of
true -> true ->
Expand Down Expand Up @@ -115,12 +115,12 @@ quote(V0) ->
orelse erlang:error({cookie_quoting_required, V}), orelse erlang:error({cookie_quoting_required, V}),
V. V.


add_seconds(Secs, LocalTime) -> add_seconds(Secs, UniversalTime) ->
Greg = calendar:datetime_to_gregorian_seconds(LocalTime), Greg = calendar:datetime_to_gregorian_seconds(UniversalTime),
calendar:gregorian_seconds_to_datetime(Greg + Secs). calendar:gregorian_seconds_to_datetime(Greg + Secs).


age_to_cookie_date(Age, LocalTime) -> age_to_cookie_date(Age, UniversalTime) ->
httpd_util:rfc1123_date(add_seconds(Age, LocalTime)). couch_util:rfc1123_date(add_seconds(Age, UniversalTime)).


%% @spec parse_cookie(string()) -> [{K::string(), V::string()}] %% @spec parse_cookie(string()) -> [{K::string(), V::string()}]
%% @doc Parse the contents of a Cookie header field, ignoring cookie %% @doc Parse the contents of a Cookie header field, ignoring cookie
Expand Down
6 changes: 3 additions & 3 deletions src/mochiweb/mochiweb_request.erl
Expand Up @@ -600,9 +600,9 @@ maybe_redirect(RelPath, FullPath, ExtraHeaders) ->
end. end.


maybe_serve_file(File, ExtraHeaders) -> maybe_serve_file(File, ExtraHeaders) ->
case file:read_file_info(File) of case file:read_file_info(File, [{time, universal}]) of
{ok, FileInfo} -> {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") of case get_header_value("if-modified-since") of
LastModified -> LastModified ->
respond({304, ExtraHeaders, ""}); respond({304, ExtraHeaders, ""});
Expand All @@ -626,7 +626,7 @@ maybe_serve_file(File, ExtraHeaders) ->


server_headers() -> server_headers() ->
[{"Server", "MochiWeb/1.0 (" ++ ?QUIP ++ ")"}, [{"Server", "MochiWeb/1.0 (" ++ ?QUIP ++ ")"},
{"Date", httpd_util:rfc1123_date()}]. {"Date", couch_util:rfc1123_date()}].


make_code(X) when is_integer(X) -> make_code(X) when is_integer(X) ->
[integer_to_list(X), [" " | httpd_util:reason_phrase(X)]]; [integer_to_list(X), [" " | httpd_util:reason_phrase(X)]];
Expand Down

0 comments on commit b1a049b

Please sign in to comment.