(* $Id: netcgi_plex.ml 1243 2009-05-25 23:45:36Z gerd $ *) open Netcgi type mountpoint = [ `Mount_dir of string | `Mount_at of string ] let wait_for_request timeout fd = let fd_style = Netsys.get_fd_style fd in let rec wait t = let t0 = Unix.gettimeofday() in try let ok = Netsys.wait_until_readable fd_style fd t in if not ok then `Conn_close else `Conn_keep_alive with | Unix.Unix_error(Unix.EINTR,_,_) -> if timeout < 0.0 then wait t else let t1 = Unix.gettimeofday() in let t' = t -. (t1 -. t0) in if t' > 0.0 then wait t' else `Conn_close in wait timeout let rec do_connection timeout do_request fd = let cdir = wait_for_request timeout fd in if cdir = `Conn_keep_alive then ( let cdir' = do_request fd in if cdir' = `Conn_keep_alive then do_connection timeout do_request fd else cdir' ) else ( cdir ) let term_connection cont fd cdir = match cdir with | `Conn_close -> Unix.shutdown fd Unix.SHUTDOWN_ALL; Unix.close fd; | `Conn_close_linger -> Unix.setsockopt_optint fd Unix.SO_LINGER (Some 15); Unix.shutdown fd Unix.SHUTDOWN_ALL; Unix.close fd | `Conn_error e -> cont # log `Crit ("Exception " ^ Netexn.to_string e); Unix.shutdown fd Unix.SHUTDOWN_ALL; Unix.close fd; | `Conn_keep_alive -> assert false let fcgi_processor ?(config = Netcgi.default_config) ?(output_type = (`Direct "" : Netcgi.output_type)) ?(arg_store = fun _ _ _ -> `Automatic) ?(exn_handler = fun _ f -> f()) ?(timeout = -1.0) ?mount f : Netplex_types.processor = (* TODO: mount *) ( object inherit Netplex_kit.empty_processor_hooks() method process ~when_done cont fd proto = let max_conns = 5 in (* TODO: Get max_conns from workload manager *) let log msg = cont # log `Err msg in let cdir = try Unix.clear_nonblock fd; do_connection timeout (Netcgi_fcgi.handle_request config output_type arg_store exn_handler (f cont) ~max_conns ~log:(Some log) ) fd with | e -> `Conn_error e in term_connection cont fd cdir; when_done() method supported_ptypes = [ `Multi_processing; `Multi_threading ] end ) ;; let scgi_processor ?(config = Netcgi.default_config) ?(output_type = (`Direct "" : Netcgi.output_type)) ?(arg_store = fun _ _ _ -> `Automatic) ?(exn_handler = fun _ f -> f()) ?(timeout = -1.0) ?mount f : Netplex_types.processor = (* TODO: mount *) ( object inherit Netplex_kit.empty_processor_hooks() method process ~when_done cont fd proto = let log msg = cont # log `Err msg in let cdir = try Unix.clear_nonblock fd; do_connection timeout (Netcgi_scgi.handle_request config output_type arg_store exn_handler (f cont) ~log:(Some log) ) fd with | e -> `Conn_error e in term_connection cont fd cdir; when_done() method supported_ptypes = [ `Multi_processing; `Multi_threading ] end ) ;; let ajp_processor ?(config = Netcgi.default_config) ?(output_type = (`Direct "" : Netcgi.output_type)) ?(arg_store = fun _ _ _ -> `Automatic) ?(exn_handler = fun _ f -> f()) ?(timeout = -1.0) ?mount f : Netplex_types.processor = (* TODO: mount *) ( object inherit Netplex_kit.empty_processor_hooks() method process ~when_done cont fd proto = let log msg = cont # log `Err msg in let cdir = try Unix.clear_nonblock fd; do_connection timeout (Netcgi_ajp.handle_request config output_type arg_store exn_handler (f cont) ~log:(Some log) ) fd with | e -> `Conn_error e in term_connection cont fd cdir; when_done() method supported_ptypes = [ `Multi_processing; `Multi_threading ] end ) ;; let multi_process ?config ?output_type ?arg_store ?exn_handler ?timeout ?mount ?(enable = [ `FCGI; `SCGI; `AJP ]) hooks f = ( object inherit Netplex_kit.processor_base hooks method process ~when_done cont fd proto = let real_processor = match proto with | "fcgi" when List.mem `FCGI enable -> fcgi_processor ?config ?output_type ?arg_store ?exn_handler ?timeout ?mount (fun cont fcgi -> f cont (fcgi : #Netcgi_fcgi.cgi :> cgi)) | "scgi" when List.mem `SCGI enable -> scgi_processor ?config ?output_type ?arg_store ?exn_handler ?timeout ?mount (fun cont cgi -> f cont cgi) | "ajp" when List.mem `AJP enable -> ajp_processor ?config ?output_type ?arg_store ?exn_handler ?timeout ?mount (fun cont cgi -> f cont cgi) | _ -> failwith ("Unsupported protocol: " ^ proto) in real_processor # process ~when_done cont fd proto method supported_ptypes = [ `Multi_processing; `Multi_threading ] end ) ;; class factory ?config ?enable ?(name = "netcgi") ?output_type ?arg_store ?exn_handler ?configure f : Netplex_types.processor_factory = object method name = name method create_processor ctrl_cfg cfg addr = let timeout_opt = try Some(float (cfg#int_param (cfg#resolve_parameter addr "timeout"))) with | Not_found -> None in let hooks = match configure with | Some c -> c cfg addr | None -> new Netplex_kit.empty_processor_hooks() in (* TODO: parse mount_dir, mount_at *) multi_process ?config ?output_type ?arg_store ?exn_handler ?timeout:timeout_opt (* ?mount *) ?enable hooks f end let factory = new factory