aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src/http_lib
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2011-09-15 09:43:48 +0200
committerMicael Karlberg <[email protected]>2011-09-15 09:43:48 +0200
commit98fd9df4c4a04554fd2f707ca9ea2d674fad984d (patch)
tree8861e1e85f352d828cf31f0690feaae63c0088bd /lib/inets/src/http_lib
parent50261525973798faf7f62ea02356447b16e5fc56 (diff)
downloadotp-98fd9df4c4a04554fd2f707ca9ea2d674fad984d.tar.gz
otp-98fd9df4c4a04554fd2f707ca9ea2d674fad984d.tar.bz2
otp-98fd9df4c4a04554fd2f707ca9ea2d674fad984d.zip
Updated http-server to make sure URLs in error-messages
are URL-encoded. Added support in http-client to use URL-encoding. Also added the missing include directory for the inets application. OTP-8940 [httpd] Prevent XSS in error pages. Prevent user controlled input from being interpreted as HTML in error pages by encoding the reserved HTML characters. Michael Santos OTP-9124
Diffstat (limited to 'lib/inets/src/http_lib')
-rw-r--r--lib/inets/src/http_lib/Makefile5
-rw-r--r--lib/inets/src/http_lib/http_transport.erl26
-rw-r--r--lib/inets/src/http_lib/http_uri.erl141
-rw-r--r--lib/inets/src/http_lib/http_util.erl20
4 files changed, 185 insertions, 7 deletions
diff --git a/lib/inets/src/http_lib/Makefile b/lib/inets/src/http_lib/Makefile
index 7f4c92861c..a715e3c9af 100644
--- a/lib/inets/src/http_lib/Makefile
+++ b/lib/inets/src/http_lib/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2010. All Rights Reserved.
+# Copyright Ericsson AB 2005-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -45,7 +45,8 @@ MODULES = \
http_transport\
http_util \
http_request \
- http_response
+ http_response \
+ http_uri
HRL_FILES = http_internal.hrl
diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl
index 7c2ac626e6..587d215051 100644
--- a/lib/inets/src/http_lib/http_transport.erl
+++ b/lib/inets/src/http_lib/http_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -150,17 +150,22 @@ listen_ip_comm(Addr, Port) ->
case IpFamily of
inet6fb4 ->
Opts2 = [inet6 | Opts],
+ ?hlrt("try ipv6 listen", [{port, NewPort}, {opts, Opts2}]),
case (catch gen_tcp:listen(NewPort, Opts2)) of
{error, Reason} when ((Reason =:= nxdomain) orelse
(Reason =:= eafnosupport)) ->
Opts3 = [inet | Opts],
+ ?hlrt("ipv6 listen failed - try ipv4 instead",
+ [{reason, Reason}, {port, NewPort}, {opts, Opts3}]),
gen_tcp:listen(NewPort, Opts3);
%% This is when a given hostname has resolved to a
%% IPv4-address. The inet6-option together with a
%% {ip, IPv4} option results in badarg
- {'EXIT', _} ->
+ {'EXIT', Reason} ->
Opts3 = [inet | Opts],
+ ?hlrt("ipv6 listen exit - try ipv4 instead",
+ [{reason, Reason}, {port, NewPort}, {opts, Opts3}]),
gen_tcp:listen(NewPort, Opts3);
Other ->
@@ -168,6 +173,7 @@ listen_ip_comm(Addr, Port) ->
end;
_ ->
Opts2 = [IpFamily | Opts],
+ ?hlrt("listen", [{port, NewPort}, {opts, Opts2}]),
gen_tcp:listen(NewPort, Opts2)
end.
@@ -364,7 +370,21 @@ peername(ip_comm, Socket) ->
http_util:integer_to_hexlist(G) ++":"++
http_util:integer_to_hexlist(H),
{Port, PeerName};
- {error, _} ->
+ {error, Reason} ->
+ Report = io_lib:format("~p Failed getting PeerName for socket ~p: "
+ "~n Reason: ~p"
+ "~n Socket stat: ~p"
+ "~n IfList: ~p"
+ "~n Fd: ~p"
+ "~n",
+ [self(),
+ Socket,
+ Reason,
+ (catch inet:getstat(Socket)),
+ (catch inet:getiflist(Socket)),
+ (catch inet:getfd(Socket))
+ ]),
+ (catch error_logger:error_report(Report)),
{-1, "unknown"}
end;
diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl
new file mode 100644
index 0000000000..3804af60f4
--- /dev/null
+++ b/lib/inets/src/http_lib/http_uri.erl
@@ -0,0 +1,141 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(http_uri).
+
+-export([parse/1]).
+-export([parse/1, encode/1, decode/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+parse(AbsURI) ->
+ case parse_scheme(AbsURI) of
+ {error, Reason} ->
+ {error, Reason};
+ {Scheme, Rest} ->
+ case (catch parse_uri_rest(Scheme, Rest)) of
+ {UserInfo, Host, Port, Path, Query} ->
+ {Scheme, UserInfo, Host, Port, Path, Query};
+ _ ->
+ {error, {malformed_url, AbsURI}}
+ end
+ end.
+
+encode(URI) ->
+ Reserved = sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?,
+ $#, $[, $], $<, $>, $\", ${, $}, $|,
+ $\\, $', $^, $%, $ ]),
+ lists:append(lists:map(fun(Char) -> uri_encode(Char, Reserved) end, URI)).
+
+decode([$%,Hex1,Hex2|Rest]) ->
+ [hex2dec(Hex1)*16+hex2dec(Hex2)|decode(Rest)];
+decode([First|Rest]) ->
+ [First|decode(Rest)];
+decode([]) ->
+ [].
+
+%%%========================================================================
+%%% Internal functions
+%%%========================================================================
+parse_scheme(AbsURI) ->
+ case split_uri(AbsURI, ":", {error, no_scheme}, 1, 1) of
+ {error, no_scheme} ->
+ {error, no_scheme};
+ {StrScheme, Rest} ->
+ case list_to_atom(http_util:to_lower(StrScheme)) of
+ Scheme when Scheme == http; Scheme == https ->
+ {Scheme, Rest};
+ Scheme ->
+ {error, {not_supported_scheme, Scheme}}
+ end
+ end.
+
+parse_uri_rest(Scheme, "//" ++ URIPart) ->
+ {Authority, PathQuery} =
+ case split_uri(URIPart, "/", URIPart, 1, 0) of
+ Split = {_, _} ->
+ Split;
+ URIPart ->
+ case split_uri(URIPart, "\\?", URIPart, 1, 0) of
+ Split = {_, _} ->
+ Split;
+ URIPart ->
+ {URIPart,""}
+ end
+ end,
+
+ {UserInfo, HostPort} = split_uri(Authority, "@", {"", Authority}, 1, 1),
+ {Host, Port} = parse_host_port(Scheme, HostPort),
+ {Path, Query} = parse_path_query(PathQuery),
+ {UserInfo, Host, Port, Path, Query}.
+
+
+parse_path_query(PathQuery) ->
+ {Path, Query} = split_uri(PathQuery, "\\?", {PathQuery, ""}, 1, 0),
+ {path(Path), Query}.
+
+
+parse_host_port(Scheme,"[" ++ HostPort) -> %ipv6
+ DefaultPort = default_port(Scheme),
+ {Host, ColonPort} = split_uri(HostPort, "\\]", {HostPort, ""}, 1, 1),
+ {_, Port} = split_uri(ColonPort, ":", {"", DefaultPort}, 0, 1),
+ {Host, int_port(Port)};
+
+parse_host_port(Scheme, HostPort) ->
+ DefaultPort = default_port(Scheme),
+ {Host, Port} = split_uri(HostPort, ":", {HostPort, DefaultPort}, 1, 1),
+ {Host, int_port(Port)}.
+
+split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) ->
+ case inets_regexp:first_match(UriPart, SplitChar) of
+ {match, Match, _} ->
+ {string:substr(UriPart, 1, Match - SkipLeft),
+ string:substr(UriPart, Match + SkipRight, length(UriPart))};
+ nomatch ->
+ NoMatchResult
+ end.
+
+default_port(http) ->
+ 80;
+default_port(https) ->
+ 443.
+
+int_port(Port) when is_integer(Port) ->
+ Port;
+int_port(Port) when is_list(Port) ->
+ list_to_integer(Port).
+
+path("") ->
+ "/";
+path(Path) ->
+ Path.
+
+uri_encode(Char, Reserved) ->
+ case sets:is_element(Char, Reserved) of
+ true ->
+ [ $% | http_util:integer_to_hexlist(Char)];
+ false ->
+ [Char]
+ end.
+
+hex2dec(X) when (X>=$0) andalso (X=<$9) -> X-$0;
+hex2dec(X) when (X>=$A) andalso (X=<$F) -> X-$A+10;
+hex2dec(X) when (X>=$a) andalso (X=<$f) -> X-$a+10.
diff --git a/lib/inets/src/http_lib/http_util.erl b/lib/inets/src/http_lib/http_util.erl
index 4f1147176c..be0602ff6e 100644
--- a/lib/inets/src/http_lib/http_util.erl
+++ b/lib/inets/src/http_lib/http_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,7 +24,8 @@
convert_netscapecookie_date/1,
hexlist_to_integer/1, integer_to_hexlist/1,
convert_month/1,
- is_hostname/1,
+ is_hostname/1,
+ html_encode/1,
timestamp/0, timeout/2
]).
@@ -185,7 +186,14 @@ timeout(Timeout, Started) ->
_ ->
0
end.
+
+html_encode(Chars) ->
+ Reserved = sets:from_list([$&, $<, $>, $\", $', $/]),
+ lists:append(lists:map(fun(Char) ->
+ char_to_html_entity(Char, Reserved)
+ end, Chars)).
+
%%%========================================================================
%%% Internal functions
@@ -235,3 +243,11 @@ convert_to_ascii([Num | Reversed], Number)
convert_to_ascii([Num | Reversed], Number)
when (Num > 9) andalso (Num < 16) ->
convert_to_ascii(Reversed, [Num + 55 | Number]).
+
+char_to_html_entity(Char, Reserved) ->
+ case sets:is_element(Char, Reserved) of
+ true ->
+ "&#" ++ integer_to_list(Char) ++ ";";
+ false ->
+ [Char]
+ end.