Skip to content

Commit

Permalink
Let client retry HTTP upload on file size mismatch
Browse files Browse the repository at this point in the history
Let the main mod_http_upload process look at the size of an HTTP upload
rather than performing this check in the ejabberd_http handler.  This
way, the upload slot won't be invalidated if the size of the uploaded
file doesn't match the size requested for the slot.  The PUT request is
still rejected, but the client now has a chance to retry the upload.
  • Loading branch information
weiss committed May 8, 2016
1 parent bcf07fd commit f7f40cf
Showing 1 changed file with 18 additions and 17 deletions.
35 changes: 18 additions & 17 deletions src/mod_http_upload.erl
Expand Up @@ -321,22 +321,24 @@ init({ServerHost, Opts}) ->
-> {reply, {ok, pos_integer(), binary(),
pos_integer() | undefined,
pos_integer() | undefined}, state()} |
{reply, {error, binary()}, state()} | {noreply, state()}.
{reply, {error, atom()}, state()} | {noreply, state()}.

handle_call({use_slot, Slot}, _From, #state{file_mode = FileMode,
dir_mode = DirMode,
get_url = GetPrefix,
thumbnail = Thumbnail,
docroot = DocRoot} = State) ->
handle_call({use_slot, Slot, Size}, _From, #state{file_mode = FileMode,
dir_mode = DirMode,
get_url = GetPrefix,
thumbnail = Thumbnail,
docroot = DocRoot} = State) ->
case get_slot(Slot, State) of
{ok, {Size, Timer}} ->
timer:cancel(Timer),
NewState = del_slot(Slot, State),
Path = str:join([DocRoot | Slot], <<$/>>),
{reply, {ok, Size, Path, FileMode, DirMode, GetPrefix, Thumbnail},
{reply, {ok, Path, FileMode, DirMode, GetPrefix, Thumbnail},
NewState};
{ok, {_WrongSize, _Timer}} ->
{reply, {error, size_mismatch}, State};
error ->
{reply, {error, <<"Invalid slot">>}, State}
{reply, {error, invalid_slot}, State}
end;
handle_call(get_docroot, _From, #state{docroot = DocRoot} = State) ->
{reply, {ok, DocRoot}, State};
Expand Down Expand Up @@ -406,9 +408,8 @@ process(LocalPath, #request{method = Method, host = Host, ip = IP})
process(_LocalPath, #request{method = 'PUT', host = Host, ip = IP,
data = Data} = Request) ->
{Proc, Slot} = parse_http_request(Request),
case catch gen_server:call(Proc, {use_slot, Slot}) of
{ok, Size, Path, FileMode, DirMode, GetPrefix, Thumbnail}
when byte_size(Data) == Size ->
case catch gen_server:call(Proc, {use_slot, Slot, byte_size(Data)}) of
{ok, Path, FileMode, DirMode, GetPrefix, Thumbnail} ->
?DEBUG("Storing file from ~s for ~s: ~s",
[?ADDR_TO_STR(IP), Host, Path]),
case store_file(Path, Data, FileMode, DirMode,
Expand All @@ -422,13 +423,13 @@ process(_LocalPath, #request{method = 'PUT', host = Host, ip = IP,
[Path, ?ADDR_TO_STR(IP), Host, ?FORMAT(Error)]),
http_response(Host, 500)
end;
{ok, Size, Path, _FileMode, _DirMode, _GetPrefix, _Thumbnail} ->
?INFO_MSG("Rejecting file ~s from ~s for ~s: Size is ~B, not ~B",
[Path, ?ADDR_TO_STR(IP), Host, byte_size(Data), Size]),
{error, size_mismatch} ->
?INFO_MSG("Rejecting file from ~s for ~s: Unexpected size (~B)",
[?ADDR_TO_STR(IP), Host, byte_size(Data)]),
http_response(Host, 413);
{error, Error} ->
?INFO_MSG("Rejecting file from ~s for ~s: ~p",
[?ADDR_TO_STR(IP), Host, Error]),
{error, invalid_slot} ->
?INFO_MSG("Rejecting file from ~s for ~s: Invalid slot",
[?ADDR_TO_STR(IP), Host]),
http_response(Host, 403);
Error ->
?ERROR_MSG("Cannot handle PUT request from ~s for ~s: ~p",
Expand Down

0 comments on commit f7f40cf

Please sign in to comment.