Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

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

Merged
merged 3 commits into from

2 participants

@saleyn

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
@saleyn 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
@saleyn saleyn Added test cases. 6abc02a
@saleyn saleyn Added more test cases. 5b7c019
@klacke
Owner

Very nice, thanks

@klacke klacke merged commit 1615f7d into klacke:master
@saleyn

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. @saleyn

    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. @saleyn

    Added test cases.

    saleyn authored
  3. @saleyn

    Added more test cases.

    saleyn authored
This page is out of date. Refresh to see the latest.
View
25 man/yaws_api.5
@@ -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
2  src/yaws.erl
@@ -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
38 src/yaws_api.erl
@@ -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])}}.
View
24 test/eunit/cookies.erl
@@ -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.