From 1716b090f9a1aa9fff80e5f024c7ae29036444c8 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 23 Nov 2009 12:00:46 +0000 Subject: [PATCH] Option to define custom HTTP headers in mod_http_fileserver (EJAB-612) SVN Revision: 2747 --- doc/guide.html | 6 ++++++ doc/guide.tex | 6 ++++++ src/web/mod_http_fileserver.erl | 27 ++++++++++++++++----------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 7bd7457e7..0b647aae9 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2155,6 +2155,9 @@ Directory to serve the files.
{accesslog, Path}
File to log accesses using an Apache-like format. No log will be recorded if this option is not specified. +
{custom_headers, [ {Name, Value}, ...]}
+Indicate custom HTTP headers to be included in all responses. +Default value is: []
{directory_indices, [Index, ...]}
Indicate one or more directory index files, similarly to Apache’s DirectoryIndex variable. When a web request hits a directory @@ -2184,6 +2187,9 @@ To use this module you must enable it: {".png", "image/png"}, {".jpg", undefined} ]}, + {custom_headers, [{"X-Powered-By", "Erlang/OTP"}, + {"X-Fry", "It's a widely-believed fact!"} + ]}, {default_content_type, "text/html"} ] }, diff --git a/doc/guide.tex b/doc/guide.tex index 6a967ae2c..7e8143a75 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -2849,6 +2849,9 @@ Options: \titem{\{accesslog, Path\}} \ind{options!accesslog} File to log accesses using an Apache-like format. 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} Indicate one or more directory index files, similarly to Apache's DirectoryIndex variable. When a web request hits a directory @@ -2886,6 +2889,9 @@ To use this module you must enable it: {".png", "image/png"}, {".jpg", undefined} ]}, + {custom_headers, [{"X-Powered-By", "Erlang/OTP"}, + {"X-Fry", "It's a widely-believed fact!"} + ]}, {default_content_type, "text/html"} ] }, diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index 36679bc2e..0b0f62f05 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -73,7 +73,7 @@ -endif. -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). @@ -141,12 +141,13 @@ start_link(Host, Opts) -> init([Host, Opts]) -> try initialize(Host, Opts) of {DocRoot, AccessLog, AccessLogFD, DirectoryIndices, - DefaultContentType, ContentTypes} -> + CustomHeaders, DefaultContentType, ContentTypes} -> {ok, #state{host = Host, accesslog = AccessLog, accesslogfd = AccessLogFD, docroot = DocRoot, directory_indices = DirectoryIndices, + custom_headers = CustomHeaders, default_content_type = DefaultContentType, content_types = ContentTypes}} catch @@ -163,12 +164,13 @@ initialize(Host, Opts) -> AccessLog = gen_mod:get_opt(accesslog, Opts, undefined), AccessLogFD = try_open_log(AccessLog, Host), 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, ?DEFAULT_CONTENT_TYPE), ContentTypes = build_list_content_types(gen_mod:get_opt(content_types, Opts, []), ?DEFAULT_CONTENT_TYPES), ?INFO_MSG("initialize: ~n ~p", [ContentTypes]),%+++ {DocRoot, AccessLog, AccessLogFD, DirectoryIndices, - DefaultContentType, ContentTypes}. + CustomHeaders, DefaultContentType, ContentTypes}. %% @spec (AdminCTs::[CT], Default::[CT]) -> [CT] %% where CT = {Extension::string(), Value} @@ -231,6 +233,7 @@ try_open_log(FN, Host) -> %%-------------------------------------------------------------------- handle_call({serve, LocalPath}, _From, State) -> Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices, + State#state.custom_headers, State#state.default_content_type, State#state.content_types), {reply, Reply, State}; handle_call(_Request, _From, State) -> @@ -298,42 +301,44 @@ process(LocalPath, Request) -> ejabberd_web:error(not_found) end. -serve(LocalPath, DocRoot, DirectoryIndices, DefaultContentType, ContentTypes) -> +serve(LocalPath, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType, ContentTypes) -> FileName = filename:join(filename:split(DocRoot) ++ LocalPath), case file:read_file_info(FileName) of {error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND; {error, eacces} -> ?HTTP_ERR_FORBIDDEN; {ok, #file_info{type = directory}} -> serve_index(FileName, DirectoryIndices, + CustomHeaders, DefaultContentType, ContentTypes); {ok, FileInfo} -> serve_file(FileInfo, FileName, + CustomHeaders, DefaultContentType, ContentTypes) end. %% Troll through the directory indices attempting to find one which %% 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; -serve_index(FileName, [Index | T], DefaultContentType, ContentTypes) -> +serve_index(FileName, [Index | T], CH, DefaultContentType, ContentTypes) -> IndexFileName = filename:join([FileName] ++ [Index]), case file:read_file_info(IndexFileName) of - {error, _Error} -> serve_index(FileName, T, DefaultContentType, ContentTypes); - {ok, #file_info{type = directory}} -> serve_index(FileName, T, DefaultContentType, ContentTypes); - {ok, FileInfo} -> serve_file(FileInfo, IndexFileName, DefaultContentType, ContentTypes) + {error, _Error} -> serve_index(FileName, T, CH, DefaultContentType, ContentTypes); + {ok, #file_info{type = directory}} -> serve_index(FileName, T, CH, DefaultContentType, ContentTypes); + {ok, FileInfo} -> serve_file(FileInfo, IndexFileName, CH, DefaultContentType, ContentTypes) end. %% Assume the file exists if we got this far and attempt to read it in %% and serve it up. -serve_file(FileInfo, FileName, DefaultContentType, ContentTypes) -> +serve_file(FileInfo, FileName, CustomHeaders, DefaultContentType, ContentTypes) -> ?DEBUG("Delivering: ~s", [FileName]), {ok, FileContents} = file:read_file(FileName), ContentType = content_type(FileName, DefaultContentType, ContentTypes), {FileInfo#file_info.size, 200, [{"Server", "ejabberd"}, {"Last-Modified", last_modified(FileInfo)}, - {"Content-Type", ContentType}], + {"Content-Type", ContentType} | CustomHeaders], FileContents}. %%----------------------------------------------------------------------