Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Update lhttpc to latest version

This simplifies error handling and fixes many
dialyzer warnings. Related upstream pull requests
are:

* esl/lhttpc#10
* esl/lhttpc#11
* esl/lhttpc#12

This is part of CBD-73

Change-Id: I5c7239ee67cbb1fa5b88fd51e9ce803e9b244f6a
Reviewed-on: http://review.couchbase.org/15099
Tested-by: buildbot <build@couchbase.com>
Reviewed-by: Volker Mische <volker.mische@gmail.com>
  • Loading branch information...
commit eeff68595502f6237f0ce654db260418f260af94 1 parent fb6fd46
@fdmanana fdmanana authored Damienkatz committed
View
2  Makefile.am
@@ -161,4 +161,4 @@ rebuild_plt:
$(MAKE) $(COUCHDB_PLT)
dialyzer: all $(COUCHDB_PLT)
- dialyzer --plt $(COUCHDB_PLT) -pa src/couchdb -pa src/couch_set_view/ebin -pa src/mapreduce -c src/couchdb -c src/couch_set_view/ebin
+ dialyzer --plt $(COUCHDB_PLT) -pa src/couchdb -pa src/couch_set_view/ebin -pa src/mapreduce -c src/couchdb -c src/couch_set_view/ebin -c src/lhttpc
View
54 src/couchdb/couch_api_wrap_httpc.erl
@@ -162,46 +162,34 @@ error_cause(Cause) ->
stream_data_self(#httpdb{timeout = T} = HttpDb, Params, Pid, Callback) ->
- try
- case lhttpc:get_body_part(Pid, T) of
- {ok, {http_eob, _Trailers}} ->
- {<<>>, fun() -> throw({maybe_retry_req, more_data_expected}) end};
- {ok, Data} ->
- {Data, fun() -> stream_data_self(HttpDb, Params, Pid, Callback) end};
- Error ->
- throw({maybe_retry_req, Error})
- end
- catch exit:ExitReason ->
- throw({maybe_retry_req, ExitReason})
+ case lhttpc:get_body_part(Pid, T) of
+ {ok, {http_eob, _Trailers}} ->
+ {<<>>, fun() -> throw({maybe_retry_req, more_data_expected}) end};
+ {ok, Data} ->
+ {Data, fun() -> stream_data_self(HttpDb, Params, Pid, Callback) end};
+ Error ->
+ throw({maybe_retry_req, Error})
end.
make_upload_fun(UploadState, #httpdb{timeout = Timeout} = HttpDb) ->
fun(eof) ->
- try
- case lhttpc:send_body_part(UploadState, http_eob, Timeout) of
- {ok, {{Code, _}, Headers, Body}} when ?NOT_HTTP_ERROR(Code) ->
- {ok, Code, Headers, decode_body(Body)};
- {ok, {{Code, _}, Headers, _Body}} when ?IS_HTTP_REDIRECT(Code) ->
- throw({redirect_req, Code, Headers});
- {ok, {{Code, _}, _Headers, _Body}} ->
- throw({maybe_retry_req, {code, Code}});
- Error ->
- throw({maybe_retry_req, Error})
- end
- catch exit:ExitReason ->
- throw({maybe_retry_req, ExitReason})
+ case lhttpc:send_body_part(UploadState, http_eob, Timeout) of
+ {ok, {{Code, _}, Headers, Body}} when ?NOT_HTTP_ERROR(Code) ->
+ {ok, Code, Headers, decode_body(Body)};
+ {ok, {{Code, _}, Headers, _Body}} when ?IS_HTTP_REDIRECT(Code) ->
+ throw({redirect_req, Code, Headers});
+ {ok, {{Code, _}, _Headers, _Body}} ->
+ throw({maybe_retry_req, {code, Code}});
+ Error ->
+ throw({maybe_retry_req, Error})
end;
(BodyPart) ->
- try
- case lhttpc:send_body_part(UploadState, BodyPart, Timeout) of
- {ok, UploadState2} ->
- {ok, make_upload_fun(UploadState2, HttpDb)};
- Error ->
- throw({maybe_retry_req, Error})
- end
- catch exit:ExitReason ->
- throw({maybe_retry_req, ExitReason})
+ case lhttpc:send_body_part(UploadState, BodyPart, Timeout) of
+ {ok, UploadState2} ->
+ {ok, make_upload_fun(UploadState2, HttpDb)};
+ Error ->
+ throw({maybe_retry_req, Error})
end
end.
View
12 src/couchdb/couch_index_merger.erl
@@ -309,9 +309,9 @@ get_ddoc(#httpdb{} = HttpDb, Id) ->
"database `~s`: ~s", [Id, db_uri(HttpDb), Error]),
throw({error, iolist_to_binary(Msg)})
end;
- Error ->
+ {error, Error} ->
Msg = io_lib:format("Error getting design document `~s` from database "
- "`~s`: ~s", [Id, db_uri(HttpDb), lhttpc_error_msg(Error)]),
+ "`~s`: ~s", [Id, db_uri(HttpDb), to_binary(Error)]),
throw({error, iolist_to_binary(Msg)})
end;
get_ddoc(Db, Id) ->
@@ -354,10 +354,6 @@ ddoc_not_found_msg(DbName, DDocId) ->
[DDocId, db_uri(DbName)]),
iolist_to_binary(Msg).
-lhttpc_error_msg({error, Reason}) ->
- to_binary(Reason);
-lhttpc_error_msg(Reason) ->
- to_binary(Reason).
lhttpc_options(#httpdb{timeout = T}) ->
% TODO: add SSL options like verify and cacertfile, which should
@@ -655,9 +651,7 @@ stream_data(Pid, Timeout) ->
{ok, Data} ->
{Data, fun() -> stream_data(Pid, Timeout) end};
{error, _} = Error ->
- throw(Error);
- Error ->
- throw({error, Error})
+ throw(Error)
end.
View
145 src/lhttpc/lhttpc.erl
@@ -46,8 +46,15 @@
-include("lhttpc_types.hrl").
-include("lhttpc.hrl").
--type result() :: {ok, {{pos_integer(), string()}, headers(), binary()}} |
- {error, atom()}.
+-type upload_state() :: {pid(), window_size()}.
+-type body() :: binary() |
+ 'undefined' | % HEAD request.
+ pid(). % When partial_download option is used.
+
+-type result() ::
+ {ok, {{pos_integer(), string()}, headers(), body()}} |
+ {ok, upload_state()} |
+ {error, atom()}.
%% @hidden
-spec start(normal | {takeover, node()} | {failover, node()}, any()) ->
@@ -346,22 +353,17 @@ request(URL, Method, Hdrs, Body, Timeout, Options) ->
-spec request(string(), 1..65535, true | false, string(), atom() | string(),
headers(), iolist(), pos_integer(), [option()]) -> result().
request(Host, Port, Ssl, Path, Method, Hdrs, Body, Timeout, Options) ->
- verify_options(Options, []),
+ verify_options(Options),
Args = [self(), Host, Port, Ssl, Path, Method, Hdrs, Body, Options],
Pid = spawn_link(lhttpc_client, request, Args),
receive
{response, Pid, R} ->
R;
- {exit, Pid, Reason} ->
- % We would rather want to exit here, instead of letting the
- % linked client send us an exit signal, since this can be
- % caught by the caller.
- exit(Reason);
{'EXIT', Pid, Reason} ->
- % This could happen if the process we're running in taps exits
+ % This could happen if the process we're running in traps exits
% and the client process exits due to some exit signal being
% sent to it. Very unlikely though
- exit(Reason)
+ {error, Reason}
after Timeout ->
kill_client(Pid)
end.
@@ -378,8 +380,7 @@ request(Host, Port, Ssl, Path, Method, Hdrs, Body, Timeout, Options) ->
%% Would be the same as calling
%% `send_body_part(UploadState, BodyPart, infinity)'.
%% @end
--spec send_body_part({pid(), window_size()}, iolist()) ->
- {pid(), window_size()} | result().
+-spec send_body_part(upload_state(), iolist() | 'http_eob') -> result().
send_body_part({Pid, Window}, IoList) ->
send_body_part({Pid, Window}, IoList, infinity).
@@ -404,8 +405,7 @@ send_body_part({Pid, Window}, IoList) ->
%% there is no response within `Timeout' milliseconds, the request is
%% canceled and `{error, timeout}' is returned.
%% @end
--spec send_body_part({pid(), window_size()}, iolist(), timeout()) ->
- {ok, {pid(), window_size()}} | result().
+-spec send_body_part(upload_state(), iolist() | 'http_eob', timeout()) -> result().
send_body_part({Pid, _Window}, http_eob, Timeout) when is_pid(Pid) ->
Pid ! {body_part, self(), http_eob},
read_response(Pid, Timeout);
@@ -415,10 +415,8 @@ send_body_part({Pid, 0}, IoList, Timeout) when is_pid(Pid) ->
send_body_part({Pid, 1}, IoList, Timeout);
{response, Pid, R} ->
R;
- {exit, Pid, Reason} ->
- exit(Reason);
{'EXIT', Pid, Reason} ->
- exit(Reason)
+ {error, Reason}
after Timeout ->
kill_client(Pid)
end;
@@ -430,10 +428,8 @@ send_body_part({Pid, Window}, IoList, _Timeout) when Window > 0, is_pid(Pid) ->
{ok, {Pid, Window}};
{response, Pid, R} ->
R;
- {exit, Pid, Reason} ->
- exit(Reason);
{'EXIT', Pid, Reason} ->
- exit(Reason)
+ {error, Reason}
after 0 ->
{ok, {Pid, lhttpc_lib:dec(Window)}}
end.
@@ -494,7 +490,9 @@ send_trailers({Pid, _Window}, Trailers, Timeout)
%% Would be the same as calling
%% `get_body_part(HTTPClient, infinity)'.
%% @end
--spec get_body_part(pid()) -> {ok, binary()} | {ok, {http_eob, headers()}}.
+-spec get_body_part(pid()) -> {ok, binary()} |
+ {ok, {http_eob, headers()}} |
+ {error, term()}.
get_body_part(Pid) ->
get_body_part(Pid, infinity).
@@ -512,7 +510,9 @@ get_body_part(Pid) ->
%% response those are returned with `http_eob' as well.
%% @end
-spec get_body_part(pid(), timeout()) ->
- {ok, binary()} | {ok, {http_eob, headers()}}.
+ {ok, binary()} |
+ {ok, {http_eob, headers()}} |
+ {error, term()}.
get_body_part(Pid, Timeout) ->
receive
{body_part, Pid, Bin} ->
@@ -533,10 +533,8 @@ read_response(Pid, Timeout) ->
read_response(Pid, Timeout);
{response, Pid, R} ->
R;
- {exit, Pid, Reason} ->
- exit(Reason);
{'EXIT', Pid, Reason} ->
- exit(Reason)
+ {error, Reason}
after Timeout ->
kill_client(Pid)
end.
@@ -549,70 +547,53 @@ kill_client(Pid) ->
{response, Pid, R} ->
erlang:demonitor(Monitor, [flush]),
R;
- {'DOWN', _, process, Pid, timeout} ->
- {error, timeout};
{'DOWN', _, process, Pid, Reason} ->
- erlang:error(Reason)
+ {error, Reason}
end.
--spec verify_options(options(), options()) -> ok.
-verify_options([{send_retry, N} | Options], Errors)
- when is_integer(N), N >= 0 ->
- verify_options(Options, Errors);
-verify_options([{connect_timeout, infinity} | Options], Errors) ->
- verify_options(Options, Errors);
-verify_options([{connect_timeout, MS} | Options], Errors)
+-spec verify_options(options()) -> ok.
+verify_options([{send_retry, N} | Options]) when is_integer(N), N >= 0 ->
+ verify_options(Options);
+verify_options([{connect_timeout, infinity} | Options]) ->
+ verify_options(Options);
+verify_options([{connect_timeout, MS} | Options])
when is_integer(MS), MS >= 0 ->
- verify_options(Options, Errors);
-verify_options([{partial_upload, WindowSize} | Options], Errors)
+ verify_options(Options);
+verify_options([{partial_upload, WindowSize} | Options])
when is_integer(WindowSize), WindowSize >= 0 ->
- verify_options(Options, Errors);
-verify_options([{partial_upload, infinity} | Options], Errors) ->
- verify_options(Options, Errors);
-verify_options([{partial_download, DownloadOptions} | Options], Errors)
+ verify_options(Options);
+verify_options([{partial_upload, infinity} | Options]) ->
+ verify_options(Options);
+verify_options([{partial_download, DownloadOptions} | Options])
when is_list(DownloadOptions) ->
- case verify_partial_download(DownloadOptions, []) of
- [] ->
- verify_options(Options, Errors);
- OptionErrors ->
- NewErrors = [{partial_download, OptionErrors} | Errors],
- verify_options(Options, NewErrors)
- end;
-verify_options([{connect_options, List} | Options], Errors)
- when is_list(List) ->
- verify_options(Options, Errors);
-verify_options([{proxy, List} | Options], Errors)
- when is_list(List) ->
- verify_options(Options, Errors);
-verify_options([{proxy_ssl_options, List} | Options], Errors)
- when is_list(List) ->
- verify_options(Options, Errors);
-verify_options([{pool, PidOrName} | Options], Errors)
+ verify_partial_download(DownloadOptions),
+ verify_options(Options);
+verify_options([{connect_options, List} | Options]) when is_list(List) ->
+ verify_options(Options);
+verify_options([{proxy, List} | Options]) when is_list(List) ->
+ verify_options(Options);
+verify_options([{proxy_ssl_options, List} | Options]) when is_list(List) ->
+ verify_options(Options);
+verify_options([{pool, PidOrName} | Options])
when is_pid(PidOrName); is_atom(PidOrName) ->
- verify_options(Options, Errors);
-verify_options([Option | Options], Errors) ->
- verify_options(Options, [Option | Errors]);
-verify_options([], []) ->
- ok;
-verify_options([], Errors) ->
- bad_options(Errors).
-
--spec bad_options(options()) -> no_return().
-bad_options(Errors) ->
- erlang:error({bad_options, Errors}).
+ verify_options(Options);
+verify_options([Option | _Rest]) ->
+ erlang:error({bad_option, Option});
+verify_options([]) ->
+ ok.
--spec verify_partial_download(options(), options()) -> options().
-verify_partial_download([{window_size, infinity} | Options], Errors)->
- verify_partial_download(Options, Errors);
-verify_partial_download([{window_size, Size} | Options], Errors) when
+-spec verify_partial_download(options()) -> ok.
+verify_partial_download([{window_size, infinity} | Options])->
+ verify_partial_download(Options);
+verify_partial_download([{window_size, Size} | Options]) when
is_integer(Size), Size >= 0 ->
- verify_partial_download(Options, Errors);
-verify_partial_download([{part_size, Size} | Options], Errors) when
+ verify_partial_download(Options);
+verify_partial_download([{part_size, Size} | Options]) when
is_integer(Size), Size >= 0 ->
- verify_partial_download(Options, Errors);
-verify_partial_download([{part_size, infinity} | Options], Errors) ->
- verify_partial_download(Options, Errors);
-verify_partial_download([Option | Options], Errors) ->
- verify_partial_download(Options, [Option | Errors]);
-verify_partial_download([], Errors) ->
- Errors.
+ verify_partial_download(Options);
+verify_partial_download([{part_size, infinity} | Options]) ->
+ verify_partial_download(Options);
+verify_partial_download([Option | _Options]) ->
+ erlang:error({bad_option, {partial_download, Option}});
+verify_partial_download([]) ->
+ ok.
View
5 src/lhttpc/lhttpc_client.erl
@@ -86,8 +86,9 @@ request(From, Host, Port, Ssl, Path, Method, Hdrs, Body, Options) ->
{response, self(), {error, Reason}};
error:closed ->
{response, self(), {error, connection_closed}};
- error:Error ->
- {exit, self(), {Error, erlang:get_stacktrace()}}
+ error:Reason ->
+ Stack = erlang:get_stacktrace(),
+ {response, self(), {error, {Reason, Stack}}}
end,
case Result of
{response, _, {ok, {no_return, _}}} -> ok;
View
8 src/lhttpc/lhttpc_sock.erl
@@ -115,16 +115,18 @@ send(Socket, Request, true) ->
send(Socket, Request, false) ->
gen_tcp:send(Socket, Request).
-%% @spec (Socket, Pid, SslFlag) -> ok | {error, Reason}
+%% @spec (Socket, Process, SslFlag) -> ok | {error, Reason}
%% Socket = socket()
-%% Pid = pid()
+%% Process = pid() | atom()
%% SslFlag = boolean()
%% Reason = atom()
%% @doc
%% Sets the controlling proces for the `Socket'.
%% @end
--spec controlling_process(socket(), pid(), boolean()) ->
+-spec controlling_process(socket(), pid() | atom(), boolean()) ->
ok | {error, atom()}.
+controlling_process(Socket, Controller, IsSsl) when is_atom(Controller) ->
+ controlling_process(Socket, whereis(Controller), IsSsl);
controlling_process(Socket, Pid, true) ->
ssl:controlling_process(Socket, Pid);
controlling_process(Socket, Pid, false) ->
View
14 src/lhttpc/lhttpc_types.hrl
@@ -29,11 +29,23 @@
-type socket() :: _.
+-type invalid_option() :: any().
+
+-type partial_download_option() ::
+ {window_size, window_size()} |
+ {part_size, non_neg_integer() | infinity} |
+ invalid_option().
+
-type option() ::
{connect_timeout, timeout()} |
{send_retry, non_neg_integer()} |
{partial_upload, non_neg_integer() | infinity} |
- {partial_download, pid(), non_neg_integer() | infinity}.
+ {partial_download, [partial_download_option()]} |
+ {connect_options, socket_options()} |
+ {proxy, string()} |
+ {proxy_ssl_options, socket_options()} |
+ {pool, pid() | atom()} |
+ invalid_option().
-type options() :: [option()].
Please sign in to comment.
Something went wrong with that request. Please try again.