Skip to content

Commit

Permalink
Add support for replication over IPv6 (part 1)
Browse files Browse the repository at this point in the history
This change upgrades ibrowse to version 2.2.0. This version adds support
for IPv6 (cmullaparthi/ibrowse#34).
This is part of COUCHDB-665.



git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@1091709 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
fdmanana committed Apr 13, 2011
1 parent baa0e30 commit 1ca42d2
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/ibrowse/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
2 changes: 1 addition & 1 deletion src/ibrowse/ibrowse.app.in
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
11 changes: 10 additions & 1 deletion src/ibrowse/ibrowse.hrl
Original file line number Diff line number Diff line change
@@ -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}).

Expand Down
37 changes: 32 additions & 5 deletions src/ibrowse/ibrowse_http_client.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
]).

-include("ibrowse.hrl").
-include_lib("kernel/include/inet.hrl").

-record(state, {host, port, connect_timeout,
inactivity_timer_ref,
Expand Down Expand Up @@ -489,20 +490,41 @@ 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];
{value, _} ->
[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, _}) ->
Expand Down Expand Up @@ -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;
Expand Down
51 changes: 50 additions & 1 deletion src/ibrowse/ibrowse_lib.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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)},
Expand All @@ -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)},
Expand Down

0 comments on commit 1ca42d2

Please sign in to comment.