From 6687734f7a43f7a6430e60b279b69f5213381c91 Mon Sep 17 00:00:00 2001 From: Andrew Tunnell-Jones Date: Fri, 29 Oct 2010 08:06:46 +0000 Subject: [PATCH] Don't depend on mochiweb_util. --- src/openid.erl | 15 ++------ src/openid_pm.erl | 56 ++++++++++++++++++++++++++++++ src/openid_utils.erl | 82 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 src/openid_pm.erl diff --git a/src/openid.erl b/src/openid.erl index 569431f..b2bd704 100644 --- a/src/openid.erl +++ b/src/openid.erl @@ -150,13 +150,13 @@ associate(OpURL) -> {"openid.dh_gen", base64:encode(roll(MG))}, {"openid.dh_consumer_public", base64:encode(roll(Public))}], - ReqBody = mochiweb_util:urlencode(Params), + ReqBody = openid_pm:url_encode(Params), Request = {OpURL, [], ?CONTENT_TYPE, ReqBody}, {ok, {_,_,Body}} = httpc:request(post, Request, [], []), - Response = parse_keyvalue(Body), + Response = openid_pm:kvf_decode(Body), Handle = ?GV("assoc_handle", Response), ExpiresIn = list_to_integer(?GV("expires_in", Response)), @@ -193,15 +193,6 @@ unroll(Bin) when is_binary(Bin) -> <>. -parse_keyvalue(Body) -> - lists:reverse(lists:foldl( - fun(E, A) -> [split_kv(E, [])|A] end, - [], string:tokens(Body, "\n"))). - -split_kv([$:|Rest], Buff) -> {lists:reverse(Buff), Rest}; -split_kv([C|Rest], Buff) -> split_kv(Rest, [C|Buff]). - - %% ------------------------------------------------------------ %% Authentication %% ------------------------------------------------------------ @@ -222,7 +213,7 @@ authentication_url(AuthReq, ReturnTo, Realm) -> {"openid.return_to", ReturnTo}, {"openid.realm", Realm}] ++ IDBits, - QueryString = mochiweb_util:urlencode(Params), + QueryString = openid_pm:uri_encode(Params), [URL|_] = AuthReq#openid_authreq.opURLs, diff --git a/src/openid_pm.erl b/src/openid_pm.erl new file mode 100644 index 0000000..b76f429 --- /dev/null +++ b/src/openid_pm.erl @@ -0,0 +1,56 @@ +-module(openid_pm). +-export([url_encode/1, uri_encode/1, kvf_encode/1, kvf_decode/1]). + +url_encode(PL) when is_list(PL) -> + encode(url, PL). + +uri_encode(PL) when is_list(PL) -> + encode(uri, PL). + +kvf_encode(PL) when is_list(PL) -> + encode(kvf, PL). + +kvf_decode(Body) when is_list(Body) -> + [ split_kv(Pair) || Pair <- string:tokens(Body, "\n") ]. + +split_kv(Pair) when is_list(Pair) -> + {Key, [$:|Value]} = lists:splitwith(fun(C) -> C =/= $: end, Pair), + { Key, Value }. + +encode(Type, PL) when is_list(PL) andalso ((Type =:= uri) orelse (Type =:= url) orelse (Type =:= kvf)) -> + {Encoder, KVSep, PairSep} = case Type of + uri -> {fun openid_utils:url_encode/1, "=", "&"}; + url -> {fun openid_utils:uri_encode/1, "=", "&"}; + kvf -> {fun (X) -> X end, ":", ""} + end, + Pairs = lists:foldr( + fun({K, V}, Acc) -> + FormattedK = format_key(Type, K), + EncodedK = Encoder(FormattedK), + FormattedV = format_val(Type, V), + EncodedV = Encoder(FormattedV), + [ EncodedK ++ KVSep ++ EncodedV | Acc ] + end, [], PL), + string:join(Pairs, PairSep). + +format_key(Type, K) -> + String = to_string(K), + case String of + "openid." ++ Suffix -> + case Type of + kvf -> Suffix; + _ -> String + end; + Suffix -> + case Type of + kvf -> Suffix; + _ -> "openid." ++ String + end + end. + +format_val(kvf, V) -> to_string(V) ++ "\n"; +format_val(_Type, V) -> to_string(V). + +to_string(List) when is_list(List) -> List; +to_string(Binary) when is_binary(Binary) -> binary_to_list(Binary); +to_string(Atom) when is_atom(Atom) -> atom_to_list(Atom). diff --git a/src/openid_utils.erl b/src/openid_utils.erl index bc28fea..d126c26 100644 --- a/src/openid_utils.erl +++ b/src/openid_utils.erl @@ -7,7 +7,7 @@ %%%------------------------------------------------------------------- -module(openid_utils). --export([get_tags/2, get_tags/4]). +-export([get_tags/2, get_tags/4, url_encode/1, url_decode/1, uri_encode/1, uri_decode/1]). -include("openid.hrl"). @@ -63,3 +63,83 @@ check_val(V, V, PropList, Tail, {Buffer,Tag,Key,Val})-> find_tags(Tail, {[PropList|Buffer],Tag,Key,Val}); check_val(_, _, _, Tail, State) -> find_tags(Tail, State). + +%% Sourced with permission from Tim's repo at +%% http://github.com/tim/erlang-percent-encoding/blob/master/src/percent.erl + +-define(is_alphanum(C), C >= $A, C =< $Z; C >= $a, C =< $z; C >= $0, C =< $9). + +%% +%% Percent encoding/decoding as defined by the application/x-www-form-urlencoded +%% content type (http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1). +%% + +url_encode(Str) when is_list(Str) -> + url_encode(lists:reverse(Str, []), []). + +url_encode([X | T], Acc) when ?is_alphanum(X); X =:= $-; X =:= $_; X =:= $. -> + url_encode(T, [X | Acc]); +url_encode([32 | T], Acc) -> + url_encode(T, [$+ | Acc]); +url_encode([X | T], Acc) -> + NewAcc = [$%, hexchr_encode(X bsr 4), hexchr_encode(X band 16#0f) | Acc], + url_encode(T, NewAcc); +url_encode([], Acc) -> + Acc. + +url_decode(Str) when is_list(Str) -> + url_decode(Str, []). + +url_decode([$+ | T], Acc) -> + url_decode(T, [32 | Acc]); +url_decode([$%, A, B | T], Acc) -> + Char = (hexchr_decode(A) bsl 4) + hexchr_decode(B), + url_decode(T, [Char | Acc]); +url_decode([X | T], Acc) -> + url_decode(T, [X | Acc]); +url_decode([], Acc) -> + lists:reverse(Acc, []). + +%% +%% Percent encoding/decoding as defined by RFC 3986 (http://tools.ietf.org/html/rfc3986). +%% + +uri_encode(Str) when is_list(Str) -> + uri_encode(lists:reverse(Str, []), []). + +uri_encode([X | T], Acc) when ?is_alphanum(X); X =:= $-; X =:= $_; X =:= $.; X =:= $~ -> + uri_encode(T, [X | Acc]); +uri_encode([X | T], Acc) -> + NewAcc = [$%, hexchr_encode(X bsr 4), hexchr_encode(X band 16#0f) | Acc], + uri_encode(T, NewAcc); +uri_encode([], Acc) -> + Acc. + +uri_decode(Str) when is_list(Str) -> + uri_decode(Str, []). + +uri_decode([$%, A, B | T], Acc) -> + Char = (hexchr_decode(A) bsl 4) + hexchr_decode(B), + uri_decode(T, [Char | Acc]); +uri_decode([X | T], Acc) -> + uri_decode(T, [X | Acc]); +uri_decode([], Acc) -> + lists:reverse(Acc, []). + +%% +%% Helper functions. +%% + +-compile({inline, [{hexchr_encode, 1}, {hexchr_decode, 1}]}). + +hexchr_encode(N) when N >= 10 andalso N < 16 -> + N + $A - 10; +hexchr_encode(N) when N >= 0 andalso N < 10 -> + N + $0. + +hexchr_decode(C) when C >= $a andalso C =< $f -> + C - $a + 10; +hexchr_decode(C) when C >= $A andalso C =< $F -> + C - $A + 10; +hexchr_decode(C) when C >= $0 andalso C =< $9 -> + C - $0.