Permalink
Browse files

Added RFC6265 compliant variant of setcookie.

The new set_cookie/3 function implements more complete RFC2109
cookie formatting than setcookie/6 and is 10x - 15x more efficient
than its old setcookie counterpart because of avoiding the use of
io_lib:format/2.  The setcookie/2 through setcookie/6 are marked
as deprecated.  The function is named set_cookie rather than setcookie
to facilitate the ease of depricating the old implementation.
  • Loading branch information...
1 parent 1e7a122 commit 00c152bbe2a2bb14d8399a6f69a984db4ac04fca @saleyn saleyn committed Oct 6, 2012
Showing with 63 additions and 2 deletions.
  1. +24 −1 man/yaws_api.5
  2. +2 −0 src/yaws.erl
  3. +37 −1 src/yaws_api.erl
View
@@ -140,8 +140,31 @@ The equivalent of io_lib:format/2. This function is automatically
Htmlize an IO list object.
.TP
+\fBset_cookie(Name, Value, Options])\fR
+Sets a cookie to the browser. Options are:
+\fI
+.nf
+
+{expires, UtcTime} - Cookie expiration time, where UtcTime is
+ a tuple returned by calendar:universal_time/0.
+{max_age, Age} - Defines the lifetime of the cookie, in seconds,
+ where age is an integer >= 0.
+{path, Path} - Path is a string that specifies the subset of URLs to
+ which this cookie applies.
+{domain, Domain} - Domain is a string that specifies the domain for which
+ the cookie is valid.
+{comment, Comment} - Comment is a string that doccuments the server's
+ intended use of the cookie.
+secure - Directs the user agent to use only secure means to
+ contact the origin server whenever it sends back this
+ cookie.
+http_only - Restricts cookie access from other non-HTTP APIs.
+.fi
+\fR
+
+.TP
\fBsetcookie(Name, Value, [Path, [ Expire, [Domain , [Secure]]]])\fR
-Sets a cookie to the browser.
+Sets a cookie to the browser. This function is deprecated by set_cookie/3.
.TP
\fBfind_cookie_val(Cookie, Header)\fR
View
@@ -100,6 +100,8 @@
-export([parse_ipmask/1, match_ipmask/2]).
+%% Internal
+-export([local_time_as_gmt_string/1, universal_time_as_string/1]).
start() ->
application:start(yaws, permanent).
View
@@ -22,6 +22,12 @@
parse_multipart/2, parse_multipart/3]).
-export([code_to_phrase/1, ssi/2, redirect/1]).
-export([setcookie/2, setcookie/3, setcookie/4, setcookie/5, setcookie/6]).
+-deprecated([{setcookie, 2, eventually},
+ {setcookie, 3, eventually},
+ {setcookie, 4, eventually},
+ {setcookie, 5, eventually},
+ {setcookie, 6, eventually}]).
+-export([set_cookie/3]).
-export([pre_ssi_files/2, pre_ssi_string/1, pre_ssi_string/2,
set_content_type/1,
htmlize/1, htmlize_char/1, f/2, fl/1]).
@@ -683,7 +689,37 @@ secs() ->
{MS, S, _} = now(),
(MS * 1000000) + S.
-
+cookie_option(secure) ->
+ "; Secure";
+cookie_option(http_only) ->
+ "; HttpOnly";
+cookie_option(I) ->
+ throw({badarg, I}).
+cookie_option(expires, UTC) when is_tuple(UTC) ->
+ ["; Expires=" | yaws:universal_time_as_string(UTC)];
+cookie_option(max_age, Age) when is_integer(Age) ->
+ V = if Age < 0 -> "0"; true -> integer_to_list(Age) end,
+ ["; Max-Age=" | V];
+cookie_option(path, Path) when is_list(Path), Path =/= [] ->
+ ["; Path=" | Path];
+cookie_option(domain, Domain) when is_list(Domain), Domain =/= [] ->
+ ["; Domain=" | Domain];
+cookie_option(comment, Comment) when is_list(Comment), Comment=/= [] ->
+ ["; Comment=" | Comment];
+cookie_option(I, _) ->
+ throw({badarg, I}).
+
+%% @doc Generate a set_cookie header field tuple.
+%% This function is more RFC6265 compliant than setcookie/6 and
+%% therefore it deprecates setcookie/6 completely.
+set_cookie(Key, Value, Options)
+ when is_list(Key), is_list(Value), is_list(Options) ->
+ %% RFC6265 (4.1.1): Name=Value options must come first.
+ {NV,SV} = lists:foldl(fun
+ ({N,V}, {L1, L2}) -> {[cookie_option(N,V) | L1], L2};
+ (N, {L1, L2}) -> {L1, [cookie_option(N) | L2]}
+ end, {[], []}, Options),
+ {header, {set_cookie, [Key, $=, Value, "; Version=1", NV | SV]}}.
setcookie(Name, Value) ->
{header, {set_cookie, f("~s=~s;", [Name, Value])}}.

0 comments on commit 00c152b

Please sign in to comment.