You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by wi...@apache.org on 2020/01/10 08:12:59 UTC

[couchdb-mochiweb] 02/32: fix cookie value parsing

This is an automated email from the ASF dual-hosted git repository.

willholley pushed a commit to branch upstream-2.20.0
in repository https://gitbox.apache.org/repos/asf/couchdb-mochiweb.git

commit 458eedf810b7417180a870077dbf957463adf08d
Author: Oleg Nemanov <le...@yandex.ru>
AuthorDate: Mon Mar 4 15:24:50 2019 +0300

    fix cookie value parsing
    
    Cookie value(according to RFC6265) can contain US-ASCII characters
    excluding CTLs, whitespace, DQUOTE, comma, semicolon and backslash:
    
    cookie-header = "Cookie:" OWS cookie-string OWS
    cookie-string = cookie-pair *( ";" SP cookie-pair )
    cookie-pair       = cookie-name "=" cookie-value
    cookie-value      = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
    cookie-octet      = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
    
    But mochiweb_cookie:parse_cookie() use smaller allowed characters list.
    For example, if cookie value is base64 string like MQ==,
    then parse_cookie() makes it MQ.
    
    Fix this by using a separate function for value parsing instead of
    read_token().
---
 src/mochiweb_cookies.erl | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/src/mochiweb_cookies.erl b/src/mochiweb_cookies.erl
index 013dbe0..b6afb65 100644
--- a/src/mochiweb_cookies.erl
+++ b/src/mochiweb_cookies.erl
@@ -39,6 +39,14 @@
          C =:= $[ orelse C =:= $] orelse C =:= $? orelse C =:= $= orelse
          C =:= ${ orelse C =:= $})).
 
+%% RFC 6265 cookie value allowed characters
+-define(IS_COOKIE_VAL_ALLOWED(C),
+        (C =:= 33
+         orelse (C >= 35 andalso C =< 43)
+         orelse (C >= 45 andalso C =< 58)
+         orelse (C >= 60 andalso C =< 91)
+         orelse (C >= 93 andalso C =< 126))).
+
 %% @type proplist() = [{Key::string(), Value::string()}].
 %% @type header() = {Name::string(), Value::string()}.
 %% @type int_seconds() = integer().
@@ -208,11 +216,15 @@ read_value([$= | Value]) ->
         [?QUOTE | _] ->
             read_quoted(Value1);
         _ ->
-            read_token(Value1)
+            read_value_(Value1)
     end;
 read_value(String) ->
     {"", String}.
 
+read_value_(String) ->
+    F = fun (C) -> ?IS_COOKIE_VAL_ALLOWED(C) end,
+    lists:splitwith(F, String).
+
 read_quoted([?QUOTE | String]) ->
     read_quoted(String, []).
 
@@ -302,6 +314,12 @@ parse_cookie_test() ->
     ?assertEqual(
        [{"foo", "bar"}, {"baz", "wibble"}],
        parse_cookie("foo=bar , baz=wibble ")),
+    ?assertEqual(
+       [{"foo", "base64=="}, {"bar", "base64="}],
+       parse_cookie("foo=\"base64==\";bar=\"base64=\"")),
+    ?assertEqual(
+       [{"foo", "base64=="}, {"bar", "base64="}],
+       parse_cookie("foo=base64==;bar=base64=")),
     ok.
 
 domain_test() ->