1%% ``Licensed under the Apache License, Version 2.0 (the "License"); 2%% you may not use this file except in compliance with the License. 3%% You may obtain a copy of the License at 4%% 5%% http://www.apache.org/licenses/LICENSE-2.0 6%% 7%% Unless required by applicable law or agreed to in writing, software 8%% distributed under the License is distributed on an "AS IS" BASIS, 9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10%% See the License for the specific language governing permissions and 11%% limitations under the License. 12%% 13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. 14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings 15%% AB. All Rights Reserved.'' 16%% 17%% $Id: httpd.erl,v 1.1 2008/12/17 09:53:33 mikpe Exp $ 18%% 19-module(httpd). 20-export([multi_start/1, multi_start_link/1, 21 start/0, start/1, start/2, 22 start_link/0, start_link/1, start_link/2, 23 start_child/0,start_child/1, 24 multi_stop/1, 25 stop/0,stop/1,stop/2, 26 stop_child/0,stop_child/1,stop_child/2, 27 multi_restart/1, 28 restart/0,restart/1,restart/2, 29 parse_query/1]). 30 31%% Optional start related stuff... 32-export([load/1, load_mime_types/1, 33 start2/1, start2/2, 34 start_link2/1, start_link2/2, 35 stop2/1]). 36 37%% Management stuff 38-export([block/0,block/1,block/2,block/3,block/4, 39 unblock/0,unblock/1,unblock/2]). 40 41%% Debugging and status info stuff... 42-export([verbosity/3,verbosity/4]). 43-export([get_status/1,get_status/2,get_status/3, 44 get_admin_state/0,get_admin_state/1,get_admin_state/2, 45 get_usage_state/0,get_usage_state/1,get_usage_state/2]). 46 47-include("httpd.hrl"). 48 49-define(D(F, A), io:format("~p:" ++ F ++ "~n", [?MODULE|A])). 50 51 52%% start 53 54start() -> 55 start("/var/tmp/server_root/conf/8888.conf"). 56 57start(ConfigFile) -> 58 %% ?D("start(~s) -> entry", [ConfigFile]), 59 start(ConfigFile, []). 60 61start(ConfigFile, Verbosity) when list(ConfigFile), list(Verbosity) -> 62 httpd_sup:start(ConfigFile, Verbosity). 63 64 65%% start_link 66 67start_link() -> 68 start("/var/tmp/server_root/conf/8888.conf"). 69 70start_link(ConfigFile) -> 71 start_link(ConfigFile, []). 72 73start_link(ConfigFile, Verbosity) when list(ConfigFile), list(Verbosity) -> 74 httpd_sup:start_link(ConfigFile, Verbosity). 75 76 77%% start2 & start_link2 78 79start2(Config) -> 80 start2(Config, []). 81 82start2(Config, Verbosity) when list(Config), list(Verbosity) -> 83 httpd_sup:start2(Config, Verbosity). 84 85start_link2(Config) -> 86 start_link2(Config, []). 87 88start_link2(Config, Verbosity) when list(Config), list(Verbosity) -> 89 httpd_sup:start_link2(Config, Verbosity). 90 91 92%% stop 93 94stop() -> 95 stop(8888). 96 97stop(Port) when integer(Port) -> 98 stop(undefined, Port); 99stop(Pid) when pid(Pid) -> 100 httpd_sup:stop(Pid); 101stop(ConfigFile) when list(ConfigFile) -> 102 %% ?D("stop(~s) -> entry", [ConfigFile]), 103 httpd_sup:stop(ConfigFile). 104 105stop(Addr, Port) when integer(Port) -> 106 httpd_sup:stop(Addr, Port). 107 108stop2(Config) when list(Config) -> 109 httpd_sup:stop2(Config). 110 111%% start_child 112 113start_child() -> 114 start_child("/var/tmp/server_root/conf/8888.conf"). 115 116start_child(ConfigFile) -> 117 start_child(ConfigFile, []). 118 119start_child(ConfigFile, Verbosity) -> 120 inets_sup:start_child(ConfigFile, Verbosity). 121 122 123%% stop_child 124 125stop_child() -> 126 stop_child(8888). 127 128stop_child(Port) -> 129 stop_child(undefined,Port). 130 131stop_child(Addr, Port) when integer(Port) -> 132 inets_sup:stop_child(Addr, Port). 133 134 135%% multi_start 136 137multi_start(MultiConfigFile) -> 138 case read_multi_file(MultiConfigFile) of 139 {ok,ConfigFiles} -> 140 mstart(ConfigFiles); 141 Error -> 142 Error 143 end. 144 145mstart(ConfigFiles) -> 146 mstart(ConfigFiles,[]). 147mstart([],Results) -> 148 {ok,lists:reverse(Results)}; 149mstart([H|T],Results) -> 150 Res = start(H), 151 mstart(T,[Res|Results]). 152 153 154%% multi_start_link 155 156multi_start_link(MultiConfigFile) -> 157 case read_multi_file(MultiConfigFile) of 158 {ok,ConfigFiles} -> 159 mstart_link(ConfigFiles); 160 Error -> 161 Error 162 end. 163 164mstart_link(ConfigFiles) -> 165 mstart_link(ConfigFiles,[]). 166mstart_link([],Results) -> 167 {ok,lists:reverse(Results)}; 168mstart_link([H|T],Results) -> 169 Res = start_link(H), 170 mstart_link(T,[Res|Results]). 171 172 173%% multi_stop 174 175multi_stop(MultiConfigFile) -> 176 case read_multi_file(MultiConfigFile) of 177 {ok,ConfigFiles} -> 178 mstop(ConfigFiles); 179 Error -> 180 Error 181 end. 182 183mstop(ConfigFiles) -> 184 mstop(ConfigFiles,[]). 185mstop([],Results) -> 186 {ok,lists:reverse(Results)}; 187mstop([H|T],Results) -> 188 Res = stop(H), 189 mstop(T,[Res|Results]). 190 191 192%% multi_restart 193 194multi_restart(MultiConfigFile) -> 195 case read_multi_file(MultiConfigFile) of 196 {ok,ConfigFiles} -> 197 mrestart(ConfigFiles); 198 Error -> 199 Error 200 end. 201 202mrestart(ConfigFiles) -> 203 mrestart(ConfigFiles,[]). 204mrestart([],Results) -> 205 {ok,lists:reverse(Results)}; 206mrestart([H|T],Results) -> 207 Res = restart(H), 208 mrestart(T,[Res|Results]). 209 210 211%% restart 212 213restart() -> restart(undefined,8888). 214 215restart(Port) when integer(Port) -> 216 restart(undefined,Port); 217restart(ConfigFile) when list(ConfigFile) -> 218 case get_addr_and_port(ConfigFile) of 219 {ok,Addr,Port} -> 220 restart(Addr,Port); 221 Error -> 222 Error 223 end. 224 225 226restart(Addr,Port) when integer(Port) -> 227 do_restart(Addr,Port). 228 229do_restart(Addr,Port) when integer(Port) -> 230 Name = make_name(Addr,Port), 231 case whereis(Name) of 232 Pid when pid(Pid) -> 233 httpd_manager:restart(Pid); 234 _ -> 235 {error,not_started} 236 end. 237 238 239%%% ========================================================= 240%%% Function: block/0, block/1, block/2, block/3, block/4 241%%% block() 242%%% block(Port) 243%%% block(ConfigFile) 244%%% block(Addr,Port) 245%%% block(Port,Mode) 246%%% block(ConfigFile,Mode) 247%%% block(Addr,Port,Mode) 248%%% block(ConfigFile,Mode,Timeout) 249%%% block(Addr,Port,Mode,Timeout) 250%%% 251%%% Returns: ok | {error,Reason} 252%%% 253%%% Description: This function is used to block an HTTP server. 254%%% The blocking can be done in two ways, 255%%% disturbing or non-disturbing. Default is disturbing. 256%%% When a HTTP server is blocked, all requests are rejected 257%%% (status code 503). 258%%% 259%%% disturbing: 260%%% By performing a disturbing block, the server 261%%% is blocked forcefully and all ongoing requests 262%%% are terminated. No new connections are accepted. 263%%% If a timeout time is given then, on-going requests 264%%% are given this much time to complete before the 265%%% server is forcefully blocked. In this case no new 266%%% connections is accepted. 267%%% 268%%% non-disturbing: 269%%% A non-disturbing block is more gracefull. No 270%%% new connections are accepted, but the ongoing 271%%% requests are allowed to complete. 272%%% If a timeout time is given, it waits this long before 273%%% giving up (the block operation is aborted and the 274%%% server state is once more not-blocked). 275%%% 276%%% Types: Port -> integer() 277%%% Addr -> {A,B,C,D} | string() | undefined 278%%% ConfigFile -> string() 279%%% Mode -> disturbing | non_disturbing 280%%% Timeout -> integer() 281%%% 282block() -> block(undefined,8888,disturbing). 283 284block(Port) when integer(Port) -> 285 block(undefined,Port,disturbing); 286 287block(ConfigFile) when list(ConfigFile) -> 288 case get_addr_and_port(ConfigFile) of 289 {ok,Addr,Port} -> 290 block(Addr,Port,disturbing); 291 Error -> 292 Error 293 end. 294 295block(Addr,Port) when integer(Port) -> 296 block(Addr,Port,disturbing); 297 298block(Port,Mode) when integer(Port), atom(Mode) -> 299 block(undefined,Port,Mode); 300 301block(ConfigFile,Mode) when list(ConfigFile), atom(Mode) -> 302 case get_addr_and_port(ConfigFile) of 303 {ok,Addr,Port} -> 304 block(Addr,Port,Mode); 305 Error -> 306 Error 307 end. 308 309 310block(Addr,Port,disturbing) when integer(Port) -> 311 do_block(Addr,Port,disturbing); 312block(Addr,Port,non_disturbing) when integer(Port) -> 313 do_block(Addr,Port,non_disturbing); 314 315block(ConfigFile,Mode,Timeout) when list(ConfigFile), atom(Mode), integer(Timeout) -> 316 case get_addr_and_port(ConfigFile) of 317 {ok,Addr,Port} -> 318 block(Addr,Port,Mode,Timeout); 319 Error -> 320 Error 321 end. 322 323 324block(Addr,Port,non_disturbing,Timeout) when integer(Port), integer(Timeout) -> 325 do_block(Addr,Port,non_disturbing,Timeout); 326block(Addr,Port,disturbing,Timeout) when integer(Port), integer(Timeout) -> 327 do_block(Addr,Port,disturbing,Timeout). 328 329do_block(Addr,Port,Mode) when integer(Port), atom(Mode) -> 330 Name = make_name(Addr,Port), 331 case whereis(Name) of 332 Pid when pid(Pid) -> 333 httpd_manager:block(Pid,Mode); 334 _ -> 335 {error,not_started} 336 end. 337 338 339do_block(Addr,Port,Mode,Timeout) when integer(Port), atom(Mode) -> 340 Name = make_name(Addr,Port), 341 case whereis(Name) of 342 Pid when pid(Pid) -> 343 httpd_manager:block(Pid,Mode,Timeout); 344 _ -> 345 {error,not_started} 346 end. 347 348 349%%% ========================================================= 350%%% Function: unblock/0, unblock/1, unblock/2 351%%% unblock() 352%%% unblock(Port) 353%%% unblock(ConfigFile) 354%%% unblock(Addr,Port) 355%%% 356%%% Description: This function is used to reverse a previous block 357%%% operation on the HTTP server. 358%%% 359%%% Types: Port -> integer() 360%%% Addr -> {A,B,C,D} | string() | undefined 361%%% ConfigFile -> string() 362%%% 363unblock() -> unblock(undefined,8888). 364unblock(Port) when integer(Port) -> unblock(undefined,Port); 365 366unblock(ConfigFile) when list(ConfigFile) -> 367 case get_addr_and_port(ConfigFile) of 368 {ok,Addr,Port} -> 369 unblock(Addr,Port); 370 Error -> 371 Error 372 end. 373 374unblock(Addr,Port) when integer(Port) -> 375 Name = make_name(Addr,Port), 376 case whereis(Name) of 377 Pid when pid(Pid) -> 378 httpd_manager:unblock(Pid); 379 _ -> 380 {error,not_started} 381 end. 382 383 384verbosity(Port,Who,Verbosity) -> 385 verbosity(undefined,Port,Who,Verbosity). 386 387verbosity(Addr,Port,Who,Verbosity) -> 388 Name = make_name(Addr,Port), 389 case whereis(Name) of 390 Pid when pid(Pid) -> 391 httpd_manager:verbosity(Pid,Who,Verbosity); 392 _ -> 393 not_started 394 end. 395 396 397%%% ========================================================= 398%%% Function: get_admin_state/0, get_admin_state/1, get_admin_state/2 399%%% get_admin_state() 400%%% get_admin_state(Port) 401%%% get_admin_state(Addr,Port) 402%%% 403%%% Returns: {ok,State} | {error,Reason} 404%%% 405%%% Description: This function is used to retrieve the administrative 406%%% state of the HTTP server. 407%%% 408%%% Types: Port -> integer() 409%%% Addr -> {A,B,C,D} | string() | undefined 410%%% State -> unblocked | shutting_down | blocked 411%%% Reason -> term() 412%%% 413get_admin_state() -> get_admin_state(undefined,8888). 414get_admin_state(Port) when integer(Port) -> get_admin_state(undefined,Port); 415 416get_admin_state(ConfigFile) when list(ConfigFile) -> 417 case get_addr_and_port(ConfigFile) of 418 {ok,Addr,Port} -> 419 unblock(Addr,Port); 420 Error -> 421 Error 422 end. 423 424get_admin_state(Addr,Port) when integer(Port) -> 425 Name = make_name(Addr,Port), 426 case whereis(Name) of 427 Pid when pid(Pid) -> 428 httpd_manager:get_admin_state(Pid); 429 _ -> 430 {error,not_started} 431 end. 432 433 434 435%%% ========================================================= 436%%% Function: get_usage_state/0, get_usage_state/1, get_usage_state/2 437%%% get_usage_state() 438%%% get_usage_state(Port) 439%%% get_usage_state(Addr,Port) 440%%% 441%%% Returns: {ok,State} | {error,Reason} 442%%% 443%%% Description: This function is used to retrieve the usage 444%%% state of the HTTP server. 445%%% 446%%% Types: Port -> integer() 447%%% Addr -> {A,B,C,D} | string() | undefined 448%%% State -> idle | active | busy 449%%% Reason -> term() 450%%% 451get_usage_state() -> get_usage_state(undefined,8888). 452get_usage_state(Port) when integer(Port) -> get_usage_state(undefined,Port); 453 454get_usage_state(ConfigFile) when list(ConfigFile) -> 455 case get_addr_and_port(ConfigFile) of 456 {ok,Addr,Port} -> 457 unblock(Addr,Port); 458 Error -> 459 Error 460 end. 461 462get_usage_state(Addr,Port) when integer(Port) -> 463 Name = make_name(Addr,Port), 464 case whereis(Name) of 465 Pid when pid(Pid) -> 466 httpd_manager:get_usage_state(Pid); 467 _ -> 468 {error,not_started} 469 end. 470 471 472 473%%% ========================================================= 474%% Function: get_status(ConfigFile) -> Status 475%% get_status(Port) -> Status 476%% get_status(Addr,Port) -> Status 477%% get_status(Port,Timeout) -> Status 478%% get_status(Addr,Port,Timeout) -> Status 479%% 480%% Arguments: ConfigFile -> string() 481%% Configuration file from which Port and 482%% BindAddress will be extracted. 483%% Addr -> {A,B,C,D} | string() 484%% Bind Address of the http server 485%% Port -> integer() 486%% Port number of the http server 487%% Timeout -> integer() 488%% Timeout time for the call 489%% 490%% Returns: Status -> list() 491%% 492%% Description: This function is used when the caller runs in the 493%% same node as the http server or if calling with a 494%% program such as erl_call (see erl_interface). 495%% 496 497get_status(ConfigFile) when list(ConfigFile) -> 498 case get_addr_and_port(ConfigFile) of 499 {ok,Addr,Port} -> 500 get_status(Addr,Port); 501 Error -> 502 Error 503 end; 504 505get_status(Port) when integer(Port) -> 506 get_status(undefined,Port,5000). 507 508get_status(Port,Timeout) when integer(Port), integer(Timeout) -> 509 get_status(undefined,Port,Timeout); 510 511get_status(Addr,Port) when list(Addr), integer(Port) -> 512 get_status(Addr,Port,5000). 513 514get_status(Addr,Port,Timeout) when integer(Port) -> 515 Name = make_name(Addr,Port), 516 case whereis(Name) of 517 Pid when pid(Pid) -> 518 httpd_manager:get_status(Pid,Timeout); 519 _ -> 520 not_started 521 end. 522 523 524%% load config 525 526load(ConfigFile) -> 527 httpd_conf:load(ConfigFile). 528 529load_mime_types(MimeTypesFile) -> 530 httpd_conf:load_mime_types(MimeTypesFile). 531 532 533%% parse_query 534 535parse_query(String) -> 536 {ok, SplitString} = regexp:split(String,"[&;]"), 537 foreach(SplitString). 538 539foreach([]) -> 540 []; 541foreach([KeyValue|Rest]) -> 542 {ok, Plus2Space, _} = regexp:gsub(KeyValue,"[\+]"," "), 543 case regexp:split(Plus2Space,"=") of 544 {ok,[Key|Value]} -> 545 [{httpd_util:decode_hex(Key), 546 httpd_util:decode_hex(lists:flatten(Value))}|foreach(Rest)]; 547 {ok,_} -> 548 foreach(Rest) 549 end. 550 551 552%% get_addr_and_port 553 554get_addr_and_port(ConfigFile) -> 555 case httpd_conf:load(ConfigFile) of 556 {ok,ConfigList} -> 557 Port = httpd_util:key1search(ConfigList,port,80), 558 Addr = httpd_util:key1search(ConfigList,bind_address), 559 {ok,Addr,Port}; 560 Error -> 561 Error 562 end. 563 564 565%% make_name 566 567make_name(Addr,Port) -> 568 httpd_util:make_name("httpd",Addr,Port). 569 570 571%% Multi stuff 572%% 573 574read_multi_file(File) -> 575 read_mfile(file:open(File,[read])). 576 577read_mfile({ok,Fd}) -> 578 read_mfile(read_line(Fd),Fd,[]); 579read_mfile(Error) -> 580 Error. 581 582read_mfile(eof,_Fd,SoFar) -> 583 {ok,lists:reverse(SoFar)}; 584read_mfile({error,Reason},_Fd,SoFar) -> 585 {error,Reason}; 586read_mfile([$#|Comment],Fd,SoFar) -> 587 read_mfile(read_line(Fd),Fd,SoFar); 588read_mfile([],Fd,SoFar) -> 589 read_mfile(read_line(Fd),Fd,SoFar); 590read_mfile(Line,Fd,SoFar) -> 591 read_mfile(read_line(Fd),Fd,[Line|SoFar]). 592 593read_line(Fd) -> read_line1(io:get_line(Fd,[])). 594read_line1(eof) -> eof; 595read_line1(String) -> httpd_conf:clean(String). 596