diff options
Diffstat (limited to 'src/xmlrpc.erl')
-rw-r--r-- | src/xmlrpc.erl | 236 |
1 files changed, 120 insertions, 116 deletions
diff --git a/src/xmlrpc.erl b/src/xmlrpc.erl index 102b75a94..009a8001d 100644 --- a/src/xmlrpc.erl +++ b/src/xmlrpc.erl @@ -3,10 +3,10 @@ %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions -%% are met: +%% are met: %% %% 1. Redistributions of source code must retain the above copyright -%% notice, this list of conditions and the following disclaimer. +%% notice, this list of conditions and the following disclaimer. %% 2. Redistributions in binary form must reproduce the above %% copyright notice, this list of conditions and the following %% disclaimer in the documentation and/or other materials provided @@ -25,162 +25,166 @@ %% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -module(xmlrpc). + -author('jocke@gleipnir.com'). + -export([call/3, call/4, call/5, call/6]). --export([start_link/1, start_link/5, start_link/6, stop/1]). + +-export([start_link/1, start_link/5, start_link/6, + stop/1]). -include("log.hrl"). --record(header, { - %% int() - content_length, - %% close | undefined - connection - }). +-record(header, {content_length :: non_neg_integer(), + connection :: close}). %% Exported: call/{3,4,5,6} -call(Host, Port, URI, Payload) -> call(Host, Port, URI, Payload, false, 60000). +call(Host, Port, URI, Payload) -> + call(Host, Port, URI, Payload, false, 60000). call(Host, Port, URI, Payload, KeepAlive, Timeout) -> - case gen_tcp:connect(Host, Port, [{active, false}]) of - {ok, Socket} -> call(Socket, URI, Payload, KeepAlive, Timeout); - {error, Reason} when KeepAlive == false -> {error, Reason}; - {error, Reason} -> {error, undefined, Reason} + case gen_tcp:connect(Host, Port, [binary, {active, false}]) of + {ok, Socket} -> + call(Socket, URI, Payload, KeepAlive, Timeout); + {error, Reason} when KeepAlive == false -> + {error, Reason}; + {error, Reason} -> {error, undefined, Reason} end. -call(Socket, URI, Payload) -> call(Socket, URI, Payload, false, 60000). +call(Socket, URI, Payload) -> + call(Socket, URI, Payload, false, 60000). call(Socket, URI, Payload, KeepAlive, Timeout) -> ?DEBUG_LOG({decoded_call, Payload}), - case xmlrpc_encode:payload(Payload) of - {ok, EncodedPayload} -> - ?DEBUG_LOG({encoded_call, EncodedPayload}), - case send(Socket, URI, KeepAlive, EncodedPayload) of - ok -> - case parse_response(Socket, Timeout) of - {ok, Header} -> - handle_payload(Socket, KeepAlive, Timeout, Header); - {error, Reason} when KeepAlive == false -> - gen_tcp:close(Socket), - {error, Reason}; - {error, Reason} -> {error, Socket, Reason} - end; - {error, Reason} when KeepAlive == false -> - gen_tcp:close(Socket), - {error, Reason}; - {error, Reason} -> {error, Socket, Reason} - end; - {error, Reason} when KeepAlive == false -> - gen_tcp:close(Socket), - {error, Reason}; - {error, Reason} -> {error, Socket, Reason} + EncodedPayload = xmlrpc_encode:payload(Payload), + ?DEBUG_LOG({encoded_call, EncodedPayload}), + case send(Socket, URI, KeepAlive, EncodedPayload) of + ok -> + case parse_response(Socket, Timeout) of + {ok, Header} -> + handle_payload(Socket, KeepAlive, Timeout, Header); + {error, Reason} when KeepAlive == false -> + gen_tcp:close(Socket), {error, Reason}; + {error, Reason} -> {error, Socket, Reason} + end; + {error, Reason} when KeepAlive == false -> + gen_tcp:close(Socket), {error, Reason}; + {error, Reason} -> {error, Socket, Reason} end. send(Socket, URI, false, Payload) -> - send(Socket, URI, "Connection: close\r\n", Payload); -send(Socket, URI, true, Payload) -> send(Socket, URI, "", Payload); + send(Socket, URI, <<"Connection: close\r\n">>, Payload); +send(Socket, URI, true, Payload) -> + send(Socket, URI, <<"">>, Payload); send(Socket, URI, Header, Payload) -> - Request = - ["POST ", URI, " HTTP/1.1\r\n", - "Content-Length: ", integer_to_list(lists:flatlength(Payload)), - "\r\n", - "User-Agent: Erlang XML-RPC Client 1.13\r\n", - "Content-Type: text/xml\r\n", - Header, "\r\n", - Payload], + Request = [<<"POST ">>, URI, <<" HTTP/1.1\r\n">>, + <<"Content-Length: ">>, + jlib:integer_to_binary(byte_size(Payload)), + <<"\r\n">>, + <<"User-Agent: Erlang XML-RPC Client 1.13\r\n">>, + <<"Content-Type: text/xml\r\n">>, Header, <<"\r\n">>, + Payload], gen_tcp:send(Socket, Request). parse_response(Socket, Timeout) -> - inet:setopts(Socket, [{packet, line}]), + inet:setopts(Socket, [binary, {packet, line}]), case gen_tcp:recv(Socket, 0, Timeout) of - {ok, "HTTP/1.1 200 OK\r\n"} -> parse_header(Socket, Timeout); - {ok, StatusLine} -> {error, StatusLine}; - {error, Reason} -> {error, Reason} + {ok, <<"HTTP/1.1 200 OK\r\n">>} -> + parse_header(Socket, Timeout); + {ok, StatusLine} -> {error, StatusLine}; + {error, Reason} -> {error, Reason} end. -parse_header(Socket, Timeout) -> parse_header(Socket, Timeout, #header{}). +parse_header(Socket, Timeout) -> + parse_header(Socket, Timeout, #header{}). parse_header(Socket, Timeout, Header) -> case gen_tcp:recv(Socket, 0, Timeout) of - {ok, "\r\n"} when Header#header.content_length == undefined -> - {error, missing_content_length}; - {ok, "\r\n"} -> {ok, Header}; - {ok, HeaderField} -> - case string:tokens(HeaderField, " \r\n") of - ["Content-Length:", ContentLength] -> - case catch list_to_integer(ContentLength) of - badarg -> - {error, {invalid_content_length, ContentLength}}; - Value -> - parse_header(Socket, Timeout, - Header#header{content_length = - Value}) - end; - ["Connection:", "close"] -> - parse_header(Socket, Timeout, - Header#header{connection = close}); - _ -> - parse_header(Socket, Timeout, Header) - end; - {error, Reason} -> {error, Reason} + {ok, <<"\r\n">>} + when Header#header.content_length == undefined -> + {error, missing_content_length}; + {ok, <<"\r\n">>} -> {ok, Header}; + {ok, HeaderField} -> + case str:tokens(HeaderField, <<" \r\n">>) of + [<<"Content-Length:">>, ContentLength] -> + case catch jlib:binary_to_integer(ContentLength) of + Value when is_integer(Value), Value>=0 -> + parse_header(Socket, Timeout, + Header#header{content_length = Value}); + _ -> + {error, {invalid_content_length, ContentLength}} + end; + [<<"Connection:">>, <<"close">>] -> + parse_header(Socket, Timeout, + Header#header{connection = close}); + _ -> parse_header(Socket, Timeout, Header) + end; + {error, Reason} -> {error, Reason} end. handle_payload(Socket, KeepAlive, Timeout, Header) -> - case get_payload(Socket, Timeout, Header#header.content_length) of - {ok, Payload} -> - ?DEBUG_LOG({encoded_response, Payload}), - case xmlrpc_decode:payload(Payload) of - {ok, DecodedPayload} when KeepAlive == false -> - ?DEBUG_LOG({decoded_response, DecodedPayload}), - gen_tcp:close(Socket), - {ok, DecodedPayload}; - {ok, DecodedPayload} when KeepAlive == true, - Header#header.connection == close -> - ?DEBUG_LOG({decoded_response, DecodedPayload}), - gen_tcp:close(Socket), - {ok, Socket, DecodedPayload}; - {ok, DecodedPayload} -> - ?DEBUG_LOG({decoded_response, DecodedPayload}), - {ok, Socket, DecodedPayload}; - {error, Reason} when KeepAlive == false -> - gen_tcp:close(Socket), - {error, Reason}; - {error, Reason} when KeepAlive == true, - Header#header.connection == close -> - gen_tcp:close(Socket), - {error, Socket, Reason}; - {error, Reason} -> - {error, Socket, Reason} - end; - {error, Reason} when KeepAlive == false -> - gen_tcp:close(Socket), - {error, Reason}; - {error, Reason} when KeepAlive == true, - Header#header.connection == close -> - gen_tcp:close(Socket), - {error, Socket, Reason}; - {error, Reason} -> {error, Socket, Reason} + case get_payload(Socket, Timeout, + Header#header.content_length) + of + {ok, Payload} -> + ?DEBUG_LOG({encoded_response, Payload}), + case xmlrpc_decode:payload(Payload) of + {ok, DecodedPayload} when KeepAlive == false -> + ?DEBUG_LOG({decoded_response, DecodedPayload}), + gen_tcp:close(Socket), + {ok, DecodedPayload}; + {ok, DecodedPayload} + when KeepAlive == true, + Header#header.connection == close -> + ?DEBUG_LOG({decoded_response, DecodedPayload}), + gen_tcp:close(Socket), + {ok, Socket, DecodedPayload}; + {ok, DecodedPayload} -> + ?DEBUG_LOG({decoded_response, DecodedPayload}), + {ok, Socket, DecodedPayload}; + {error, Reason} when KeepAlive == false -> + gen_tcp:close(Socket), {error, Reason}; + {error, Reason} + when KeepAlive == true, + Header#header.connection == close -> + gen_tcp:close(Socket), {error, Socket, Reason}; + {error, Reason} -> {error, Socket, Reason} + end; + {error, Reason} when KeepAlive == false -> + gen_tcp:close(Socket), {error, Reason}; + {error, Reason} + when KeepAlive == true, + Header#header.connection == close -> + gen_tcp:close(Socket), {error, Socket, Reason}; + {error, Reason} -> {error, Socket, Reason} end. get_payload(Socket, Timeout, ContentLength) -> - inet:setopts(Socket, [{packet, raw}]), + inet:setopts(Socket, [binary, {packet, raw}]), gen_tcp:recv(Socket, ContentLength, Timeout). %% Exported: start_link/{1,5,6} -start_link(Handler) -> start_link(4567, 1000, 60000, Handler, undefined). +start_link(Handler) -> + start_link(4567, 1000, 60000, Handler, undefined). -start_link(Port, MaxSessions, Timeout, Handler, State) -> - start_link(all, Port, MaxSessions, Timeout, Handler, State). +start_link(Port, MaxSessions, Timeout, Handler, + State) -> + start_link(all, Port, MaxSessions, Timeout, Handler, + State). -start_link(IP, Port, MaxSessions, Timeout, Handler, State) -> - OptionList = [{active, false}, {reuseaddr, true}] ++ ip(IP), - SessionHandler = {xmlrpc_http, handler, [Timeout, Handler, State]}, - tcp_serv:start_link([Port, MaxSessions, OptionList, SessionHandler]). +start_link(IP, Port, MaxSessions, Timeout, Handler, + State) -> + OptionList = [{active, false}, {reuseaddr, true}] ++ + ip(IP), + SessionHandler = {xmlrpc_http, handler, + [Timeout, Handler, State]}, + tcp_serv:start_link([Port, MaxSessions, OptionList, + SessionHandler]). ip(all) -> []; -ip(IP) when tuple(IP) -> [{ip, IP}]. +ip(IP) when is_tuple(IP) -> [{ip, IP}]. %% Exported: stop/1 |