Option to define custom HTTP headers in mod_http_fileserver (EJAB-612)
SVN Revision: 2747
This commit is contained in:
parent
e5e777694d
commit
1716b090f9
|
@ -2155,6 +2155,9 @@ Directory to serve the files.
|
||||||
</DD><DT CLASS="dt-description"><B><TT>{accesslog, Path}</TT></B></DT><DD CLASS="dd-description">
|
</DD><DT CLASS="dt-description"><B><TT>{accesslog, Path}</TT></B></DT><DD CLASS="dd-description">
|
||||||
File to log accesses using an Apache-like format.
|
File to log accesses using an Apache-like format.
|
||||||
No log will be recorded if this option is not specified.
|
No log will be recorded if this option is not specified.
|
||||||
|
</DD><DT CLASS="dt-description"><B><TT>{custom_headers, [ {Name, Value}, ...]}</TT></B></DT><DD CLASS="dd-description">
|
||||||
|
Indicate custom HTTP headers to be included in all responses.
|
||||||
|
Default value is: <TT>[]</TT>
|
||||||
</DD><DT CLASS="dt-description"><B><TT>{directory_indices, [Index, ...]}</TT></B></DT><DD CLASS="dd-description">
|
</DD><DT CLASS="dt-description"><B><TT>{directory_indices, [Index, ...]}</TT></B></DT><DD CLASS="dd-description">
|
||||||
Indicate one or more directory index files, similarly to Apache’s
|
Indicate one or more directory index files, similarly to Apache’s
|
||||||
DirectoryIndex variable. When a web request hits a directory
|
DirectoryIndex variable. When a web request hits a directory
|
||||||
|
@ -2184,6 +2187,9 @@ To use this module you must enable it:
|
||||||
{".png", "image/png"},
|
{".png", "image/png"},
|
||||||
{".jpg", undefined}
|
{".jpg", undefined}
|
||||||
]},
|
]},
|
||||||
|
{custom_headers, [{"X-Powered-By", "Erlang/OTP"},
|
||||||
|
{"X-Fry", "It's a widely-believed fact!"}
|
||||||
|
]},
|
||||||
{default_content_type, "text/html"}
|
{default_content_type, "text/html"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -2849,6 +2849,9 @@ Options:
|
||||||
\titem{\{accesslog, Path\}} \ind{options!accesslog}
|
\titem{\{accesslog, Path\}} \ind{options!accesslog}
|
||||||
File to log accesses using an Apache-like format.
|
File to log accesses using an Apache-like format.
|
||||||
No log will be recorded if this option is not specified.
|
No log will be recorded if this option is not specified.
|
||||||
|
\titem{\{custom\_headers, [ \{Name, Value\}, ...]\}} \ind{options!customheaders}
|
||||||
|
Indicate custom HTTP headers to be included in all responses.
|
||||||
|
Default value is: \term{[]}
|
||||||
\titem{\{directory\_indices, [Index, ...]\}} \ind{options!directoryindices}
|
\titem{\{directory\_indices, [Index, ...]\}} \ind{options!directoryindices}
|
||||||
Indicate one or more directory index files, similarly to Apache's
|
Indicate one or more directory index files, similarly to Apache's
|
||||||
DirectoryIndex variable. When a web request hits a directory
|
DirectoryIndex variable. When a web request hits a directory
|
||||||
|
@ -2886,6 +2889,9 @@ To use this module you must enable it:
|
||||||
{".png", "image/png"},
|
{".png", "image/png"},
|
||||||
{".jpg", undefined}
|
{".jpg", undefined}
|
||||||
]},
|
]},
|
||||||
|
{custom_headers, [{"X-Powered-By", "Erlang/OTP"},
|
||||||
|
{"X-Fry", "It's a widely-believed fact!"}
|
||||||
|
]},
|
||||||
{default_content_type, "text/html"}
|
{default_content_type, "text/html"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-record(state, {host, docroot, accesslog, accesslogfd, directory_indices,
|
-record(state, {host, docroot, accesslog, accesslogfd, directory_indices,
|
||||||
default_content_type, content_types = []}).
|
custom_headers, default_content_type, content_types = []}).
|
||||||
|
|
||||||
-define(PROCNAME, ejabberd_mod_http_fileserver).
|
-define(PROCNAME, ejabberd_mod_http_fileserver).
|
||||||
|
|
||||||
|
@ -141,12 +141,13 @@ start_link(Host, Opts) ->
|
||||||
init([Host, Opts]) ->
|
init([Host, Opts]) ->
|
||||||
try initialize(Host, Opts) of
|
try initialize(Host, Opts) of
|
||||||
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
|
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
|
||||||
DefaultContentType, ContentTypes} ->
|
CustomHeaders, DefaultContentType, ContentTypes} ->
|
||||||
{ok, #state{host = Host,
|
{ok, #state{host = Host,
|
||||||
accesslog = AccessLog,
|
accesslog = AccessLog,
|
||||||
accesslogfd = AccessLogFD,
|
accesslogfd = AccessLogFD,
|
||||||
docroot = DocRoot,
|
docroot = DocRoot,
|
||||||
directory_indices = DirectoryIndices,
|
directory_indices = DirectoryIndices,
|
||||||
|
custom_headers = CustomHeaders,
|
||||||
default_content_type = DefaultContentType,
|
default_content_type = DefaultContentType,
|
||||||
content_types = ContentTypes}}
|
content_types = ContentTypes}}
|
||||||
catch
|
catch
|
||||||
|
@ -163,12 +164,13 @@ initialize(Host, Opts) ->
|
||||||
AccessLog = gen_mod:get_opt(accesslog, Opts, undefined),
|
AccessLog = gen_mod:get_opt(accesslog, Opts, undefined),
|
||||||
AccessLogFD = try_open_log(AccessLog, Host),
|
AccessLogFD = try_open_log(AccessLog, Host),
|
||||||
DirectoryIndices = gen_mod:get_opt(directory_indices, Opts, []),
|
DirectoryIndices = gen_mod:get_opt(directory_indices, Opts, []),
|
||||||
|
CustomHeaders = gen_mod:get_opt(custom_headers, Opts, []),
|
||||||
DefaultContentType = gen_mod:get_opt(default_content_type, Opts,
|
DefaultContentType = gen_mod:get_opt(default_content_type, Opts,
|
||||||
?DEFAULT_CONTENT_TYPE),
|
?DEFAULT_CONTENT_TYPE),
|
||||||
ContentTypes = build_list_content_types(gen_mod:get_opt(content_types, Opts, []), ?DEFAULT_CONTENT_TYPES),
|
ContentTypes = build_list_content_types(gen_mod:get_opt(content_types, Opts, []), ?DEFAULT_CONTENT_TYPES),
|
||||||
?INFO_MSG("initialize: ~n ~p", [ContentTypes]),%+++
|
?INFO_MSG("initialize: ~n ~p", [ContentTypes]),%+++
|
||||||
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
|
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
|
||||||
DefaultContentType, ContentTypes}.
|
CustomHeaders, DefaultContentType, ContentTypes}.
|
||||||
|
|
||||||
%% @spec (AdminCTs::[CT], Default::[CT]) -> [CT]
|
%% @spec (AdminCTs::[CT], Default::[CT]) -> [CT]
|
||||||
%% where CT = {Extension::string(), Value}
|
%% where CT = {Extension::string(), Value}
|
||||||
|
@ -231,6 +233,7 @@ try_open_log(FN, Host) ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
handle_call({serve, LocalPath}, _From, State) ->
|
handle_call({serve, LocalPath}, _From, State) ->
|
||||||
Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices,
|
Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices,
|
||||||
|
State#state.custom_headers,
|
||||||
State#state.default_content_type, State#state.content_types),
|
State#state.default_content_type, State#state.content_types),
|
||||||
{reply, Reply, State};
|
{reply, Reply, State};
|
||||||
handle_call(_Request, _From, State) ->
|
handle_call(_Request, _From, State) ->
|
||||||
|
@ -298,42 +301,44 @@ process(LocalPath, Request) ->
|
||||||
ejabberd_web:error(not_found)
|
ejabberd_web:error(not_found)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
serve(LocalPath, DocRoot, DirectoryIndices, DefaultContentType, ContentTypes) ->
|
serve(LocalPath, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType, ContentTypes) ->
|
||||||
FileName = filename:join(filename:split(DocRoot) ++ LocalPath),
|
FileName = filename:join(filename:split(DocRoot) ++ LocalPath),
|
||||||
case file:read_file_info(FileName) of
|
case file:read_file_info(FileName) of
|
||||||
{error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND;
|
{error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND;
|
||||||
{error, eacces} -> ?HTTP_ERR_FORBIDDEN;
|
{error, eacces} -> ?HTTP_ERR_FORBIDDEN;
|
||||||
{ok, #file_info{type = directory}} -> serve_index(FileName,
|
{ok, #file_info{type = directory}} -> serve_index(FileName,
|
||||||
DirectoryIndices,
|
DirectoryIndices,
|
||||||
|
CustomHeaders,
|
||||||
DefaultContentType,
|
DefaultContentType,
|
||||||
ContentTypes);
|
ContentTypes);
|
||||||
{ok, FileInfo} -> serve_file(FileInfo, FileName,
|
{ok, FileInfo} -> serve_file(FileInfo, FileName,
|
||||||
|
CustomHeaders,
|
||||||
DefaultContentType,
|
DefaultContentType,
|
||||||
ContentTypes)
|
ContentTypes)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Troll through the directory indices attempting to find one which
|
%% Troll through the directory indices attempting to find one which
|
||||||
%% works, if none can be found, return a 404.
|
%% works, if none can be found, return a 404.
|
||||||
serve_index(_FileName, [], _DefaultContentType, _ContentTypes) ->
|
serve_index(_FileName, [], CH, _DefaultContentType, _ContentTypes) ->
|
||||||
?HTTP_ERR_FILE_NOT_FOUND;
|
?HTTP_ERR_FILE_NOT_FOUND;
|
||||||
serve_index(FileName, [Index | T], DefaultContentType, ContentTypes) ->
|
serve_index(FileName, [Index | T], CH, DefaultContentType, ContentTypes) ->
|
||||||
IndexFileName = filename:join([FileName] ++ [Index]),
|
IndexFileName = filename:join([FileName] ++ [Index]),
|
||||||
case file:read_file_info(IndexFileName) of
|
case file:read_file_info(IndexFileName) of
|
||||||
{error, _Error} -> serve_index(FileName, T, DefaultContentType, ContentTypes);
|
{error, _Error} -> serve_index(FileName, T, CH, DefaultContentType, ContentTypes);
|
||||||
{ok, #file_info{type = directory}} -> serve_index(FileName, T, DefaultContentType, ContentTypes);
|
{ok, #file_info{type = directory}} -> serve_index(FileName, T, CH, DefaultContentType, ContentTypes);
|
||||||
{ok, FileInfo} -> serve_file(FileInfo, IndexFileName, DefaultContentType, ContentTypes)
|
{ok, FileInfo} -> serve_file(FileInfo, IndexFileName, CH, DefaultContentType, ContentTypes)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Assume the file exists if we got this far and attempt to read it in
|
%% Assume the file exists if we got this far and attempt to read it in
|
||||||
%% and serve it up.
|
%% and serve it up.
|
||||||
serve_file(FileInfo, FileName, DefaultContentType, ContentTypes) ->
|
serve_file(FileInfo, FileName, CustomHeaders, DefaultContentType, ContentTypes) ->
|
||||||
?DEBUG("Delivering: ~s", [FileName]),
|
?DEBUG("Delivering: ~s", [FileName]),
|
||||||
{ok, FileContents} = file:read_file(FileName),
|
{ok, FileContents} = file:read_file(FileName),
|
||||||
ContentType = content_type(FileName, DefaultContentType, ContentTypes),
|
ContentType = content_type(FileName, DefaultContentType, ContentTypes),
|
||||||
{FileInfo#file_info.size,
|
{FileInfo#file_info.size,
|
||||||
200, [{"Server", "ejabberd"},
|
200, [{"Server", "ejabberd"},
|
||||||
{"Last-Modified", last_modified(FileInfo)},
|
{"Last-Modified", last_modified(FileInfo)},
|
||||||
{"Content-Type", ContentType}],
|
{"Content-Type", ContentType} | CustomHeaders],
|
||||||
FileContents}.
|
FileContents}.
|
||||||
|
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue