Browse Source

Document how to recover from cookie parsing errors

Loïc Hoguin 5 years ago
parent
commit
62836cdddc

+ 5 - 0
doc/src/manual/cowboy_req.match_cookies.asciidoc

@@ -31,6 +31,10 @@ be converted through the use of constraints, making this
 function able to extract, validate and convert values all
 in one step.
 
+This function will crash on invalid cookie data. How to
+handle this is explained in details in the manual page for
+link:man:cowboy_req:parse_cookies(3)[cowboy_req:parse_cookies(3)].
+
 == Arguments
 
 Fields::
@@ -85,4 +89,5 @@ An exception is triggered when the match fails.
 == See also
 
 link:man:cowboy_req(3)[cowboy_req(3)],
+link:man:cowboy_req:filter_cookies(3)[cowboy_req:filter_cookies(3)],
 link:man:cowboy_req:parse_cookies(3)[cowboy_req:parse_cookies(3)]

+ 30 - 4
doc/src/manual/cowboy_req.parse_cookies.asciidoc

@@ -18,10 +18,35 @@ Parse cookie headers.
 
 Alias for link:man:cowboy_req:parse_header(3)[cowboy_req:parse_header(<<"cookie">>, Req)].
 
-When the cookie header is missing, `[]` is returned.
-
-While an empty cookie header is not valid, some clients do
-send it. Cowboy will in this case also return `[]`.
+When the cookie header is missing or empty, `[]` is returned.
+
+This function will crash on invalid cookie data. Because
+invalid cookies are fairly common when dealing with browsers
+(because of the string interface that the Javascript API provides),
+it is recommended to filter the cookie header value before
+attempting to parse it. This can be accomplished by calling
+the function link:man:cowboy_req:filter_cookies(3)[cowboy_req:filter_cookies(3)]
+first. This does not guarantee that parsing succeeds. If it
+still fails it is recommended to send an error response or
+redirect with instructions to delete the relevant cookies:
+
+.Recover from cookie parsing errors
+[source,erlang]
+----
+Req1 = cowboy_req:filter_cookies([session_id, token], Req0),
+try cowboy_req:parse_cookies(Req1) of
+    Cookies ->
+        do_something(Req1, Cookies)
+catch _:_ ->
+    %% We can't parse the cookies we need, unset them
+    %% otherwise the browser will continue sending them.
+    Req2 = cowboy_req:set_resp_cookie(<<"session_id">>,
+        <<>>, Req1, #{max_age => 0}),
+    Req = cowboy_req:set_resp_cookie(<<"token">>,
+        <<>>, Req2, #{max_age => 0}),
+    cowboy_req:reply(500, Req)
+end.
+----
 
 == Arguments
 
@@ -52,4 +77,5 @@ Cookies = cowboy_req:parse_cookies(Req),
 
 link:man:cowboy_req(3)[cowboy_req(3)],
 link:man:cowboy_req:parse_header(3)[cowboy_req:parse_header(3)],
+link:man:cowboy_req:filter_cookies(3)[cowboy_req:filter_cookies(3)],
 link:man:cowboy_req:match_cookies(3)[cowboy_req:match_cookies(3)]