Codifica URL in Erlang
Domanda
Sto usando erlang http: richiesta per pubblicare alcuni dati su un servizio remoto. Ho il post funzionante ma i dati nel corpo () del post passano così come sono, senza alcuna codifica URL che causa il fallimento del post quando analizzato dal servizio remoto.
Esiste una funzione in Erlang simile a CGI.escape in Ruby per questo scopo?
Soluzione
Altri suggerimenti
Ho riscontrato la mancanza di questa funzione anche nei moduli HTTP.
Si scopre che questa funzionalità è effettivamente disponibile nella distribuzione erlang, devi solo sembrare abbastanza difficile.
> edoc_lib:escape_uri("luca+more@here.com").
"luca%2bmore%40here.com"
Questo si comporta come CGI.escape in Ruby, c'è anche URI.escape che si comporta in modo leggermente diverso:
> CGI.escape("luca+more@here.com")
=> "luca%2Bmore%40here.com"
> URI.escape("luca+more@here.com")
=> "luca+more@here.com"
Almeno in R15 c'è http_uri: encode / 1 che fa il lavoro. Inoltre, non consiglierei di usare edoc_lib: escape_uri perché sta traducendo un '=' in% 3d invece di un% 3D che mi ha causato qualche problema.
Ecco una semplice funzione che fa il lavoro. È progettato per funzionare direttamente con inets httpc.
%% @doc A function to URL encode form data.
%% @spec url_encode(formdata()).
-spec(url_encode(formdata()) -> string()).
url_encode(Data) ->
url_encode(Data,"").
url_encode([],Acc) ->
Acc;
url_encode([{Key,Value}|R],"") ->
url_encode(R, edoc_lib:escape_uri(Key) ++ "=" ++ edoc_lib:escape_uri(Value));
url_encode([{Key,Value}|R],Acc) ->
url_encode(R, Acc ++ "&" ++ edoc_lib:escape_uri(Key) ++ "=" ++ edoc_lib:escape_uri(Value)).
Esempio di utilizzo:
httpc:request(post, {"http://localhost:3000/foo", [],
"application/x-www-form-urlencoded",
url_encode([{"username", "bob"}, {"password", "123456"}])}
,[],[]).
Per rispondere alla mia domanda ... Ho trovato questa lib in ibrowse!
http: //www.erlware .org / lib / 5.6.3 / iBrowse-1.4 / ibrowse_lib.html # url_encode-1
url_encode/1
url_encode(Str) -> UrlEncodedStr
Str = string()
UrlEncodedStr = string()
URL codifica una stringa basata su RFC 1738. Restituisce un elenco semplice.
Immagino di poterlo utilizzare per eseguire la codifica e continuare a utilizzare http:
Se qualcuno ha bisogno di codificare uri che funziona con utf-8 in erlang:
https://gist.github.com/3796470
Ex.
Eshell V5.9.1 (abort with ^G)
1> c(encode_uri_rfc3986).
{ok,encode_uri_rfc3986}
2> encode_uri_rfc3986:encode("テスト").
"%e3%83%86%e3%82%b9%e3%83%88"
3> edoc_lib:escape_uri("テスト").
"%c3%86%c2%b9%c3%88" # output wrong: ƹÈ
Ecco un " fork " della funzione edoc_lib: escape_uri che migliora il supporto UTF-8 e supporta anche i binari.
escape_uri(S) when is_list(S) ->
escape_uri(unicode:characters_to_binary(S));
escape_uri(<<C:8, Cs/binary>>) when C >= $a, C =< $z ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C >= $A, C =< $Z ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C >= <*>, C =< $9 ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C == $. ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C == $- ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C == Ecco un " fork " della funzione edoc_lib: escape_uri che migliora il supporto UTF-8 e supporta anche i binari.
<*>
Nota che, a causa dell'uso di unicode: characters_to_binary, funzionerà solo in R13 o più recente.
->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) ->
escape_byte(C) ++ escape_uri(Cs);
escape_uri(<<>>) ->
"".
escape_byte(C) ->
"%" ++ hex_octet(C).
hex_octet(N) when N =< 9 ->
[<*> + N];
hex_octet(N) when N > 15 ->
hex_octet(N bsr 4) ++ hex_octet(N band 15);
hex_octet(N) ->
[N - 10 + $a].
Nota che, a causa dell'uso di unicode: characters_to_binary, funzionerà solo in R13 o più recente.
AFAIK non esiste un codificatore URL nelle librerie standard. Credo di aver "preso in prestito" il seguente codice da YAWS o forse uno degli altri server Web Erlang:
% Utility function to convert a 'form' of name-value pairs into a URL encoded
% content string.
urlencode(Form) ->
RevPairs = lists:foldl(fun({K,V},Acc) -> [[quote_plus(K),$=,quote_plus(V)] | Acc] end, [],Form),
lists:flatten(revjoin(RevPairs,<*>amp;,[])).
quote_plus(Atom) when is_atom(Atom) ->
quote_plus(atom_to_list(Atom));
quote_plus(Int) when is_integer(Int) ->
quote_plus(integer_to_list(Int));
quote_plus(String) ->
quote_plus(String, []).
quote_plus([], Acc) ->
lists:reverse(Acc);
quote_plus([C | Rest], Acc) when ?QS_SAFE(C) ->
quote_plus(Rest, [C | Acc]);
quote_plus([$\s | Rest], Acc) ->
quote_plus(Rest, [<*> | Acc]);
quote_plus([C | Rest], Acc) ->
<<Hi:4, Lo:4>> = <<C>>,
quote_plus(Rest, [hexdigit(Lo), hexdigit(Hi), ?PERCENT | Acc]).
revjoin([], _Separator, Acc) ->
Acc;
revjoin([S | Rest],Separator,[]) ->
revjoin(Rest,Separator,[S]);
revjoin([S | Rest],Separator,Acc) ->
revjoin(Rest,Separator,[S,Separator | Acc]).
hexdigit(C) when C < 10 -> <*> + C;
hexdigit(C) when C < 16 -> $A + (C - 10).