📄 httpd_conf.erl
字号:
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(httpd_conf).%% EWSAPI -export([is_directory/1, is_file/1, make_integer/1, clean/1, custom_clean/3, check_enum/2]).%% Application internal API-export([load/1, load/2, load_mime_types/1, store/1, store/2, remove/1, remove_all/1, config/1]).-define(VMODULE,"CONF").-include("httpd.hrl").%%%=========================================================================%%% EWSAPI%%%=========================================================================%%-------------------------------------------------------------------------%% is_directory(FilePath) -> Result%% FilePath = string()%% Result = {ok,Directory} | {error,Reason}%% Directory = string()%% Reason = string() | enoent | eaccess | enotdir | FileInfo%% FileInfo = File info record%%%% Description: Checks if FilePath is a directory in which case it is%% returned. %%-------------------------------------------------------------------------is_directory(Directory) -> case file:read_file_info(Directory) of {ok,FileInfo} -> #file_info{type = Type, access = Access} = FileInfo, is_directory(Type,Access,FileInfo,Directory); {error,Reason} -> {error,Reason} end.is_directory(directory,read,_FileInfo,Directory) -> {ok,Directory};is_directory(directory,read_write,_FileInfo,Directory) -> {ok,Directory};is_directory(_Type,_Access,FileInfo,_Directory) -> {error,FileInfo}.%%-------------------------------------------------------------------------%% is_file(FilePath) -> Result%% FilePath = string()%% Result = {ok,File} | {error,Reason}%% File = string()%% Reason = string() | enoent | eaccess | enotdir | FileInfo%% FileInfo = File info record%%%% Description: Checks if FilePath is a regular file in which case it%% is returned.%%-------------------------------------------------------------------------is_file(File) -> case file:read_file_info(File) of {ok,FileInfo} -> #file_info{type = Type, access = Access} = FileInfo, is_file(Type,Access,FileInfo,File); {error,Reason} -> {error,Reason} end.is_file(regular,read,_FileInfo,File) -> {ok,File};is_file(regular,read_write,_FileInfo,File) -> {ok,File};is_file(_Type,_Access,FileInfo,_File) -> {error,FileInfo}.%%-------------------------------------------------------------------------%% make_integer(String) -> Result%% String = string()%% Result = {ok,integer()} | {error,nomatch}%%%% Description: make_integer/1 returns an integer representation of String. %%-------------------------------------------------------------------------make_integer(String) -> case regexp:match(clean(String),"[0-9]+") of {match, _, _} -> {ok, list_to_integer(clean(String))}; nomatch -> {error, nomatch} end.%%-------------------------------------------------------------------------%% clean(String) -> Stripped%% String = Stripped = string()%%%% Description:clean/1 removes leading and/or trailing white spaces%% from String.%%-------------------------------------------------------------------------clean(String) -> {ok,CleanedString,_} = regexp:gsub(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$",""), CleanedString.%%-------------------------------------------------------------------------%% custom_clean(String,Before,After) -> Stripped%% Before = After = regexp()%% String = Stripped = string()%%%% Description: custom_clean/3 removes leading and/or trailing white%% spaces and custom characters from String. %%-------------------------------------------------------------------------custom_clean(String,MoreBefore,MoreAfter) -> {ok,CleanedString,_} = regexp:gsub(String,"^[ \t\n\r\f"++MoreBefore++ "]*|[ \t\n\r\f"++MoreAfter++"]*\$",""), CleanedString.%%-------------------------------------------------------------------------%% check_enum(EnumString,ValidEnumStrings) -> Result%% EnumString = string()%% ValidEnumStrings = [string()]%% Result = {ok,atom()} | {error,not_valid}%%%% Description: check_enum/2 checks if EnumString is a valid%% enumeration of ValidEnumStrings in which case it is returned as an%% atom.%%-------------------------------------------------------------------------check_enum(_Enum,[]) -> {error, not_valid};check_enum(Enum,[Enum|_Rest]) -> {ok, list_to_atom(Enum)};check_enum(Enum, [_NotValid|Rest]) -> check_enum(Enum, Rest).%%%=========================================================================%%% Application internal API%%%=========================================================================%% The configuration data is handled in three (3) phases:%% 1. Parse the config file and put all directives into a key-vale%% tuple list (load/1). %% 2. Traverse the key-value tuple list store it into an ETS table.%% Directives depending on other directives are taken care of here%% (store/1).%% 3. Traverse the ETS table and do a complete clean-up (remove/1).%% Phase 1: Loadload(ConfigFile) -> case read_config_file(ConfigFile) of {ok, Config} -> case bootstrap(Config) of {error, Reason} -> {error, Reason}; {ok, Modules} -> load_config(Config, lists:append(Modules, [?MODULE])) end; {error, Reason} -> {error, ?NICE("Error while reading config file: "++Reason)} end.load(eof, []) -> eof;load("MaxHeaderSize " ++ MaxHeaderSize, []) -> case make_integer(MaxHeaderSize) of {ok, Integer} -> {ok, [], {max_header_size,Integer}}; {error, _} -> {error, ?NICE(clean(MaxHeaderSize)++ " is an invalid number of MaxHeaderSize")} end;load("MaxHeaderAction " ++ Action, []) -> {ok, [], {max_header_action,list_to_atom(clean(Action))}};load("MaxBodySize " ++ MaxBodySize, []) -> case make_integer(MaxBodySize) of {ok, Integer} -> {ok, [], {max_body_size,Integer}}; {error, _} -> {error, ?NICE(clean(MaxBodySize)++ " is an invalid number of MaxBodySize")} end;load("MaxBodyAction " ++ Action, []) -> {ok, [], {max_body_action,list_to_atom(clean(Action))}};load("ServerName " ++ ServerName, []) -> {ok,[],{server_name,clean(ServerName)}};load("SocketType " ++ SocketType, []) -> case check_enum(clean(SocketType),["ssl","ip_comm"]) of {ok, ValidSocketType} -> {ok, [], {com_type,ValidSocketType}}; {error,_} -> {error, ?NICE(clean(SocketType) ++ " is an invalid SocketType")} end;load("Port " ++ Port, []) -> case make_integer(Port) of {ok, Integer} -> {ok, [], {port,Integer}}; {error, _} -> {error, ?NICE(clean(Port)++" is an invalid Port")} end;load("BindAddress " ++ Address, []) -> %% If an ipv6 address is provided in URL-syntax strip the %% url specific part e.i. "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]" %% -> "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210" NewAddress = string:strip(string:strip(clean(Address), left, $[), right, $]), case NewAddress of "*" -> {ok, [], {bind_address,any}}; CAddress -> case (catch inet:getaddr(CAddress,inet6)) of {ok, {0, 0, 0, 0, 0, 16#ffff, _, _}} -> case inet:getaddr(CAddress, inet) of {ok, IPAddr} -> {ok, [], {bind_address,IPAddr}}; {error, _} -> {error, ?NICE(CAddress++" is an invalid address")} end; {ok, IPAddr} -> {ok, [], {bind_address, IPAddr}}; _ -> case inet:getaddr(CAddress, inet) of {ok, IPAddr} -> {ok, [], {bind_address,IPAddr}}; {error, _} -> {error, ?NICE(CAddress++" is an invalid address")} end end end;load("KeepAlive " ++ OnorOff, []) -> case list_to_atom(clean(OnorOff)) of off -> {ok, [], {persistent_conn, false}}; _ -> {ok, [], {persistent_conn, true}} end;load("MaxKeepAliveRequests " ++ MaxRequests, []) -> case make_integer(MaxRequests) of {ok, Integer} -> {ok, [], {max_keep_alive_request, Integer}}; {error, _} -> {error, ?NICE(clean(MaxRequests) ++ " is an invalid MaxKeepAliveRequests")} end;%% This clause is keept for backwards compability load("MaxKeepAliveRequest " ++ MaxRequests, []) -> case make_integer(MaxRequests) of {ok, Integer} -> {ok, [], {max_keep_alive_request, Integer}}; {error, _} -> {error, ?NICE(clean(MaxRequests) ++ " is an invalid MaxKeepAliveRequest")} end;load("KeepAliveTimeout " ++ Timeout, []) -> case make_integer(Timeout) of {ok, Integer} -> {ok, [], {keep_alive_timeout, Integer*1000}}; {error, _} -> {error, ?NICE(clean(Timeout)++" is an invalid KeepAliveTimeout")} end;load("Modules " ++ Modules, []) -> {ok, ModuleList} = regexp:split(Modules," "), {ok, [], {modules,[list_to_atom(X) || X <- ModuleList]}};load("ServerAdmin " ++ ServerAdmin, []) -> {ok, [], {server_admin,clean(ServerAdmin)}};load("ServerRoot " ++ ServerRoot, []) -> case is_directory(clean(ServerRoot)) of {ok, Directory} -> MimeTypesFile = filename:join([clean(ServerRoot),"conf", "mime.types"]), case load_mime_types(MimeTypesFile) of {ok, MimeTypesList} -> {ok, [], [{server_root,string:strip(Directory,right,$/)}, {mime_types,MimeTypesList}]}; {error, Reason} -> {error, Reason} end; {error, _} -> {error, ?NICE(clean(ServerRoot)++" is an invalid ServerRoot")} end;load("MaxClients " ++ MaxClients, []) -> case make_integer(MaxClients) of {ok, Integer} -> {ok, [], {max_clients,Integer}}; {error, _} -> {error, ?NICE(clean(MaxClients) ++ " is an invalid number of MaxClients")} end;load("DocumentRoot " ++ DocumentRoot,[]) -> case is_directory(clean(DocumentRoot)) of {ok, Directory} -> {ok, [], {document_root,string:strip(Directory,right,$/)}}; {error, _} -> {error, ?NICE(clean(DocumentRoot)++"is an invalid DocumentRoot")} end;load("DefaultType " ++ DefaultType, []) -> {ok, [], {default_type,clean(DefaultType)}};load("SSLCertificateFile " ++ SSLCertificateFile, []) -> case is_file(clean(SSLCertificateFile)) of {ok, File} -> {ok, [], {ssl_certificate_file,File}}; {error, _} -> {error, ?NICE(clean(SSLCertificateFile)++ " is an invalid SSLCertificateFile")} end;load("SSLCertificateKeyFile " ++ SSLCertificateKeyFile, []) -> case is_file(clean(SSLCertificateKeyFile)) of {ok, File} -> {ok, [], {ssl_certificate_key_file,File}}; {error, _} -> {error, ?NICE(clean(SSLCertificateKeyFile)++ " is an invalid SSLCertificateKeyFile")} end;load("SSLVerifyClient " ++ SSLVerifyClient, []) -> case make_integer(clean(SSLVerifyClient)) of {ok, Integer} when Integer >=0,Integer =< 2 -> {ok, [], {ssl_verify_client,Integer}}; {ok, _Integer} -> {error,?NICE(clean(SSLVerifyClient) ++ " is an invalid SSLVerifyClient")}; {error, nomatch} -> {error,?NICE(clean(SSLVerifyClient) ++ " is an invalid SSLVerifyClient")} end;load("SSLVerifyDepth " ++ SSLVerifyDepth, []) -> case make_integer(clean(SSLVerifyDepth)) of {ok, Integer} when Integer > 0 -> {ok, [], {ssl_verify_client_depth,Integer}}; {ok, _Integer} -> {error,?NICE(clean(SSLVerifyDepth) ++ " is an invalid SSLVerifyDepth")}; {error, nomatch} -> {error,?NICE(clean(SSLVerifyDepth) ++ " is an invalid SSLVerifyDepth")} end;load("SSLCiphers " ++ SSLCiphers, []) -> {ok, [], {ssl_ciphers, clean(SSLCiphers)}};load("SSLCACertificateFile " ++ SSLCACertificateFile, []) -> case is_file(clean(SSLCACertificateFile)) of {ok, File} -> {ok, [], {ssl_ca_certificate_file,File}}; {error, _} -> {error, ?NICE(clean(SSLCACertificateFile)++ " is an invalid SSLCACertificateFile")} end;load("SSLPasswordCallbackModule " ++ SSLPasswordCallbackModule, []) -> {ok, [], {ssl_password_callback_module, list_to_atom(clean(SSLPasswordCallbackModule))}};load("SSLPasswordCallbackFunction " ++ SSLPasswordCallbackFunction, []) -> {ok, [], {ssl_password_callback_function, list_to_atom(clean(SSLPasswordCallbackFunction))}};load("DisableChunkedTransferEncodingSend " ++ TrueOrFalse, []) -> case list_to_atom(clean(TrueOrFalse)) of true -> {ok, [], {disable_chunked_transfer_encoding_send, true}}; _ -> {ok, [], {disable_chunked_transfer_encoding_send, false}} end.%%
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -