mod_http_upload: Add "jid_in_url" option

The new "jid_in_url" option allows for configuring the way the user's
JID is included in the URLs generated by mod_http_upload.
This commit is contained in:
Holger Weiss 2015-08-21 23:22:48 +02:00
parent 034a156066
commit 216e244b6a
2 changed files with 43 additions and 8 deletions

View File

@ -66,6 +66,13 @@ The configurable mod_http_upload options are:
This option limits the acceptable file size. Either a number of bytes This option limits the acceptable file size. Either a number of bytes
(larger than zero) or 'infinity' must be specified. (larger than zero) or 'infinity' must be specified.
- jid_in_url (default: 'sha1')
When this option is set to 'node', the node identifier of the user's JID
(i.e., the user name) is included in the GET and PUT URLs generated by
mod_http_upload. Otherwise, a SHA-1 hash of the user's bare JID is
included instead.
- docroot (default: 'undefined') - docroot (default: 'undefined')
Uploaded files are stored below the directory specified (as an absolute Uploaded files are stored below the directory specified (as an absolute

View File

@ -75,6 +75,7 @@
name :: binary(), name :: binary(),
access :: atom(), access :: atom(),
max_size :: pos_integer() | infinity, max_size :: pos_integer() | infinity,
jid_in_url :: sha1 | node,
docroot :: binary(), docroot :: binary(),
put_url :: binary(), put_url :: binary(),
get_url :: binary(), get_url :: binary(),
@ -142,6 +143,10 @@ mod_opt_type(max_size) ->
fun (I) when is_integer(I), I > 0 -> I; fun (I) when is_integer(I), I > 0 -> I;
(infinity) -> infinity (infinity) -> infinity
end; end;
mod_opt_type(jid_in_url) ->
fun(sha1) -> sha1;
(node) -> node
end;
mod_opt_type(docroot) -> mod_opt_type(docroot) ->
fun iolist_to_binary/1; fun iolist_to_binary/1;
mod_opt_type(put_url) -> mod_opt_type(put_url) ->
@ -157,7 +162,8 @@ mod_opt_type(service_url) ->
(<<"https://", _/binary>> = URL) -> URL (<<"https://", _/binary>> = URL) -> URL
end; end;
mod_opt_type(_) -> mod_opt_type(_) ->
[host, name, access, max_size, docroot, put_url, get_url, service_url]. [host, name, access, max_size, jid_in_url, docroot,
put_url, get_url, service_url].
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% gen_server callbacks. %% gen_server callbacks.
@ -176,6 +182,11 @@ init({ServerHost, Opts}) ->
fun (I) when is_integer(I), I > 0 -> I; fun (I) when is_integer(I), I > 0 -> I;
(infinity) -> infinity (infinity) -> infinity
end, 104857600), end, 104857600),
JIDinURL = gen_mod:get_opt(jid_in_url, Opts,
fun(sha1) -> sha1;
(node) -> node
end,
sha1),
DocRoot = gen_mod:get_opt(docroot, Opts, fun iolist_to_binary/1, DocRoot = gen_mod:get_opt(docroot, Opts, fun iolist_to_binary/1,
undefined), undefined),
PutURL = gen_mod:get_opt(put_url, Opts, PutURL = gen_mod:get_opt(put_url, Opts,
@ -210,7 +221,9 @@ init({ServerHost, Opts}) ->
end, end,
ejabberd_router:register_route(Host), ejabberd_router:register_route(Host),
{ok, #state{server_host = ServerHost, host = Host, name = Name, {ok, #state{server_host = ServerHost, host = Host, name = Name,
access = Access, max_size = MaxSize, docroot = DocRoot, access = Access, max_size = MaxSize,
jid_in_url = JIDinURL,
docroot = DocRoot,
put_url = str:strip(PutURL, right, $/), put_url = str:strip(PutURL, right, $/),
get_url = str:strip(GetURL, right, $/), get_url = str:strip(GetURL, right, $/),
service_url = ServiceURL}}. service_url = ServiceURL}}.
@ -440,14 +453,15 @@ create_slot(#state{service_url = undefined, max_size = MaxSize},
?INFO_MSG("Rejecting file ~s from ~s (too large: ~B bytes)", ?INFO_MSG("Rejecting file ~s from ~s (too large: ~B bytes)",
[File, User, Size]), [File, User, Size]),
{error, ?ERRT_NOT_ACCEPTABLE(Lang, Text)}; {error, ?ERRT_NOT_ACCEPTABLE(Lang, Text)};
create_slot(#state{service_url = undefined}, User, File, _Size, _ContentType, create_slot(#state{service_url = undefined,
_Lang) -> jid_in_url = JIDinURL},
UserHash = p1_sha:sha(User), User, File, _Size, _ContentType, _Lang) ->
UserStr = make_user_string(User, JIDinURL),
RandStr = make_rand_string(40), RandStr = make_rand_string(40),
SaneFile = re:replace(File, <<"[^a-zA-Z0-9_.-]">>, <<$_>>, SaneFile = re:replace(File, <<"[^a-zA-Z0-9_.-]">>, <<$_>>,
[global, {return, binary}]), [global, {return, binary}]),
?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)", [User, File]), ?INFO_MSG("Got HTTP upload slot for ~s (file: ~s)", [User, File]),
{ok, [UserHash, RandStr, SaneFile]}; {ok, [UserStr, RandStr, SaneFile]};
create_slot(#state{service_url = ServiceURL}, User, File, Size, ContentType, create_slot(#state{service_url = ServiceURL}, User, File, Size, ContentType,
_Lang) -> _Lang) ->
Options = [{body_format, binary}, {full_result, false}], Options = [{body_format, binary}, {full_result, false}],
@ -520,6 +534,14 @@ slot_el(PutURL, GetURL) ->
#xmlel{name = <<"get">>, #xmlel{name = <<"get">>,
children = [{xmlcdata, GetURL}]}]}. children = [{xmlcdata, GetURL}]}]}.
-spec make_user_string(binary(), sha1 | node) -> binary().
make_user_string(User, sha1) ->
p1_sha:sha(User);
make_user_string(User, node) ->
[Node, _Domain] = binary:split(User, <<$@>>),
re:replace(Node, <<"[^a-zA-Z0-9_.-]">>, <<$_>>, [global, {return, binary}]).
-spec make_rand_string(non_neg_integer()) -> binary(). -spec make_rand_string(non_neg_integer()) -> binary().
make_rand_string(Length) -> make_rand_string(Length) ->
@ -630,8 +652,14 @@ remove_user(User, Server) ->
undefined -> undefined ->
ok; ok;
DocRoot -> DocRoot ->
UserHash = p1_sha:sha(LUser), JIDinURL = gen_mod:get_module_opt(LServer, ?MODULE, jid_in_url,
UserDir = str:join([DocRoot, UserHash], <<$/>>), fun(sha1) -> sha1;
(node) -> node
end,
sha1),
UserStr = make_user_string(<<LUser/binary, $@, LServer/binary>>,
JIDinURL),
UserDir = str:join([DocRoot, UserStr], <<$/>>),
case del_tree(UserDir) of case del_tree(UserDir) of
ok -> ok ->
?INFO_MSG("Removed HTTP upload directory of ~s@~s", ?INFO_MSG("Removed HTTP upload directory of ~s@~s",