Browse Source

Add new module cow_base64url

It implements the algorithm found in RFC 7515 Appendix C
https://tools.ietf.org/html/rfc7515#appendix-C with an
option to switch between with/no padding variants.

Relace the cow_multipart:boundary function to use this
and fix issues with agents which do not support slashes
in the boundary characters.
Loïc Hoguin 7 years ago
parent
commit
0eb0db3653
3 changed files with 83 additions and 2 deletions
  1. 1 1
      ebin/cowlib.app
  2. 81 0
      src/cow_base64url.erl
  3. 1 1
      src/cow_multipart.erl

+ 1 - 1
ebin/cowlib.app

@@ -1,7 +1,7 @@
 {application, 'cowlib', [
 	{description, "Support library for manipulating Web protocols."},
 	{vsn, "2.0.0-pre.1"},
-	{modules, ['cow_cookie','cow_date','cow_hpack','cow_http','cow_http2','cow_http_hd','cow_http_te','cow_mimetypes','cow_multipart','cow_qs','cow_spdy','cow_sse','cow_uri','cow_ws']},
+	{modules, ['cow_base64url','cow_cookie','cow_date','cow_hpack','cow_http','cow_http2','cow_http_hd','cow_http_te','cow_mimetypes','cow_multipart','cow_qs','cow_spdy','cow_sse','cow_uri','cow_ws']},
 	{registered, []},
 	{applications, [kernel,stdlib,crypto]},
 	{env, []}

+ 81 - 0
src/cow_base64url.erl

@@ -0,0 +1,81 @@
+%% Copyright (c) 2017, Loïc Hoguin <essen@ninenines.eu>
+%%
+%% Permission to use, copy, modify, and/or distribute this software for any
+%% purpose with or without fee is hereby granted, provided that the above
+%% copyright notice and this permission notice appear in all copies.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+%% This module implements "base64url" following the algorithm
+%% found in Appendix C of RFC7515. The option #{padding => false}
+%% must be given to reproduce this variant exactly. The default
+%% will leave the padding characters.
+-module(cow_base64url).
+
+-export([decode/1]).
+-export([decode/2]).
+-export([encode/1]).
+-export([encode/2]).
+
+-ifdef(TEST).
+-include_lib("proper/include/proper.hrl").
+-endif.
+
+decode(Enc) ->
+	decode(Enc, #{}).
+
+decode(Enc0, Opts) ->
+	Enc1 = << << case C of
+		$- -> $+;
+		$_ -> $/;
+		_ -> C
+	end >> || << C >> <= Enc0 >>,
+	Enc = case Opts of
+		#{padding := false} ->
+			case byte_size(Enc1) rem 4 of
+				0 -> Enc1;
+				2 -> << Enc1/binary, "==" >>;
+				3 -> << Enc1/binary, "=" >>
+			end;
+		_ ->
+			Enc1
+	end,
+	base64:decode(Enc).
+
+encode(Dec) ->
+	encode(Dec, #{}).
+
+encode(Dec, Opts) ->
+	encode(base64:encode(Dec), Opts, <<>>).
+
+encode(<<$+, R/bits>>, Opts, Acc) -> encode(R, Opts, <<Acc/binary, $->>);
+encode(<<$/, R/bits>>, Opts, Acc) -> encode(R, Opts, <<Acc/binary, $_>>);
+encode(<<$=, _/bits>>, #{padding := false}, Acc) -> Acc;
+encode(<<C, R/bits>>, Opts, Acc) -> encode(R, Opts, <<Acc/binary, C>>);
+encode(<<>>, _, Acc) -> Acc.
+
+-ifdef(TEST).
+
+rfc7515_test() ->
+	Dec = <<3,236,255,224,193>>,
+	Enc = <<"A-z_4ME">>,
+	Pad = <<"A-z_4ME=">>,
+	Dec = decode(<<Enc/binary,$=>>),
+	Dec = decode(Enc, #{padding => false}),
+	Pad = encode(Dec),
+	Enc = encode(Dec, #{padding => false}),
+	ok.
+
+prop_identity() ->
+	?FORALL(B, binary(), B =:= decode(encode(B))).
+
+prop_identity_no_padding() ->
+	?FORALL(B, binary(), B =:= decode(encode(B, #{padding => false}), #{padding => false})).
+
+-endif.

+ 1 - 1
src/cow_multipart.erl

@@ -424,7 +424,7 @@ horse_parse() ->
 
 -spec boundary() -> binary().
 boundary() ->
-	base64:encode(crypto:strong_rand_bytes(48)).
+	cow_base64url:encode(crypto:strong_rand_bytes(48), #{padding => false}).
 
 %% @doc Return the first part's head.
 %%