]> granicus.if.org Git - ejabberd/commitdiff
Make host header parser work correctly with ipv6 literal addresses
authorPaweł Chmielowski <pchmielowski@process-one.net>
Fri, 24 Feb 2017 09:25:16 +0000 (10:25 +0100)
committerPaweł Chmielowski <pchmielowski@process-one.net>
Fri, 24 Feb 2017 09:25:26 +0000 (10:25 +0100)
src/ejabberd_http.erl

index bd3291508d004f74b35b8154ebe7d3109b7c75d9..53787626f33aaafee1695142e1752c2fb496e754 100644 (file)
@@ -68,7 +68,8 @@
                end_of_request = false,
                options = [],
                default_host,
-               trail = <<>>
+               trail = <<>>,
+               addr_re
               }).
 
 -define(XHTML_DOCTYPE,
@@ -164,13 +165,15 @@ init({SockMod, Socket}, Opts) ->
     ?DEBUG("S: ~p~n", [RequestHandlers]),
 
     DefaultHost = gen_mod:get_opt(default_host, Opts, fun(A) -> A end, undefined),
+    {ok, RE} = re:compile(<<"^(?:\\[(.*?)\\]|(.*?))(?::(\\d+))?$">>),
 
     ?INFO_MSG("started: ~p", [{SockMod1, Socket1}]),
     State = #state{sockmod = SockMod1,
                    socket = Socket1,
                    default_host = DefaultHost,
                   options = Opts,
-                   request_handlers = RequestHandlers},
+                  request_handlers = RequestHandlers,
+                  addr_re = RE},
     try receive_headers(State) of
         V -> V
     catch
@@ -292,7 +295,7 @@ process_header(State, Data) ->
                 [State#state.socket, State#state.request_method,
                  element(2, State#state.request_path)]),
          {HostProvided, Port, TP} =
-             get_transfer_protocol(SockMod,
+             get_transfer_protocol(State#state.addr_re, SockMod,
                                    State#state.request_host),
          Host = get_host_really_served(State#state.default_host,
                                        HostProvided),
@@ -332,16 +335,25 @@ get_host_really_served(Default, Provided) ->
       false -> Default
     end.
 
-get_transfer_protocol(SockMod, HostPort) ->
-    [Host | PortList] = str:tokens(HostPort, <<":">>),
-    case {SockMod, PortList} of
-      {gen_tcp, []} -> {Host, 80, http};
-      {gen_tcp, [Port]} ->
-         {Host, binary_to_integer(Port), http};
-      {fast_tls, []} -> {Host, 443, https};
-      {fast_tls, [Port]} ->
-         {Host, binary_to_integer(Port), https}
-    end.
+get_transfer_protocol(RE, SockMod, HostPort) ->
+    {Proto, DefPort} = case SockMod of
+                          gen_tcp -> {http, 80};
+                          fast_tls -> {https, 443}
+                      end,
+    {Host, Port} = case re:run(HostPort, RE, [{capture,[1,2,3],binary}]) of
+                      nomatch ->
+                          {<<"0.0.0.0">>, DefPort};
+                      {match, [<<>>, H, <<>>]} ->
+                          {H, DefPort};
+                      {match, [H, <<>>, <<>>]} ->
+                          {H, DefPort};
+                      {match, [<<>>, H, PortStr]} ->
+                          {H, binary_to_integer(PortStr)};
+                      {match, [H, <<>>, PortStr]} ->
+                          {H, binary_to_integer(PortStr)}
+                  end,
+
+    {Host, Port, Proto}.
 
 %% XXX bard: search through request handlers looking for one that
 %% matches the requested URL path, and pass control to it.  If none is