2008-09-22 2 views
16

Я использую erlang http: request для отправки некоторых данных в удаленную службу. У меня есть почта, но данные в теле() сообщения появляются, как есть, без какой-либо кодировки url, которая приводит к сбою сообщения при анализе удаленной службой.URL-адрес в Erlang

Есть ли функция в Эрланге, похожая на CGI.escape в Ruby для этой цели?

ответ

8

Вы можете найти здесь YAWS urlencode and urldecode routines

Они достаточно просты, хотя комментарии указывают закодировать не 100% полной для всех знаки пунктуации.

0

AFAIK В стандартных библиотеках нет кодировщика URL. Думаю, что я «заимствовал» следующий код из Yaws или, может быть, один из других веб-серверов 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,$&,[])). 

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 -> $0 + C; 
hexdigit(C) when C < 16 -> $A + (C - 10). 
4

Для того, чтобы ответить на мой собственный вопрос ... Я нашел этот LIB в 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-кодирует строку на основе RFC 1738. Возвращает плоский список.

Я думаю, я могу использовать это, чтобы сделать кодировку и до сих пор используют HTTP:

23

Я столкнулся с отсутствием этой функции в модулях HTTP.

Оказывается, эта функциональность действительно доступна в дистрибутиве erlang, вам просто нужно выглядеть достаточно сложно.

> edoc_lib:escape_uri("[email protected]"). 
"luca%2bmore%40here.com" 

Это ведет себя как CGI.escape в Ruby, есть также URI.escape, который ведет себя немного по-другому:

> CGI.escape("[email protected]") 
=> "luca%2Bmore%40here.com" 
> URI.escape("[email protected]") 
=> "[email protected]" 

edoc_lib

+1

Похоже, этот совет устарел - перейдите по ссылке, и вы увидите `edoc_lib: escape_uri` - MIA. Не уверен, что релиз erlang представил это изменение. – jtmoulia 2015-03-31 23:34:06

+0

[Он есть и экспортируется.] (Https://github.com/erlang/otp/blob/172e812c491680fbb175f56f7604d4098cdc9de4/lib/edoc/src/edoc_lib.erl#L382-L414). Я не уверен, почему это не в справочная страница. – mqsoh 2015-05-30 02:59:17

5

Вот простая функция, которая делает работу. Он предназначен для работы непосредственно с 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)). 

Пример использования:

httpc:request(post, {"http://localhost:3000/foo", [], 
        "application/x-www-form-urlencoded", 
        url_encode([{"username", "bob"}, {"password", "123456"}])} 
      ,[],[]). 
1

Вот "вилка" из edoc_lib: escape_uri функция, которая улучшает поддержку в UTF-8, а также поддерживает двоичные файлы.

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 >= $0, 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 == $_ -> 
    [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 -> 
    [$0 + N]; 
hex_octet(N) when N > 15 -> 
    hex_octet(N bsr 4) ++ hex_octet(N band 15); 
hex_octet(N) -> 
    [N - 10 + $a]. 

Обратите внимание, что из-за использования Юникода: characters_to_binary это будет работать только в R13 или более поздней версии.

8

По крайней мере, в R15 есть http_uri:encode/1, который выполняет эту работу. Я бы также не рекомендовал использовать edoc_lib: escape_uri как его перевод «=» в% 3d вместо% 3D, что вызвало у меня некоторые проблемы.

2

Если кто-то должен кодировать URI, который работает с UTF-8 в Эрл:

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: ƹÈ