diff options
| author | Filipe David Borba Manana <fdmanana@apache.org> | 2011-04-13 11:05:30 +0000 | 
|---|---|---|
| committer | Filipe David Borba Manana <fdmanana@apache.org> | 2011-04-13 11:05:30 +0000 | 
| commit | 01d9ef20f62bac0320ac7dc83192c29889720fa2 (patch) | |
| tree | f2a17a331c9e35d136802d8e2e4e41a3a87c8c9d | |
| parent | 33f7a1bb847736e78da91b681059520b0c41befd (diff) | |
Merged revision 1091709 from trunk
    Add support for replication over IPv6 (part 1)
    This change upgrades ibrowse to version 2.2.0. This version adds support
    for IPv6 (https://github.com/cmullaparthi/ibrowse/pull/34).
    This is part of COUCHDB-665.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/branches/1.1.x@1091741 13f79535-47bb-0310-9956-ffa450edef68
| -rw-r--r-- | src/ibrowse/Makefile.am | 2 | ||||
| -rw-r--r-- | src/ibrowse/ibrowse.app.in | 2 | ||||
| -rw-r--r-- | src/ibrowse/ibrowse.hrl | 11 | ||||
| -rw-r--r-- | src/ibrowse/ibrowse_http_client.erl | 37 | ||||
| -rw-r--r-- | src/ibrowse/ibrowse_lib.erl | 51 | 
5 files changed, 94 insertions, 9 deletions
| diff --git a/src/ibrowse/Makefile.am b/src/ibrowse/Makefile.am index bfd52ba2..869bd107 100644 --- a/src/ibrowse/Makefile.am +++ b/src/ibrowse/Makefile.am @@ -10,7 +10,7 @@  ## License for the specific language governing permissions and limitations under  ## the License. -ibrowseebindir = $(localerlanglibdir)/ibrowse-2.1.3/ebin +ibrowseebindir = $(localerlanglibdir)/ibrowse-2.2.0/ebin  ibrowse_file_collection = \  	ibrowse.app.in \ diff --git a/src/ibrowse/ibrowse.app.in b/src/ibrowse/ibrowse.app.in index 875620dd..af46d8a5 100644 --- a/src/ibrowse/ibrowse.app.in +++ b/src/ibrowse/ibrowse.app.in @@ -1,6 +1,6 @@  {application, ibrowse,          [{description, "HTTP client application"}, -         {vsn, "2.1.3"}, +         {vsn, "2.2.0"},           {modules, [ ibrowse,   		     ibrowse_http_client,   		     ibrowse_app,  diff --git a/src/ibrowse/ibrowse.hrl b/src/ibrowse/ibrowse.hrl index ebf3bb33..18dde827 100644 --- a/src/ibrowse/ibrowse.hrl +++ b/src/ibrowse/ibrowse.hrl @@ -1,7 +1,16 @@  -ifndef(IBROWSE_HRL).  -define(IBROWSE_HRL, "ibrowse.hrl"). --record(url, {abspath, host, port, username, password, path, protocol}). +-record(url, { +          abspath, +          host, +          port, +          username, +          password, +          path, +          protocol, +          host_type  % 'hostname', 'ipv4_address' or 'ipv6_address' +}).  -record(lb_pid, {host_port, pid}). diff --git a/src/ibrowse/ibrowse_http_client.erl b/src/ibrowse/ibrowse_http_client.erl index 7d606e61..eb2bf315 100644 --- a/src/ibrowse/ibrowse_http_client.erl +++ b/src/ibrowse/ibrowse_http_client.erl @@ -35,6 +35,7 @@          ]).  -include("ibrowse.hrl"). +-include_lib("kernel/include/inet.hrl").  -record(state, {host, port, connect_timeout,                  inactivity_timer_ref, @@ -489,13 +490,19 @@ do_connect(Host, Port, Options, #state{is_ssl      = true,                                         use_proxy   = false,                                         ssl_options = SSLOptions},             Timeout) -> -    ssl:connect(Host, Port, get_sock_options(Options, SSLOptions), Timeout); +    ssl:connect(Host, Port, get_sock_options(Host, Options, SSLOptions), Timeout);  do_connect(Host, Port, Options, _State, Timeout) -> -    gen_tcp:connect(Host, Port, get_sock_options(Options, []), Timeout). +    gen_tcp:connect(Host, Port, get_sock_options(Host, Options, []), Timeout). -get_sock_options(Options, SSLOptions) -> +get_sock_options(Host, Options, SSLOptions) ->      Caller_socket_options = get_value(socket_options, Options, []), -    Other_sock_options = filter_sock_options(SSLOptions ++ Caller_socket_options), +    Ipv6Options = case is_ipv6_host(Host) of +        true -> +            [inet6]; +        false -> +            [] +    end, +    Other_sock_options = filter_sock_options(SSLOptions ++ Caller_socket_options ++ Ipv6Options),      case lists:keysearch(nodelay, 1, Other_sock_options) of          false ->              [{nodelay, true}, binary, {active, false} | Other_sock_options]; @@ -503,6 +510,21 @@ get_sock_options(Options, SSLOptions) ->              [binary, {active, false} | Other_sock_options]      end. +is_ipv6_host(Host) -> +    case inet_parse:address(Host) of +        {ok, {_, _, _, _, _, _, _, _}} -> +            true; +        {ok, {_, _, _, _}} -> +            false; +        _  -> +            case inet:gethostbyname(Host) of +                {ok, #hostent{h_addrtype = inet6}} -> +                    true; +                _ -> +                    false +            end +    end. +  %% We don't want the caller to specify certain options  filter_sock_options(Opts) ->      lists:filter(fun({active, _}) -> @@ -1278,7 +1300,12 @@ handle_response(#request{from=From, stream_to=StreamTo, req_id=ReqId,                         reply_buffer  = RepBuf,                         recvd_headers = RespHeaders}=State) when SaveResponseToFile /= false ->      Body = RepBuf, -    ok = file:close(Fd), +    case Fd of +        undefined ->  +            ok; +        _ ->  +            ok = file:close(Fd) +    end,      ResponseBody = case TmpFilename of                         undefined ->                             Body; diff --git a/src/ibrowse/ibrowse_lib.erl b/src/ibrowse/ibrowse_lib.erl index 696d0f69..3cbe3ace 100644 --- a/src/ibrowse/ibrowse_lib.erl +++ b/src/ibrowse/ibrowse_lib.erl @@ -180,7 +180,19 @@ get_value(Tag, TVL) ->      V.  parse_url(Url) -> -    parse_url(Url, get_protocol, #url{abspath=Url}, []). +    case parse_url(Url, get_protocol, #url{abspath=Url}, []) of +        #url{host_type = undefined, host = Host} = UrlRec -> +            case inet_parse:address(Host) of +                {ok, {_, _, _, _, _, _, _, _}} -> +                    UrlRec#url{host_type = ipv6_address}; +                {ok, {_, _, _, _}} -> +                    UrlRec#url{host_type = ipv4_address}; +                _ -> +                    UrlRec#url{host_type = hostname} +            end; +        Else -> +            Else +    end.  parse_url([$:, $/, $/ | _], get_protocol, Url, []) ->      {invalid_uri_1, Url}; @@ -215,6 +227,21 @@ parse_url([$@ | T], get_username, Url, TmpAcc) ->                Url#url{username = lists:reverse(TmpAcc),                        password = ""},                []); +parse_url([$[ | T], get_username, Url, []) -> +    % IPv6 address literals are enclosed by square brackets: +    %     http://www.ietf.org/rfc/rfc2732.txt +    parse_url(T, get_ipv6_address, Url#url{host_type = ipv6_address}, []); +parse_url([$[ | T], get_username, _Url, TmpAcc) -> +    {error, {invalid_username_or_host, lists:reverse(TmpAcc) ++ "[" ++ T}}; +parse_url([$[ | _], get_password, _Url, []) -> +    {error, missing_password}; +parse_url([$[ | T], get_password, Url, TmpAcc) -> +    % IPv6 address literals are enclosed by square brackets: +    %     http://www.ietf.org/rfc/rfc2732.txt +    parse_url(T, get_ipv6_address, +              Url#url{host_type = ipv6_address, +                      password = lists:reverse(TmpAcc)}, +              []);  parse_url([$@ | T], get_password, Url, TmpAcc) ->      parse_url(T, get_host,                 Url#url{password = lists:reverse(TmpAcc)}, @@ -236,6 +263,28 @@ parse_url([H | T], get_password, Url, TmpAcc) when H == $/;              username = undefined,              password = undefined,             path = Path}; +parse_url([$] | T], get_ipv6_address, #url{protocol = Prot} = Url, TmpAcc) -> +    Addr = lists:reverse(TmpAcc), +    case inet_parse:address(Addr) of +        {ok, {_, _, _, _, _, _, _, _}} -> +            Url2 = Url#url{host = Addr, port = default_port(Prot)}, +            case T of +                [$: | T2] -> +                    parse_url(T2, get_port, Url2, []); +                [$/ | T2] -> +                    Url2#url{path = [$/ | T2]}; +                [$? | T2] -> +                    Url2#url{path = [$/, $? | T2]}; +                [] -> +                    Url2#url{path = "/"}; +                _ -> +                    {error, {invalid_host, "[" ++ Addr ++ "]" ++ T}} +            end; +        _ -> +            {error, {invalid_ipv6_address, Addr}} +    end; +parse_url([$[ | T], get_host, #url{} = Url, []) -> +    parse_url(T, get_ipv6_address, Url#url{host_type = ipv6_address}, []);  parse_url([$: | T], get_host, #url{} = Url, TmpAcc) ->      parse_url(T, get_port,                 Url#url{host = lists:reverse(TmpAcc)}, | 
