(* TODO: - correct error messages, not failwith "..." - HTML design, logo - dump *) open Netcgi let operating_type = Netcgi.buffered_transactional_optype let cgi = new Netcgi.std_activation ~operating_type () let fatal_error title s = cgi # output # rollback_work(); cgi # set_header ~content_type:"text/html; charset=\"iso-8859-1\"" ~cache:`No_cache (); cgi # output # output_string ("

" ^ title ^ "

"); cgi # output # output_string s; cgi # output # commit_work(); cgi # finalize () let () = fatal_error "Error" "Blabla\n\n" (* (* Configuration *) let session_dirs = [ "/home/frisch/sessions"; "/users/formel/cduce/sessions" ] let session_dir = try List.find Sys.file_exists session_dirs with Not_found -> fatal_error "Internal error" "Cannot find sessions directory" let timeout = 60 * 5 (* seconds *) let max_sess = 10 (*****************) let persistant = ref false let session_id = ref "" let html_header p = p " CDuce online prototype

CDuce online prototype

"; if !persistant then (p "(session #"; p !session_id; p ")
") let html_form p content = p "
"; p ""; if !persistant then( p "\ \ "; ) else ( p ""; ); p "
"; p "
" let html_footer p = p "" let () = Random.self_init (); State.close () let session_file sid = Filename.concat session_dir sid let gen_session_id () = string_of_int (Random.bits ()) let check_session_id sid = try ignore (int_of_string sid) with _ -> failwith "Invalid session id" let close_session sid = check_session_id sid; try Unix.unlink (session_file sid) with Unix.Unix_error (_,_,_) -> () let flush_sessions () = let time = Unix.time () -. (float timeout) in let n = ref 0 in let dir = Unix.opendir session_dir in try while true do let f = session_file (Unix.readdir dir) in let st = Unix.stat f in if (st.Unix.st_kind = Unix.S_REG) then if (st.Unix.st_mtime < time) then Unix.unlink f else incr n done; assert false with End_of_file -> Unix.closedir dir; !n let cmds = [ "open", `Open; "close", `Close; "dump", `Dump; "exec", `Exec; "new", `New; ] let main (cgi : Netcgi.std_activation) = let p = cgi # output # output_string in let clicked s = cgi # argument_value s <> "" in try let nb_sessions = flush_sessions () in cgi # set_header ~content_type:"text/html; charset=\"iso-8859-1\"" (); let cmd = try snd (List.find (fun (x,y) -> clicked x) cmds) with Not_found -> `New in let sid = match cmd with | `Open -> if (nb_sessions >= max_sess) then failwith "Too many open sessions ..."; let sid = gen_session_id () in (* touch the session file ... *) let chan = open_out_bin (session_file sid) in close_out chan; sid | `Close -> close_session (cgi # argument_value "session"); "" | `New -> "" | _ -> cgi # argument_value "session" in session_id := sid; persistant := !session_id <> ""; if !persistant then check_session_id !session_id; let dialog content = html_form p content in let exec src = let ppf = Format.str_formatter and input = Stream.of_string src in Location.set_source (`String src); Location.set_viewport `Html; Load_xml.set_auth false; if !persistant then ( try let chan = open_in_bin (session_file !session_id) in if in_channel_length chan > 0 then (let s = Marshal.from_channel chan in State.set s); close_in chan; with Sys_error _ -> failwith "This session has expired ..." ); let ok = Cduce.run ppf input in if ok then Format.fprintf ppf "@\nOk.@\n"; let res = Format.flush_str_formatter () in cgi # output # output_string ("
" ^ res ^ "
"); if ok then dialog "" else dialog src; if ok && !persistant then ( let s = State.get () in let chan = open_out_bin (session_file !session_id) in Marshal.to_channel chan s [ Marshal.Closures ]; close_out chan ) in html_header p; let prog = cgi # argument_value "prog" in (match cmd with | `Exec -> exec prog | `Open -> dialog prog | `New -> dialog "" | `Dump -> failwith "Dump not yet implemented" | `Close -> dialog "" ); html_footer p; cgi # output # commit_work() with exn -> cgi # output # rollback_work(); cgi # set_header ~status:`Internal_server_error ~cache:`No_cache (); cgi # output # output_string "

Internal software error!

"; (match exn with | Unix.Unix_error (e,f,arg) -> cgi # output # output_string ( "System error: " ^ (Unix.error_message e) ^ "; function " ^ f ^ "; argument " ^ arg ) | exn -> cgi # output # output_string (Printexc.to_string exn); ); cgi # output # commit_work() let () = main cgi; cgi # finalize () *)