Skip to content

Commit

Permalink
perf: remove the usage of charlists in favor of binaries (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
neslinesli93 authored May 5, 2023
1 parent aa3a6d8 commit 3f405a7
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 38 deletions.
2 changes: 1 addition & 1 deletion src/soap_client_util.erl
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ parse_xml(Message, Model, Http_status, Http_headers,
#p_state{model = Model, version = Version,
soap_ns = Ns, state = start,
handler = Handler},
fun xml_parser_cb_wrapped/2, []) of
fun xml_parser_cb_wrapped/2, [{output_encoding, utf8}]) of
{ok, #p_state{is_fault = true,
soap_headers = Decoded_headers,
soap_body = Decoded_fault,
Expand Down
53 changes: 29 additions & 24 deletions src/soap_fault.erl
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@
-type fault_code() :: fault_code_atom() | fault_code_object().
-export_type([fault_code/0]).

-type fault_string() :: string() | fault_reason() | [fault_reason()].
-type fault_string() :: binary() | fault_reason() | [fault_reason()].

-type fault_actor() :: string() | undefined.
-type fault_actor() :: binary() | undefined.

-opaque fault_detail() :: iodata().
-export_type([fault_detail/0]).
Expand All @@ -75,7 +75,7 @@
-record(pf_state, {
version :: atom(),
state :: atom(),
characters = "" :: string() | undefined,
characters = <<>> :: binary() | undefined,
code :: fault_code_object() | undefined,
fault_string :: fault_string() | undefined,
actor :: fault_actor() | undefined,
Expand Down Expand Up @@ -210,7 +210,7 @@ make_reasons(Fault_string)
make_reasons(Fault_strings)
when is_list(Fault_strings) andalso
((length(Fault_strings) == 0) orelse is_tuple(hd(Fault_strings))) ->
[make_reason(Text) || Text <- Fault_strings];
[make_reason(Text) || Text <- Fault_strings];
make_reasons(Fault_string) ->
make_reason(#fault_reason{text = Fault_string}).

Expand Down Expand Up @@ -300,7 +300,7 @@ fault_detail(Details, '1.2') ->
xml_string(String) ->
soap_req:xml_string(String).

make_code(String, N_spaces) ->
make_code(String, N_spaces) when is_list(String) ->
case string:tokens(String, ":") of
[Prefix, Local] ->
case lists:keyfind(Prefix, 1, N_spaces) of
Expand All @@ -314,7 +314,9 @@ make_code(String, N_spaces) ->
_ ->
#faultcode{uri = "",
code = String}
end.
end;
make_code(Bin, N_spaces) when is_binary(Bin) ->
make_code(unicode:characters_to_list(Bin), N_spaces).

%%% ----------------------------------------------------------------------------
%%% Parsing faults
Expand All @@ -337,13 +339,13 @@ parse_fault_1_1({startElement, _, "faultcode", _, _},
parse_fault_1_1({characters, Characters},
_Namespaces,
#pf_state{characters = String} = S) ->
S#pf_state{characters = String ++ Characters};
S#pf_state{characters = <<String/binary, Characters/binary>>};
parse_fault_1_1({endElement, _, "faultcode", _},
Namespaces,
#pf_state{state = code,
characters = String} = S) ->
S#pf_state{code = make_code(String, Namespaces),
characters = "",
characters = <<>>,
state = code_done};
parse_fault_1_1({startElement, _, "faultstring", _, _},
_Namespaces,
Expand All @@ -354,7 +356,7 @@ parse_fault_1_1({endElement, _, "faultstring", _},
#pf_state{state = faultstring,
characters = String} = S) ->
S#pf_state{fault_string = String,
characters = "",
characters = <<>>,
state = faultstring_done};
parse_fault_1_1({startElement, _, "faultactor", _, _},
_Namespaces,
Expand All @@ -367,7 +369,7 @@ parse_fault_1_1({endElement, _, "faultactor", _},
#pf_state{state = faultactor,
characters = String} = S) ->
S#pf_state{actor = String,
characters = "",
characters = <<>>,
state = actor_done};
parse_fault_1_1({startElement, _, "detail", _, _},
_Namespaces,
Expand All @@ -389,8 +391,8 @@ parse_fault_1_1({endElement, Namespace, Tag, _},
characters = String} = S) ->
S#pf_state{details = [#faultdetail{tag = Tag,
uri = Namespace,
text = String} | Details],
characters = "",
text = unicode:characters_to_list(String)} | Details],
characters = <<>>,
state = details};
parse_fault_1_1({endElement, _, "detail", _},
_Namespaces,
Expand Down Expand Up @@ -431,13 +433,13 @@ parse_fault_1_2({startElement, ?SOAP12_NS, "Value", _, _},
parse_fault_1_2({characters, Characters},
_Namespaces,
#pf_state{characters = String} = S) ->
S#pf_state{characters = String ++ Characters};
S#pf_state{characters = <<String/binary, Characters/binary>>};
parse_fault_1_2({endElement, ?SOAP12_NS, "Value", _},
Namespaces,
#pf_state{state = code_value,
characters = String} = S) ->
S#pf_state{code = make_code(String, Namespaces),
characters = "",
characters = <<>>,
state = value_done};
parse_fault_1_2({startElement, ?SOAP12_NS, "Subcode", _, _},
_Namespaces,
Expand All @@ -449,7 +451,7 @@ parse_fault_1_2({endElement, ?SOAP12_NS, "Value", _},
code = Code,
characters = String} = S) ->
S#pf_state{code = Code#faultcode{subcode = make_code(String, Namespaces)},
characters = "",
characters = <<>>,
state = value_done};
parse_fault_1_2({endElement, _, "Subcode", _},
_Namespaces,
Expand Down Expand Up @@ -488,9 +490,9 @@ parse_fault_1_2({endElement, ?SOAP12_NS, "Text", _},
language = Language,
reasons = Reasons,
characters = String} = S) ->
S#pf_state{reasons = [#faultreason{language = Language,
text = String} | Reasons],
characters = "",
S#pf_state{reasons = [#faultreason{language = unicode:characters_to_list(Language),
text = unicode:characters_to_list(String)} | Reasons],
characters = <<>>,
state = reasons};
parse_fault_1_2({startElement, ?SOAP12_NS, "Role", _, _},
_Namespaces,
Expand All @@ -503,7 +505,7 @@ parse_fault_1_2({endElement, ?SOAP12_NS, "Role", _},
#pf_state{state = role,
characters = String} = S) ->
S#pf_state{actor = String,
characters = "",
characters = <<>>,
state = role_done};
parse_fault_1_2({startElement, ?SOAP12_NS, "Detail", _, _},
_Namespaces,
Expand All @@ -525,8 +527,8 @@ parse_fault_1_2({endElement, Namespace, Tag, _},
characters = String} = S) ->
S#pf_state{details = [#faultdetail{tag = Tag,
uri = Namespace,
text = String} | Details],
characters = "",
text = unicode:characters_to_list(String)} | Details],
characters = <<>>,
state = details};
parse_fault_1_2({endElement, ?SOAP12_NS, "Detail", _},
_Namespaces,
Expand All @@ -550,13 +552,16 @@ make_record(#pf_state{version = '1.1', code = Code,
actor = Actor, details = Details,
fault_string = String}) ->
#soap_fault_1_1{faultcode = Code,
faultstring = String,
faultactor = Actor,
faultstring = characters_to_list(String),
faultactor = characters_to_list(Actor),
detail = Details};
make_record(#pf_state{version = '1.2', code = Code,
actor = Actor, details = Details,
reasons = Reasons}) ->
#soap_fault_1_2{code = Code,
reason = Reasons,
role = Actor,
role = characters_to_list(Actor),
detail = Details}.

characters_to_list(undefined) -> undefined;
characters_to_list(Bin) -> unicode:characters_to_list(Bin).
2 changes: 1 addition & 1 deletion src/soap_server_handler.erl
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ handle(Parsed_body, Soap_req, Handler_s) ->
Handler = soap_req:handler(Soap_req),
case lists:keyfind(Record_type, #op.in_type, Operations) of
false ->
{fault, soap_fault:fault(client, "Unknown operation", Soap_req),
{fault, soap_fault:fault(client, <<"Unknown operation">>, Soap_req),
Soap_req, Handler_s};
#op{operation = Operation} ->
Handler:Operation(Parsed_body, Soap_req, Handler_s)
Expand Down
27 changes: 15 additions & 12 deletions test/soap_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ client_11_ok(_Config) ->
%% Normally one should include the record definition and use
%% record syntax.
%% TODO: the P0 prefixes should not be necessary.
{ok, 200, _, _, {'P0:sendMessageResponse', "OK"}, [], _} =
{ok, 200, _, _, {'P0:sendMessageResponse', <<"OK">>}, [], _} =
sendService_client:'SendMessage'({'P0:sendMessage', "+31234567890",
"Hello there", "Text"}, [], []).

Expand All @@ -434,7 +434,7 @@ client_11_fault(_Config) ->
client_12_ok() ->
[{userdata,[{doc,"use the generated client, receive OK answer"}]}].
client_12_ok(_Config) ->
{ok, 200, Http_headers, _, {'P0:sendMessageResponse', "OK"}, [], Raw} =
{ok, 200, Http_headers, _, {'P0:sendMessageResponse', <<"OK">>}, [], Raw} =
sendService_client:'SendMessage'({'P0:sendMessage', "+31234567890",
"Hello there", "Text"}, [], []),
"application/soap+xml" = proplists:get_value("Content-Type", Http_headers),
Expand Down Expand Up @@ -479,17 +479,19 @@ test_client(_Config) ->


client_no_error(_Config) ->
{ok,200, Http_headers, [],#response_body{response = "ok"}, [], _} =
{ok,200, Http_headers, [],#response_body{response = <<"ok">>}, [], _} =
test_service_client:do_test(#request_body{expected_response="ok"}, [], []),
"text/xml" = proplists:get_value("Content-Type", Http_headers).

client_unicode(_Config) ->
{ok,200, _, [],#response_body{response = "بِسْمِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ"}, [], _} =
Expected = unicode:characters_to_binary("بِسْمِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ"),
{ok,200, _, [],#response_body{response = Expected}, [], _} =
test_service_client:do_test(#request_body{expected_response=
"بِسْمِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ"}, [], []).

client_unicode_binary(_Config) ->
{ok,200, _, [],#response_body{response = "بِسْمِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ"}, [], _} =
Expected = unicode:characters_to_binary("بِسْمِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ"),
{ok,200, _, [],#response_body{response = Expected}, [], _} =
test_service_client:do_test(#request_body{
expected_response=
unicode:characters_to_binary("بِسْمِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ")},
Expand All @@ -500,7 +502,8 @@ inets_client_no_error(_Config) ->
test_inets_client:do_test(#request_body{expected_response="sleep:0"}, [], []).

inets_client_unicode(_Config) ->
{ok,200, _, [],#response_body{response = "بِسْمِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ"}, [], _} =
Expected = unicode:characters_to_binary("بِسْمِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ"),
{ok,200, _, [],#response_body{response = Expected}, [], _} =
test_inets_client:do_test(#request_body{expected_response=
"بِسْمِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ"}, [], []).

Expand Down Expand Up @@ -578,15 +581,15 @@ client_fault_encoding_header(_Config) ->
test_service_client:do_test(#request_body{expected_response="fault_encoding_header"}, [], []).

client_encoded_header(_Config) ->
{ok,200, _, [#header{header_field = "hello"}], #response_body{response = "ok"}, [], _} =
{ok,200, _, [#header{header_field = <<"hello">>}], #response_body{response = <<"ok">>}, [], _} =
test_service_client:do_test(#request_body{expected_response="encoded_header"}, [], []).

client_two_headers(_Config) ->
{ok,200, _, [_Hash,#header{header_field = "hello"}], #response_body{response = "ok"}, [], _} =
{ok,200, _, [_Hash,#header{header_field = <<"hello">>}], #response_body{response = <<"ok">>}, [], _} =
test_service_client:do_test(#request_body{expected_response="two_headers"}, [], []).

client_one_header_one_skipped(_Config) ->
{ok,200, _, [#header{header_field = "hello"}], #response_body{response = "ok"}, [], _} =
{ok,200, _, [#header{header_field = <<"hello">>}], #response_body{response = <<"ok">>}, [], _} =
test_service_client:do_test(#request_body{expected_response="one_header_one_skipped"}, [], []).

ibrowse_client_timeout(_Config) ->
Expand All @@ -595,15 +598,15 @@ ibrowse_client_timeout(_Config) ->
[{http_options, [{timeout, 1000}]}]).

raw(_Config) ->
{ok,200, _, [], #response_body{response = "raw"}, [], _} =
{ok,200, _, [], #response_body{response = <<"raw">>}, [], _} =
test_service_client:do_test(#request_body{expected_response="raw"}, [], []).

raw_client(_Config) ->
Message = [<<"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/so">>,
<<"ap/envelope/\"><s:Body><erlsom:request_body xmlns:erl">>,
<<"som=\"test\"><expected_response>raw</expected_response>">>,
"</erlsom:request_body></s:Body></s:Envelope>"],
{ok,200, _, [], #response_body{response = "raw"}, [], _} =
{ok,200, _, [], #response_body{response = <<"raw">>}, [], _} =
test_service_client:do_test(Message, [], []).

raw_client_error(_Config) ->
Expand All @@ -615,7 +618,7 @@ soap_req_no_headers(_Config) ->
test_service_client:do_test(#request_body{expected_response="ok"}, [], []).

soap_req_w_headers(_Config) ->
{ok,200, _, [],{response_body,"authenticated!"}, [], _} =
{ok,200, _, [],{response_body,<<"authenticated!">>}, [], _} =
test_service_client:do_test(#request_body{expected_response="ok"},
[], [{http_headers, [{"authorization", "user:pwd"}]}]).

Expand Down

0 comments on commit 3f405a7

Please sign in to comment.