Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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
Filipe Manana fdmanana authored Damienkatz committed
2  Makefile.am
View
@@ -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
54 src/couchdb/couch_api_wrap_httpc.erl
View
@@ -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.
12 src/couchdb/couch_index_merger.erl
View
@@ -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.
145 src/lhttpc/lhttpc.erl
View
@@ -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.
5 src/lhttpc/lhttpc_client.erl
View
@@ -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;
8 src/lhttpc/lhttpc_sock.erl
View
@@ -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) ->
14 src/lhttpc/lhttpc_types.hrl
View
@@ -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.