1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%% 21-module(httpd_conf). 22 23%% Application internal API 24-export([load_mime_types/1, store/1, store/2, 25 remove/1, remove_all/1, get_config/3, get_config/4, 26 lookup_socket_type/1, 27 lookup/2, lookup/3, lookup/4, 28 validate_properties/1, white_space_clean/1]). 29 30-define(VMODULE,"CONF"). 31-include("httpd_internal.hrl"). 32-include("httpd.hrl"). 33-include_lib("inets/src/http_lib/http_internal.hrl"). 34 35%% Removed functions 36 37-removed([{check_enum,2,"use lists:member/2 instead"}, 38 {clean,1,"use sting:strip/1 instead or possibly the re module"}, 39 {custom_clean,3,"use sting:strip/1 instead or possibly the re module"}, 40 {is_directory,1,"use filelib:is_dir/1 instead"}, 41 {is_file,1,"use filelib:is_file/1 instead"}, 42 {make_integer,1,"use erlang:list_to_integer/1 instead"}]). 43 44%%%========================================================================= 45%%% Application internal API 46%%%========================================================================= 47%% The configuration data is handled in three (2) phases: 48%% 1. Traverse the key-value tuple list store it into an ETS table. 49%% Directives depending on other directives are taken care of here 50%% (store/1). 51%% 3. Traverse the ETS table and do a complete clean-up (remove/1). 52 53validate_ipfamily(inet) -> 54 inet; 55validate_ipfamily(inet6) -> 56 inet6; 57%% Backwards compatibility wrapper, 58%% fallback to the default, IPV4, 59%% as it will most proably work. 60%% IPv6 standard moved away from 61%% beeing able to fallback to ipv4 62validate_ipfamily(inet6fb4) -> 63 inet; 64validate_ipfamily(IpFamilyStr) -> 65 throw({error, {bad_ipfamily, IpFamilyStr}}). 66 67%% 68%% load_mime_types/1 -> {ok, MimeTypes} | {error, Reason} 69%% 70load_mime_types(MimeTypesFile) -> 71 case file:open(MimeTypesFile, [read]) of 72 {ok, Stream} -> 73 parse_mime_types(Stream, []); 74 {error, _} -> 75 {error, ?NICE("Can't open " ++ MimeTypesFile)} 76 end. 77 78 79validate_properties(Properties) -> 80 %% First, check that all mandatory properties are present 81 case mandatory_properties(Properties) of 82 ok -> 83 %% Second, check that property dependency are ok 84 {ok, check_minimum_bytes_per_second(validate_properties2(Properties))}; 85 Error -> 86 throw(Error) 87 end. 88 89%% This function is used to validate inter-property dependencies. 90%% That is, if property A depends on property B. 91%% The only sunch preperty at this time is bind_address that depends 92%% on ipfamily. 93validate_properties2(Properties0) -> 94 Properties = fix_ipfamily(Properties0), 95 case proplists:get_value(bind_address, Properties) of 96 undefined -> 97 case proplists:get_value(sock_type, Properties, ip_comm) of 98 ip_comm -> 99 add_inet_defaults(Properties); 100 {ip_comm, _} -> 101 add_inet_defaults(Properties); 102 _ -> 103 [{bind_address, any} | Properties] 104 end; 105 any -> 106 Properties; 107 Address0 -> 108 IpFamily = proplists:get_value(ipfamily, Properties, inet), 109 case httpd_util:ip_address(Address0, IpFamily) of 110 {ok, Address} -> 111 Properties1 = proplists:delete(bind_address, Properties), 112 [{bind_address, Address} | Properties1]; 113 {error, Reason} -> 114 Error = {error, 115 {failed_determine_ip_address, 116 Address0, IpFamily, Reason}}, 117 throw(Error) 118 end 119 end. 120 121fix_ipfamily(Properties) -> 122 case proplists:get_value(ipfamily, Properties) of 123 undefined -> 124 Properties; 125 IpFamily -> 126 NewProps = proplists:delete(ipfamily, Properties), 127 [{ipfamily, validate_ipfamily(IpFamily)} | NewProps] 128 end. 129 130add_inet_defaults(Properties) -> 131 case proplists:get_value(ipfamily, Properties) of 132 undefined -> 133 [{bind_address, any}, 134 {ipfamily, inet} | Properties]; 135 _ -> 136 [{bind_address, any} | Properties] 137 end. 138 139check_minimum_bytes_per_second(Properties) -> 140 case proplists:get_value(minimum_bytes_per_second, Properties, false) of 141 false -> 142 Properties; 143 Nr -> 144 case is_integer(Nr) of 145 false -> 146 throw({error, {minimum_bytes_per_second, is_not_integer}}); 147 _ -> 148 Properties 149 end 150 end. 151mandatory_properties(ConfigList) -> 152 a_must(ConfigList, [server_name, port, server_root, document_root]). 153 154a_must(_ConfigList, []) -> 155 ok; 156a_must(ConfigList, [Prop | Rest]) -> 157 case proplists:get_value(Prop, ConfigList) of 158 undefined -> 159 {error, {missing_property, Prop}}; 160 _ -> 161 a_must(ConfigList, Rest) 162 end. 163 164 165validate_config_params([]) -> 166 ok; 167validate_config_params([{max_header_size, Value} | Rest]) 168 when is_integer(Value) andalso (Value > 0) -> 169 validate_config_params(Rest); 170validate_config_params([{max_header_size, Value} | _]) -> 171 throw({max_header_size, Value}); 172 173validate_config_params([{max_body_size, Value} | Rest]) 174 when is_integer(Value) andalso (Value > 0) -> 175 validate_config_params(Rest); 176validate_config_params([{max_body_size, Value} | _]) -> 177 throw({max_body_size, Value}); 178 179validate_config_params([{max_content_length, Value} | Rest]) 180 when is_integer(Value) andalso (Value > 0) -> 181 validate_config_params(Rest); 182validate_config_params([{max_content_length, Value} | _]) -> 183 throw({max_content_length, Value}); 184 185validate_config_params([{server_name, Value} | Rest]) 186 when is_list(Value) -> 187 validate_config_params(Rest); 188validate_config_params([{server_name, Value} | _]) -> 189 throw({server_name, Value}); 190 191validate_config_params([{server_tokens, Value} | Rest]) 192 when is_atom(Value) -> 193 case lists:member(Value, plain_server_tokens()) of 194 true -> 195 validate_config_params(Rest); 196 false -> 197 throw({server_tokens, Value}) 198 end; 199validate_config_params([{server_tokens, {private, Value}} | Rest]) 200 when is_list(Value) -> 201 validate_config_params(Rest); 202validate_config_params([{server_tokens, Value} | _]) -> 203 throw({server_tokens, Value}); 204 205validate_config_params([{socket_type, ip_comm} | Rest]) -> 206 validate_config_params(Rest); 207 208validate_config_params([{socket_type, {Value, Opts}} | Rest]) when Value == ip_comm; 209 Value == ssl; 210 Value == essl -> 211 %% Make sure not to set socket values used internaly 212 validate_config_params(Opts), 213 validate_config_params(Rest); 214 215validate_config_params([{socket_type, Value} | _]) -> 216 throw({socket_type, Value}); 217 218validate_config_params([{port, Value} | Rest]) 219 when is_integer(Value) andalso (Value >= 0) -> 220 validate_config_params(Rest); 221validate_config_params([{port, Value} | _]) -> 222 throw({port, Value}); 223 224validate_config_params([{bind_address, Value} | Rest]) -> 225 case is_bind_address(Value) of 226 true -> 227 validate_config_params(Rest); 228 false -> 229 throw({bind_address, Value}) 230 end; 231 232validate_config_params([{ipfamily, Value} | Rest]) 233 when ((Value =:= inet) orelse 234 (Value =:= inet6) orelse 235 (Value =:= inet6fb4)) -> 236 validate_config_params(Rest); 237validate_config_params([{ipfamily, Value} | _]) -> 238 throw({ipfamily, Value}); 239 240validate_config_params([{keep_alive, Value} | Rest]) 241 when (Value =:= true) orelse (Value =:= false) -> 242 validate_config_params(Rest); 243validate_config_params([{keep_alive, Value} | _]) -> 244 throw({keep_alive, Value}); 245 246validate_config_params([{max_keep_alive_request, Value} | Rest]) 247 when is_integer(Value) andalso (Value > 0) -> 248 validate_config_params(Rest); 249validate_config_params([{max_keep_alive_request, Value} | _]) -> 250 throw({max_keep_alive_request, Value}); 251 252validate_config_params([{keep_alive_timeout, Value} | Rest]) 253 when is_integer(Value) andalso (Value >= 0) -> 254 validate_config_params(Rest); 255validate_config_params([{keep_alive_timeout, Value} | _]) -> 256 throw({keep_alive_timeout, Value}); 257 258validate_config_params([{modules, Value} | Rest]) -> 259 ok = httpd_util:modules_validate(Value), 260 validate_config_params(Rest); 261 262validate_config_params([{server_admin, Value} | Rest]) when is_list(Value) -> 263 validate_config_params(Rest); 264validate_config_params([{server_admin, Value} | _]) -> 265 throw({server_admin, Value}); 266 267validate_config_params([{server_root, Value} | Rest]) -> 268 ok = httpd_util:dir_validate(server_root, Value), 269 validate_config_params(Rest); 270 271validate_config_params([{mime_types, Value} | Rest]) -> 272 ok = httpd_util:mime_types_validate(Value), 273 validate_config_params(Rest); 274 275validate_config_params([{max_clients, Value} | Rest]) 276 when is_integer(Value) andalso (Value > 0) -> 277 validate_config_params(Rest); 278validate_config_params([{max_clients, Value} | _]) -> 279 throw({max_clients, Value}); 280 281validate_config_params([{document_root, Value} | Rest]) -> 282 ok = httpd_util:dir_validate(document_root, Value), 283 validate_config_params(Rest); 284 285validate_config_params([{default_type, Value} | Rest]) when is_list(Value) -> 286 validate_config_params(Rest); 287validate_config_params([{default_type, Value} | _]) -> 288 throw({default_type, Value}); 289 290validate_config_params([{logger, Value} | Rest]) when is_list(Value) -> 291 true = validate_logger(Value), 292 validate_config_params(Rest); 293validate_config_params([{logger, Value} | _]) -> 294 throw({logger, Value}); 295 296validate_config_params([{ssl_certificate_file = Key, Value} | Rest]) -> 297 ok = httpd_util:file_validate(Key, Value), 298 validate_config_params(Rest); 299 300validate_config_params([{ssl_certificate_key_file = Key, Value} | Rest]) -> 301 ok = httpd_util:file_validate(Key, Value), 302 validate_config_params(Rest); 303 304validate_config_params([{ssl_verify_client, Value} | Rest]) 305 when (Value =:= 0) orelse (Value =:= 1) orelse (Value =:= 2) -> 306 validate_config_params(Rest); 307 308validate_config_params([{ssl_verify_client_depth, Value} | Rest]) 309 when is_integer(Value) andalso (Value >= 0) -> 310 validate_config_params(Rest); 311validate_config_params([{ssl_verify_client_depth, Value} | _]) -> 312 throw({ssl_verify_client_depth, Value}); 313 314validate_config_params([{ssl_ciphers, Value} | Rest]) when is_list(Value) -> 315 validate_config_params(Rest); 316validate_config_params([{ssl_ciphers, Value} | _]) -> 317 throw({ssl_ciphers, Value}); 318 319validate_config_params([{ssl_ca_certificate_file = Key, Value} | Rest]) -> 320 ok = httpd_util:file_validate(Key, Value), 321 validate_config_params(Rest); 322 323validate_config_params([{ssl_password_callback_module, Value} | Rest]) 324 when is_atom(Value) -> 325 validate_config_params(Rest); 326validate_config_params([{ssl_password_callback_module, Value} | _]) -> 327 throw({ssl_password_callback_module, Value}); 328 329validate_config_params([{ssl_password_callback_function, Value} | Rest]) 330 when is_atom(Value) -> 331 validate_config_params(Rest); 332validate_config_params([{ssl_password_callback_function, Value} | _]) -> 333 throw({ssl_password_callback_function, Value}); 334 335validate_config_params([{ssl_password_callback_arguments, Value} | Rest]) 336 when is_list(Value) -> 337 validate_config_params(Rest); 338validate_config_params([{ssl_password_callback_arguments, Value} | _]) -> 339 throw({ssl_password_callback_arguments, Value}); 340 341validate_config_params([{disable_chunked_transfer_encoding_send, Value} | 342 Rest]) 343 when (Value =:= true) orelse (Value =:= false) -> 344 validate_config_params(Rest); 345validate_config_params([{disable_chunked_transfer_encoding_send, Value} | 346 _ ]) -> 347 throw({disable_chunked_transfer_encoding_send, Value}); 348validate_config_params([{Name, _} = Opt | _]) when Name == packet; 349 Name == mode; 350 Name == active; 351 Name == reuseaddr -> 352 throw({internaly_handled_opt_can_not_be_set, Opt}); 353validate_config_params([_| Rest]) -> 354 validate_config_params(Rest). 355 356is_bind_address(any) -> 357 true; 358is_bind_address(Value) -> 359 case is_bind_address(Value, inet) of 360 false -> 361 is_bind_address(Value, inet6); 362 True -> 363 True 364 end. 365 366is_bind_address(Value, IpFamily) -> 367 case httpd_util:ip_address(Value, IpFamily) of 368 {ok, _} -> 369 true; 370 _ -> 371 false 372 end. 373 374store(ConfigList0) -> 375 try validate_config_params(ConfigList0) of 376 ok -> 377 Modules = 378 proplists:get_value(modules, ConfigList0, ?DEFAULT_MODS), 379 Port = proplists:get_value(port, ConfigList0), 380 Addr = proplists:get_value(bind_address, ConfigList0, any), 381 Profile = proplists:get_value(profile, ConfigList0, default), 382 ConfigList = fix_mime_types(ConfigList0), 383 Name = httpd_util:make_name("httpd_conf", Addr, Port, Profile), 384 ConfigDB = ets:new(Name, [named_table, bag, protected]), 385 store(ConfigDB, ConfigList, 386 lists:append(Modules, [?MODULE]), 387 ConfigList) 388 catch 389 throw:Error -> 390 {error, {invalid_option, Error}} 391 end. 392 393fix_mime_types(ConfigList0) -> 394 case proplists:get_value(mime_types, ConfigList0) of 395 undefined -> 396 ServerRoot = proplists:get_value(server_root, ConfigList0), 397 MimeTypesFile = 398 filename:join([ServerRoot,"conf", "mime.types"]), 399 case filelib:is_file(MimeTypesFile) of 400 true -> 401 {ok, MimeTypesList} = load_mime_types(MimeTypesFile), 402 [{mime_types, MimeTypesList} | ConfigList0]; 403 false -> 404 [{mime_types, 405 [{"html","text/html"},{"htm","text/html"}]} 406 | ConfigList0] 407 end; 408 MimeTypes -> 409 case filelib:is_file(MimeTypes) of 410 true -> 411 {ok, MimeTypesList} = load_mime_types(MimeTypes), 412 ConfigList = proplists:delete(mime_types, ConfigList0), 413 [{mime_types, MimeTypesList} | ConfigList]; 414 false -> 415 ConfigList0 416 end 417 end. 418 419store({mime_types,MimeTypesList},ConfigList) -> 420 Port = proplists:get_value(port, ConfigList), 421 Addr = proplists:get_value(bind_address, ConfigList), 422 Name = httpd_util:make_name("httpd_mime",Addr,Port), 423 {ok, MimeTypesDB} = store_mime_types(Name,MimeTypesList), 424 {ok, {mime_types,MimeTypesDB}}; 425store({log_format, LogFormat}, _ConfigList) 426 when (LogFormat =:= common) orelse (LogFormat =:= combined) -> 427 {ok,{log_format, LogFormat}}; 428store({log_format, LogFormat}, _ConfigList) 429 when (LogFormat =:= compact) orelse (LogFormat =:= pretty) -> 430 {ok, {log_format, LogFormat}}; 431store({server_tokens, ServerTokens} = Entry, _ConfigList) -> 432 Server = server(ServerTokens), 433 {ok, [Entry, {server, Server}]}; 434store({keep_alive_timeout, KeepAliveTimeout}, _ConfigList) -> 435 {ok, {keep_alive_timeout, KeepAliveTimeout}}; 436store(ConfigListEntry, _ConfigList) -> 437 {ok, ConfigListEntry}. 438 439 440%% The SERVER_SOFTWARE macro has the following structure: 441%% <product>/<version> 442%% Example: "inets/1.2.3" 443%% So, with this example (on a linux machine, with OTP R15B), 444%% this will result in: 445%% prod: "inets" 446%% major: "inets/1" 447%% minor: "inets/1.2" 448%% minimal: "inets/1.2.3" 449%% os: "inets/1.2.3 (unix) 450%% full: "inets/1.2.3 (unix/linux) OTP/R15B" 451%% Note that the format of SERVER_SOFTWARE is that of 'minimal'. 452%% Also, there will always be atleast two digits in a version: 453%% Not just 1 but 1.0 454%% 455%% We have already checked that the value is valid, 456%% so there is no need to check enything here. 457%% 458server(prod = _ServerTokens) -> 459 [Prod|_Version] = string:tokens(?SERVER_SOFTWARE, [$/]), 460 Prod; 461server(major = _ServerTokens) -> 462 [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]), 463 [Major|_] = string:tokens(Version, [$.]), 464 Prod ++ "/" ++ Major; 465server(minor = _ServerTokens) -> 466 [Prod|Version] = string:tokens(?SERVER_SOFTWARE, [$/]), 467 [Major,Minor|_] = string:tokens(Version, [$.]), 468 Prod ++ "/" ++ Major ++ "." ++ Minor; 469server(minimal = _ServerTokens) -> 470 %% This is the default 471 ?SERVER_SOFTWARE; 472server(os = _ServerTokens) -> 473 OS = os_info(partial), 474 lists:flatten(io_lib:format("~s ~s", [?SERVER_SOFTWARE, OS])); 475server(full = _ServerTokens) -> 476 OTPRelease = otp_release(), 477 OS = os_info(full), 478 lists:flatten( 479 io_lib:format("~s ~s OTP/~s", [?SERVER_SOFTWARE, OS, OTPRelease])); 480server(none = _ServerTokens) -> 481 ""; 482server({private, Server} = _ServerTokens) when is_list(Server) -> 483 %% The user provide its own 484 Server; 485server(_) -> 486 ?SERVER_SOFTWARE. 487 488os_info(Info) -> 489 case os:type() of 490 {OsFamily, _OsName} when Info =:= partial -> 491 lists:flatten(io_lib:format("(~w)", [OsFamily])); 492 {OsFamily, OsName} -> 493 lists:flatten(io_lib:format("(~w/~w)", [OsFamily, OsName])) 494 end. 495 496otp_release() -> 497 erlang:system_info(otp_release). 498 499 500%% Phase 3: Remove 501remove_all(ConfigDB) -> 502 Modules = httpd_util:lookup(ConfigDB,modules,[]), 503 remove_traverse(ConfigDB, lists:append(Modules,[?MODULE])). 504 505remove(ConfigDB) -> 506 ets:delete(ConfigDB), 507 ok. 508 509 510get_config(Address, Port, Profile) -> 511 Tab = httpd_util:make_name("httpd_conf", Address, Port, Profile), 512 Properties = ets:tab2list(Tab), 513 MimeTab = proplists:get_value(mime_types, Properties), 514 NewProperties = proplists:delete(mime_types, Properties), 515 [{mime_types, ets:tab2list(MimeTab)} | NewProperties]. 516 517get_config(Address, Port, Profile, Properties) -> 518 Tab = httpd_util:make_name("httpd_conf", Address, Port, Profile), 519 Config = 520 lists:map(fun(Prop) -> {Prop, httpd_util:lookup(Tab, Prop)} end, 521 Properties), 522 [{Proporty, Value} || {Proporty, Value} <- Config, Value =/= undefined]. 523 524 525lookup(Tab, Key) -> 526 httpd_util:lookup(Tab, Key). 527 528lookup(Tab, Key, Default) when is_atom(Key) -> 529 httpd_util:lookup(Tab, Key, Default); 530 531lookup(Address, Port, Key) when is_integer(Port) -> 532 Tab = table(Address, Port), 533 lookup(Tab, Key). 534 535lookup(Address, Port, Key, Default) when is_integer(Port) -> 536 Tab = table(Address, Port), 537 lookup(Tab, Key, Default). 538 539table(Address, Port) -> 540 httpd_util:make_name("httpd_conf", Address, Port). 541 542 543lookup_socket_type(ConfigDB) -> 544 case httpd_util:lookup(ConfigDB, socket_type, ip_comm) of 545 ip_comm -> 546 ip_comm; 547 {ip_comm, _} = Type -> 548 Type; 549 {Tag, Conf} -> 550 {Tag, Conf}; 551 SSL when (SSL =:= ssl) orelse (SSL =:= essl) -> 552 SSLTag = 553 if 554 (SSL =:= ssl) -> 555 ?HTTP_DEFAULT_SSL_KIND; 556 true -> 557 SSL 558 end, 559 case ssl_certificate_file(ConfigDB) of 560 undefined -> 561 Reason = "Directive SSLCertificateFile " 562 "not found in the config file", 563 throw({error, Reason}); 564 SSLCertificateFile -> 565 {SSLTag, SSLCertificateFile ++ ssl_config(ConfigDB)} 566 end 567 end. 568 569ssl_config(ConfigDB) -> 570 ssl_certificate_key_file(ConfigDB) ++ 571 ssl_verify_client(ConfigDB) ++ 572 ssl_ciphers(ConfigDB) ++ 573 ssl_password(ConfigDB) ++ 574 ssl_verify_depth(ConfigDB) ++ 575 ssl_ca_certificate_file(ConfigDB) ++ 576 ssl_log_level(ConfigDB). 577 578%%%======================================================================== 579%%% Internal functions 580%%%======================================================================== 581parse_mime_types(Stream,MimeTypesList) -> 582 Line= 583 case io:get_line(Stream,'') of 584 eof -> 585 eof; 586 String -> 587 re:replace(white_space_clean(String), "[\t\r\f ]"," ", [{return,list}, global]) 588 end, 589 parse_mime_types(Stream, MimeTypesList, Line). 590parse_mime_types(Stream, MimeTypesList, eof) -> 591 file:close(Stream), 592 {ok, MimeTypesList}; 593parse_mime_types(Stream, MimeTypesList, "") -> 594 parse_mime_types(Stream, MimeTypesList); 595parse_mime_types(Stream, MimeTypesList, [$#|_]) -> 596 parse_mime_types(Stream, MimeTypesList); 597parse_mime_types(Stream, MimeTypesList, Line) -> 598 case re:split(Line, " ", [{return, list}]) of 599 [NewMimeType|Suffixes] -> 600 parse_mime_types(Stream, 601 lists:append(suffixes(NewMimeType,Suffixes), 602 MimeTypesList)); 603 _ -> 604 {error, ?NICE(Line)} 605 end. 606 607suffixes(_MimeType,[]) -> 608 []; 609suffixes(MimeType,[""|Rest]) -> 610 suffixes(MimeType, Rest); 611suffixes(MimeType,[Suffix|Rest]) -> 612 [{Suffix,MimeType}|suffixes(MimeType,Rest)]. 613 614 615%% Phase 2: store 616store(ConfigDB, _ConfigList, _Modules, []) -> 617 {ok, ConfigDB}; 618store(ConfigDB, ConfigList, Modules, [ConfigListEntry|Rest]) -> 619 case store_traverse(ConfigListEntry, ConfigList, Modules) of 620 {ok, ConfigDBEntry} when is_tuple(ConfigDBEntry) -> 621 ets:insert(ConfigDB, ConfigDBEntry), 622 store(ConfigDB, ConfigList, Modules, Rest); 623 {ok, ConfigDBEntry} when is_list(ConfigDBEntry) -> 624 lists:foreach(fun(Entry) -> 625 ets:insert(ConfigDB,Entry) 626 end,ConfigDBEntry), 627 store(ConfigDB, ConfigList, Modules, Rest); 628 {error, Reason} -> 629 {error,Reason} 630 end. 631 632store_traverse(_ConfigListEntry, _ConfigList,[]) -> 633 {error, ?NICE("Unable to store configuration...")}; 634store_traverse(ConfigListEntry, ConfigList, [Module|Rest]) -> 635 case catch apply(Module, store, [ConfigListEntry, ConfigList]) of 636 {'EXIT',{function_clause,_}} -> 637 store_traverse(ConfigListEntry,ConfigList,Rest); 638 {'EXIT',{undef, _}} -> 639 store_traverse(ConfigListEntry,ConfigList,Rest); 640 {'EXIT', Reason} -> 641 error_logger:error_report({'EXIT',Reason}), 642 store_traverse(ConfigListEntry,ConfigList,Rest); 643 Result -> 644 Result 645 end. 646 647store_mime_types(Name,MimeTypesList) -> 648 %% Make sure that the ets table is not duplicated 649 %% when reloading configuration 650 catch ets:delete(Name), 651 MimeTypesDB = ets:new(Name, [named_table, set, protected]), 652 store_mime_types1(MimeTypesDB, MimeTypesList). 653store_mime_types1(MimeTypesDB,[]) -> 654 {ok, MimeTypesDB}; 655store_mime_types1(MimeTypesDB,[Type|Rest]) -> 656 ets:insert(MimeTypesDB, Type), 657 store_mime_types1(MimeTypesDB, Rest). 658 659 660%% Phase 3: remove 661remove_traverse(_ConfigDB,[]) -> 662 ok; 663remove_traverse(ConfigDB,[Module|Rest]) -> 664 case (catch apply(Module,remove,[ConfigDB])) of 665 {'EXIT',{undef,_}} -> 666 remove_traverse(ConfigDB,Rest); 667 {'EXIT',{function_clause,_}} -> 668 remove_traverse(ConfigDB,Rest); 669 {'EXIT',Reason} -> 670 error_logger:error_report({'EXIT',Reason}), 671 remove_traverse(ConfigDB,Rest); 672 {error,Reason} -> 673 error_logger:error_report(Reason), 674 remove_traverse(ConfigDB,Rest); 675 _ -> 676 remove_traverse(ConfigDB,Rest) 677 end. 678 679ssl_certificate_file(ConfigDB) -> 680 case httpd_util:lookup(ConfigDB,ssl_certificate_file) of 681 undefined -> 682 undefined; 683 SSLCertificateFile -> 684 [{certfile,SSLCertificateFile}] 685 end. 686 687ssl_certificate_key_file(ConfigDB) -> 688 case httpd_util:lookup(ConfigDB,ssl_certificate_key_file) of 689 undefined -> 690 []; 691 SSLCertificateKeyFile -> 692 [{keyfile,SSLCertificateKeyFile}] 693 end. 694 695ssl_log_level(ConfigDB) -> 696 case httpd_util:lookup(ConfigDB,ssl_log_alert) of 697 undefined -> 698 []; 699 SSLLogLevel -> 700 [{log_alert,SSLLogLevel}] 701 end. 702 703ssl_verify_client(ConfigDB) -> 704 case httpd_util:lookup(ConfigDB,ssl_verify_client) of 705 undefined -> 706 []; 707 SSLVerifyClient -> 708 [{verify,SSLVerifyClient}] 709 end. 710 711ssl_ciphers(ConfigDB) -> 712 case httpd_util:lookup(ConfigDB,ssl_ciphers) of 713 undefined -> 714 []; 715 Ciphers -> 716 [{ciphers, Ciphers}] 717 end. 718 719ssl_password(ConfigDB) -> 720 case httpd_util:lookup(ConfigDB,ssl_password_callback_module) of 721 undefined -> 722 []; 723 Module -> 724 case httpd_util:lookup(ConfigDB, 725 ssl_password_callback_function) of 726 undefined -> 727 []; 728 Function -> 729 Args = case httpd_util:lookup(ConfigDB, 730 ssl_password_callback_arguments) of 731 undefined -> 732 []; 733 Arguments -> 734 [Arguments] 735 end, 736 737 case catch apply(Module, Function, Args) of 738 Password when is_list(Password) -> 739 [{password, Password}]; 740 Error -> 741 error_report(ssl_password,Module,Function,Error), 742 [] 743 end 744 end 745 end. 746 747ssl_verify_depth(ConfigDB) -> 748 case httpd_util:lookup(ConfigDB, ssl_verify_client_depth) of 749 undefined -> 750 []; 751 Depth -> 752 [{depth, Depth}] 753 end. 754 755ssl_ca_certificate_file(ConfigDB) -> 756 case httpd_util:lookup(ConfigDB, ssl_ca_certificate_file) of 757 undefined -> 758 []; 759 File -> 760 [{cacertfile, File}] 761 end. 762 763plain_server_tokens() -> 764 [none, prod, major, minor, minimum, os, full]. 765 766error_report(Where,M,F,Error) -> 767 error_logger:error_report([{?MODULE, Where}, 768 {apply, {M, F, []}}, Error]). 769white_space_clean(String) -> 770 re:replace(String, "^[ \t\n\r\f]*|[ \t\n\r\f]*\$","", 771 [{return,list}, global]). 772 773validate_logger([{error, Domain}]) when is_atom(Domain) -> 774 true; 775validate_logger(List) -> 776 throw({logger, List}). 777 778 779 780 781 782