diff options
-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)}, |