Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added RFC6265 compliant variant of yaws_api:set_cookie/3. #127

Merged
merged 3 commits into from

2 participants

Serge Aleynikov Claes Wikstrom
Serge Aleynikov

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.

saleyn added some commits
Serge Aleynikov saleyn 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.
00c152b
Serge Aleynikov saleyn Added test cases. 6abc02a
Serge Aleynikov saleyn Added more test cases. 5b7c019
Claes Wikstrom
Owner

Very nice, thanks

Claes Wikstrom klacke merged commit 1615f7d into from
Serge Aleynikov

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 6, 2012
  1. Serge Aleynikov

    Added RFC6265 compliant variant of setcookie.

    saleyn authored
    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.
  2. Serge Aleynikov

    Added test cases.

    saleyn authored
  3. Serge Aleynikov

    Added more test cases.

    saleyn authored
This page is out of date. Refresh to see the latest.
25 man/yaws_api.5
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
2  src/yaws.erl
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).
38 src/yaws_api.erl
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])}}.
24 test/eunit/cookies.erl
View
@@ -305,6 +305,30 @@ real_setcookies_test() ->
?assertEqual(ok, parse_set_cookies(Io, file:read_line(Io), 1)),
ok.
+set_cookie_test() ->
+ ?assertEqual(
+ "a=bcd; Version=1; Comment=OK; Domain=g.com; Path=/; Max-Age=1; "
+ "Expires=Tue, 03 Jan 2012 10:00:05 GMT; HttpOnly; Secure",
+ begin
+ {header, {set_cookie, L}} = yaws_api:set_cookie("a", "bcd",
+ [{expires, {{2012,1,3},{10,0,5}}},
+ {max_age, 1}, secure, http_only,
+ {path, "/"}, {domain, "g.com"}, {comment, "OK"}]),
+ lists:flatten(L)
+ end),
+ ?assertEqual(
+ "a=bcd; Version=1; Path=/home",
+ begin
+ {header, {set_cookie, L}} =
+ yaws_api:set_cookie("a", "bcd", [{path, "/home"}]),
+ lists:flatten(L)
+ end),
+ ?assertEqual(
+ "a=bcd; Version=1",
+ begin
+ {header, {set_cookie, L}} = yaws_api:set_cookie("a", "bcd", []),
+ lists:flatten(L)
+ end).
parse_cookies(Io, eof, _) ->
file:close(Io),
Something went wrong with that request. Please try again.