Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add support for replication over IPv6 (part 1)

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...
commit 1ca42d229fe5c478311c348ee115cd31b46a2841 1 parent baa0e30
Filipe Manana fdmanana authored
2  src/ibrowse/Makefile.am
@@ -10,7 +10,7 @@
10 10 ## License for the specific language governing permissions and limitations under
11 11 ## the License.
12 12
13   -ibrowseebindir = $(localerlanglibdir)/ibrowse-2.1.3/ebin
  13 +ibrowseebindir = $(localerlanglibdir)/ibrowse-2.2.0/ebin
14 14
15 15 ibrowse_file_collection = \
16 16 ibrowse.app.in \
2  src/ibrowse/ibrowse.app.in
... ... @@ -1,6 +1,6 @@
1 1 {application, ibrowse,
2 2 [{description, "HTTP client application"},
3   - {vsn, "2.1.3"},
  3 + {vsn, "2.2.0"},
4 4 {modules, [ ibrowse,
5 5 ibrowse_http_client,
6 6 ibrowse_app,
11 src/ibrowse/ibrowse.hrl
... ... @@ -1,7 +1,16 @@
1 1 -ifndef(IBROWSE_HRL).
2 2 -define(IBROWSE_HRL, "ibrowse.hrl").
3 3
4   --record(url, {abspath, host, port, username, password, path, protocol}).
  4 +-record(url, {
  5 + abspath,
  6 + host,
  7 + port,
  8 + username,
  9 + password,
  10 + path,
  11 + protocol,
  12 + host_type % 'hostname', 'ipv4_address' or 'ipv6_address'
  13 +}).
5 14
6 15 -record(lb_pid, {host_port, pid}).
7 16
37 src/ibrowse/ibrowse_http_client.erl
@@ -35,6 +35,7 @@
35 35 ]).
36 36
37 37 -include("ibrowse.hrl").
  38 +-include_lib("kernel/include/inet.hrl").
38 39
39 40 -record(state, {host, port, connect_timeout,
40 41 inactivity_timer_ref,
@@ -489,13 +490,19 @@ do_connect(Host, Port, Options, #state{is_ssl = true,
489 490 use_proxy = false,
490 491 ssl_options = SSLOptions},
491 492 Timeout) ->
492   - ssl:connect(Host, Port, get_sock_options(Options, SSLOptions), Timeout);
  493 + ssl:connect(Host, Port, get_sock_options(Host, Options, SSLOptions), Timeout);
493 494 do_connect(Host, Port, Options, _State, Timeout) ->
494   - gen_tcp:connect(Host, Port, get_sock_options(Options, []), Timeout).
  495 + gen_tcp:connect(Host, Port, get_sock_options(Host, Options, []), Timeout).
495 496
496   -get_sock_options(Options, SSLOptions) ->
  497 +get_sock_options(Host, Options, SSLOptions) ->
497 498 Caller_socket_options = get_value(socket_options, Options, []),
498   - Other_sock_options = filter_sock_options(SSLOptions ++ Caller_socket_options),
  499 + Ipv6Options = case is_ipv6_host(Host) of
  500 + true ->
  501 + [inet6];
  502 + false ->
  503 + []
  504 + end,
  505 + Other_sock_options = filter_sock_options(SSLOptions ++ Caller_socket_options ++ Ipv6Options),
499 506 case lists:keysearch(nodelay, 1, Other_sock_options) of
500 507 false ->
501 508 [{nodelay, true}, binary, {active, false} | Other_sock_options];
@@ -503,6 +510,21 @@ get_sock_options(Options, SSLOptions) ->
503 510 [binary, {active, false} | Other_sock_options]
504 511 end.
505 512
  513 +is_ipv6_host(Host) ->
  514 + case inet_parse:address(Host) of
  515 + {ok, {_, _, _, _, _, _, _, _}} ->
  516 + true;
  517 + {ok, {_, _, _, _}} ->
  518 + false;
  519 + _ ->
  520 + case inet:gethostbyname(Host) of
  521 + {ok, #hostent{h_addrtype = inet6}} ->
  522 + true;
  523 + _ ->
  524 + false
  525 + end
  526 + end.
  527 +
506 528 %% We don't want the caller to specify certain options
507 529 filter_sock_options(Opts) ->
508 530 lists:filter(fun({active, _}) ->
@@ -1278,7 +1300,12 @@ handle_response(#request{from=From, stream_to=StreamTo, req_id=ReqId,
1278 1300 reply_buffer = RepBuf,
1279 1301 recvd_headers = RespHeaders}=State) when SaveResponseToFile /= false ->
1280 1302 Body = RepBuf,
1281   - ok = file:close(Fd),
  1303 + case Fd of
  1304 + undefined ->
  1305 + ok;
  1306 + _ ->
  1307 + ok = file:close(Fd)
  1308 + end,
1282 1309 ResponseBody = case TmpFilename of
1283 1310 undefined ->
1284 1311 Body;
51 src/ibrowse/ibrowse_lib.erl
@@ -180,7 +180,19 @@ get_value(Tag, TVL) ->
180 180 V.
181 181
182 182 parse_url(Url) ->
183   - parse_url(Url, get_protocol, #url{abspath=Url}, []).
  183 + case parse_url(Url, get_protocol, #url{abspath=Url}, []) of
  184 + #url{host_type = undefined, host = Host} = UrlRec ->
  185 + case inet_parse:address(Host) of
  186 + {ok, {_, _, _, _, _, _, _, _}} ->
  187 + UrlRec#url{host_type = ipv6_address};
  188 + {ok, {_, _, _, _}} ->
  189 + UrlRec#url{host_type = ipv4_address};
  190 + _ ->
  191 + UrlRec#url{host_type = hostname}
  192 + end;
  193 + Else ->
  194 + Else
  195 + end.
184 196
185 197 parse_url([$:, $/, $/ | _], get_protocol, Url, []) ->
186 198 {invalid_uri_1, Url};
@@ -215,6 +227,21 @@ parse_url([$@ | T], get_username, Url, TmpAcc) ->
215 227 Url#url{username = lists:reverse(TmpAcc),
216 228 password = ""},
217 229 []);
  230 +parse_url([$[ | T], get_username, Url, []) ->
  231 + % IPv6 address literals are enclosed by square brackets:
  232 + % http://www.ietf.org/rfc/rfc2732.txt
  233 + parse_url(T, get_ipv6_address, Url#url{host_type = ipv6_address}, []);
  234 +parse_url([$[ | T], get_username, _Url, TmpAcc) ->
  235 + {error, {invalid_username_or_host, lists:reverse(TmpAcc) ++ "[" ++ T}};
  236 +parse_url([$[ | _], get_password, _Url, []) ->
  237 + {error, missing_password};
  238 +parse_url([$[ | T], get_password, Url, TmpAcc) ->
  239 + % IPv6 address literals are enclosed by square brackets:
  240 + % http://www.ietf.org/rfc/rfc2732.txt
  241 + parse_url(T, get_ipv6_address,
  242 + Url#url{host_type = ipv6_address,
  243 + password = lists:reverse(TmpAcc)},
  244 + []);
218 245 parse_url([$@ | T], get_password, Url, TmpAcc) ->
219 246 parse_url(T, get_host,
220 247 Url#url{password = lists:reverse(TmpAcc)},
@@ -236,6 +263,28 @@ parse_url([H | T], get_password, Url, TmpAcc) when H == $/;
236 263 username = undefined,
237 264 password = undefined,
238 265 path = Path};
  266 +parse_url([$] | T], get_ipv6_address, #url{protocol = Prot} = Url, TmpAcc) ->
  267 + Addr = lists:reverse(TmpAcc),
  268 + case inet_parse:address(Addr) of
  269 + {ok, {_, _, _, _, _, _, _, _}} ->
  270 + Url2 = Url#url{host = Addr, port = default_port(Prot)},
  271 + case T of
  272 + [$: | T2] ->
  273 + parse_url(T2, get_port, Url2, []);
  274 + [$/ | T2] ->
  275 + Url2#url{path = [$/ | T2]};
  276 + [$? | T2] ->
  277 + Url2#url{path = [$/, $? | T2]};
  278 + [] ->
  279 + Url2#url{path = "/"};
  280 + _ ->
  281 + {error, {invalid_host, "[" ++ Addr ++ "]" ++ T}}
  282 + end;
  283 + _ ->
  284 + {error, {invalid_ipv6_address, Addr}}
  285 + end;
  286 +parse_url([$[ | T], get_host, #url{} = Url, []) ->
  287 + parse_url(T, get_ipv6_address, Url#url{host_type = ipv6_address}, []);
239 288 parse_url([$: | T], get_host, #url{} = Url, TmpAcc) ->
240 289 parse_url(T, get_port,
241 290 Url#url{host = lists:reverse(TmpAcc)},

0 comments on commit 1ca42d2

Please sign in to comment.
Something went wrong with that request. Please try again.