%s
" (String.concat "" contents) let tt contents = Printf.sprintf "%s" (String.concat "" contents) (* Process a page request. *) let process (cgi : Netcgi.cgi) = (* Get a parameter from a form. *) let value = cgi#argument_value "PARAM_NAME" in (* Output a document. *) let out = cgi#out_channel#output_string in out (start_html "Howdy there!"); out (p ["You typed: "; tt [escape_html value]]); out end_html; (* Flush the output buffer. *) cgi#out_channel#commit_work () (* Initialize and run the Netcgi process. *) let () = let config = Netcgi.default_config in let buffered _ ch = new Netchannels.buffered_trans_channel ch in Netcgi_cgi.run ~config ~output_type:(`Transactional buffered) process (*-----------------------------*) (* Set the output mime-type and expiration time. *) cgi#set_header ~content_type:"text/html" ~cache:(`Max_age 3600) () (*-----------------------------*) (* Read multiple form fields, one containing multiple values. *) let who = cgi#argument_value "Name" in let phone = cgi#argument_value "Number" in let picks = List.map (fun arg -> arg#value) (cgi#multiple_argument "Choices") in (* ... *) (* @@PLEAC@@_19.2 *) (* The default Netcgi configuration sends all exceptions to the browser in nicely formatted error pages. This is helpful during development but may be inappropriate for production. The exception pages can be disabled by setting the "default_exn_handler" configuration field: *) let config = {Netcgi.default_config with Netcgi.default_exn_handler=false} (* Most web servers send standard error to the error log, which is typically /var/log/apache2/error.log for a default Apache 2 configuration. You can define a "warn" function to include the script name in warning messages: *) let warn = Printf.eprintf "%s: %s\n" (Filename.basename Sys.argv.(0)) let () = warn "This goes to the error log." (* You can also use Printf.kprintf to define a fancier warning function that supports Printf formatting. *) let warn = Printf.kprintf (Printf.eprintf "%s: %s\n" (Filename.basename Sys.argv.(0))) let () = warn "So does %s." "this" (* @@PLEAC@@_19.3 *) #!/usr/bin/env ocaml (* webwhoami - show web users id *) #use "topfind";; #require "netcgi2";; #require "unix";; let process (cgi : Netcgi.cgi) = cgi#set_header ~content_type:"text/plain" (); cgi#out_channel#output_string (Printf.sprintf "Running as %s\n" (Unix.getpwuid (Unix.geteuid ())).Unix.pw_name); cgi#out_channel#commit_work () let () = let config = Netcgi.default_config in let buffered _ ch = new Netchannels.buffered_trans_channel ch in Netcgi_cgi.run ~config ~output_type:(`Transactional buffered) process (*-----------------------------*) (* By using Netcgi_test.run instead of Netcgi_run, you can enable a command-line testing mechanism. *) let () = let config = Netcgi.default_config in let buffered _ ch = new Netchannels.buffered_trans_channel ch in let output_type = `Transactional buffered in if Unix.isatty Unix.stdin then Netcgi_test.run ~config ~output_type process else Netcgi_cgi.run ~config ~output_type process (* Now, you can run the CGI script from the command line to test for compilation and runtime errors. *) $ ./webwhoami -help ocaml [options] name1=value1 ... nameN=valueN -get Set the method to GET (the default) -head Set the method to HEAD -post Set the method to POST -put file Set the method to PUT with the file as argument -delete Set the method to DELETE -mimetype type Set the MIME type for the next file argument(s) (default: text/plain) -filename path Set the filename property for the next file argument(s) -filearg name=file Specify a file argument whose contents are in the file -user name Set REMOTE_USER to this name -prop name=value Set the environment property -header name=value Set the request header field -o file Set the output file (default: stdout) -help Display this list of options --help Display this list of options (* @@PLEAC@@_19.4 *) (* There is no feature in OCaml resembling Perl's "taint mode". *) (* @@PLEAC@@_19.5 *) (* Ocamlnet provides an Apache 2 module called netcgi_apache that allows Netcgi scripts to run inside the Apache process. To load the module, put something like the following in your Apache configuration file: *) LoadModule netcgi_module /usr/lib/apache2/modules/mod_netcgi_apache.so NetcgiLoad pcre/pcre.cma NetcgiLoad netsys/netsys.cma NetcgiLoad netstring/netstring.cma NetcgiLoad str.cma NetcgiLoad netcgi2/netcgi.cma NetcgiLoad netcgi_apache/netcgi_apache.cma (* Extra libraries can be added with additional "NetcgiLoad" directives. The following will enable netcgi_apache for *.cma files: *) NetcgiHandler Netcgi_apache.bytecode AddHandler ocaml-bytecode .cma (* Or, if you prefer, you can enable netcgi_apache for a directory: *)%s
" (String.concat "" contents) let h1 contents = sprintf "%s
" (String.concat "" contents) let start_form ?(action="") ?(method'="get") () = sprintf "" let textfield ?(name="") ?(value="") () = sprintf "" (escape_html name) (escape_html value) let process (cgi : Netcgi.cgi) = let cookname = "favorite ice cream" in let favorite = cgi#argument_value "flavor" in let tasty = try Netcgi_common.Cookie.value (cgi#environment#cookie cookname) with Not_found -> "mint" in let print s = cgi#out_channel#output_string s; cgi#out_channel#output_string "\n" in cgi#set_header ~content_type:"text/html" (); if favorite = "" then begin print (start_html "Ice Cookies"); print (h1 ["Hello Ice Cream"]); print hr; print (start_form ~method':"post" ()); print (p ["Please select a flavor: "; textfield ~name:"flavor" ~value:tasty ()]); print end_form; print hr; print end_html; end else begin let cookie = Netcgi_common.Cookie.make ~max_age:(60 * 60 * 24 * 365 * 2) (* 2 years *) cookname favorite in cgi#set_header ~set_cookies:[cookie] (); print (start_html "Ice Cookies, #2"); print (h1 ["Hello Ice Cream"]); print (p ["You chose as your favorite flavor `"; escape_html favorite; "'."]); print end_html; end; cgi#out_channel#commit_work () let () = let config = Netcgi.default_config in let buffered _ ch = new Netchannels.buffered_trans_channel ch in let output_type = `Transactional buffered in if Unix.isatty Unix.stdin then Netcgi_test.run ~config ~output_type process else Netcgi_cgi.run ~config ~output_type process (* @@PLEAC@@_19.11 *) #!/usr/bin/env ocaml (* who.cgi - run who(1) on a user and format the results nicely *) #use "topfind";; #require "netcgi2";; #require "str";; open Printf let escape_html = Netencoding.Html.encode ~in_enc:`Enc_utf8 () let start_html title = sprintf "\%s
" (String.concat "" contents) let pre contents = sprintf "%s" (String.concat "" contents) let start_form ?(action="") ?(method'="get") () = sprintf "" let textfield ?(name="") ?(value="") () = sprintf "" (escape_html name) (escape_html value) let submit ?(name="") ?(value="") () = sprintf "" (escape_html name) (escape_html value) let process (cgi : Netcgi.cgi) = let print s = cgi#out_channel#output_string s; cgi#out_channel#output_string "\n" in let name = cgi#argument_value "WHO" in (* print search form *) cgi#set_header ~content_type:"text/html" (); print (start_html "Query Users"); print (h1 ["Search"]); print (start_form ~method':"post" ()); print (p ["Which user? "; textfield ~name:"WHO" ~value:name ()]); print (submit ~value:"Query" ()); print end_form; (* print results of the query if we have someone to look for *) if name <> "" then begin print (h1 ["Results"]); let regexp = Str.regexp name in let proc = Unix.open_process_in "who" in let found = ref false in let html = Buffer.create 0 in begin (* call who and build up text of response *) try while true do let line = input_line proc in (* only lines matching [name] *) if Str.string_match regexp line 0 then begin Buffer.add_string html (escape_html line ^ "\n"); found := true; end done with End_of_file -> close_in proc; (* nice message if we didn't find anyone by that name *) if not !found then Buffer.add_string html (escape_html name ^ " is not logged in"); end; print (pre [Buffer.contents html]); end; print end_html let () = let config = Netcgi.default_config in let buffered _ ch = new Netchannels.buffered_trans_channel ch in let output_type = `Transactional buffered in if Unix.isatty Unix.stdin then Netcgi_test.run ~config ~output_type process else Netcgi_cgi.run ~config ~output_type process (* @@PLEAC@@_19.12 *) #!/usr/bin/env ocaml #use "topfind";; #require "netcgi2";; open Printf let ( => ) k v = (k, v) let escape_html = Netencoding.Html.encode ~in_enc:`Enc_utf8 () let start_html title = sprintf "\
%s
" (String.concat "" contents) let pre contents = sprintf "%s" (String.concat "" contents) let start_form ?(action="") ?(method'="get") () = sprintf "" let hidden ?(name="") ?(value="") () = sprintf "" (escape_html name) (escape_html value) let submit ?(name="") ?(value="") () = sprintf "" (escape_html name) (escape_html value) let popup_menu ?(name="") ?(value="") values = let options = List.map (fun (value', label) -> sprintf "" (if value = value' then "selected=\"selected\"" else "") (escape_html value') (escape_html label)) values in sprintf "" (escape_html name) (String.concat "\n" options) let standard_header () = h1 ["Program Title"] let standard_footer () = "
%s
" (String.concat "" contents) let pre contents = sprintf "%s" (String.concat "" contents) let start_form ?(action="") ?(method'="get") () = sprintf "" let hidden ?(name="") ?(value="") () = sprintf "" (escape_html name) (escape_html value) let submit ?(name="") ?(value="") () = sprintf "" (escape_html name) (escape_html value) let textfield ?(name="") ?(value="") () = sprintf "" (escape_html name) (escape_html value) let popup_menu ?(name="") ?(value="") values = let options = List.map (fun (value', label) -> sprintf "" (if value = value' then "selected=\"selected\"" else "") (escape_html value') (escape_html label)) values in sprintf "" (escape_html name) (String.concat "\n" options) let defaults label = sprintf "" (escape_html label) "javascript:location.href='?'" let to_page value = submit ~name:".State" ~value () (******************************** * header, footer, menu functions ********************************) let standard_header print = print (start_html "Shirts"); print (start_form ()) let standard_footer print = print end_form; print end_html let shop_menu print = print (p [defaults "Empty My Shopping Cart"; to_page "Shirt"; to_page "Sweater"; to_page "Checkout"]) (***************************** * subroutines for each screen *****************************) (* The default page. *) let front_page cgi print active = if active then begin print (h1 ["Hi!"]); print "Welcome to our Shirt Shop! Please make your selection "; print "from the menu below."; shop_menu print; end (* Page to order a shirt from. *) let shirt (cgi : Netcgi.cgi) print active = let sizes = ["XL" => "X-Large"; "L" => "Large"; "M" => "Medium"; "S" => "Small"; "XS" => "X-Small"] in let colors = ["Black" => "Black"; "White" => "White"] in let size, color, count = cgi#argument_value "shirt_size", cgi#argument_value "shirt_color", cgi#argument_value "shirt_count" in (* sanity check *) let size = if List.mem_assoc size sizes then size else fst (List.hd sizes) in let color = if List.mem_assoc color colors then color else fst (List.hd colors) in if active then begin print (h1 ["T-Shirt"]); print (p ["What a shirt! This baby is decked out with all the "; "options. It comes with full luxury interior, cotton "; "trim, and a collar to make your eyes water! "; "Unit price: $33.00"]); print (h2 ["Options"]); print (p ["How Many? "; textfield ~name:"shirt_count" ~value:count ()]); print (p ["Size? "; popup_menu ~name:"shirt_size" ~value:size sizes]); print (p ["Color? "; popup_menu ~name:"shirt_color" ~value:color colors]); shop_menu print; end else begin if size <> "" then print (hidden ~name:"shirt_size" ~value:size ()); if color <> "" then print (hidden ~name:"shirt_color" ~value:color ()); if count <> "" then print (hidden ~name:"shirt_count" ~value:count ()); end (* Page to order a sweater from. *) let sweater (cgi : Netcgi.cgi) print active = let sizes = ["XL" => "X-Large"; "L" => "Large"; "M" => "Medium"] in let colors = ["Chartreuse" => "Chartreuse"; "Puce" => "Puce"; "Lavender" => "Lavender"] in let size, color, count = cgi#argument_value "sweater_size", cgi#argument_value "sweater_color", cgi#argument_value "sweater_count" in (* sanity check *) let size = if List.mem_assoc size sizes then size else fst (List.hd sizes) in let color = if List.mem_assoc color colors then color else fst (List.hd colors) in if active then begin print (h1 ["Sweater"]); print (p ["Nothing implies preppy elegance more than this fine "; "sweater. Made by peasant workers from black market "; "silk, it slides onto your lean form and cries out "; "``Take me, for I am a god!''. Unit price: $49.99."]); print (h2 ["Options"]); print (p ["How Many? "; textfield ~name:"sweater_count" ~value:count ()]); print (p ["Size? "; popup_menu ~name:"sweater_size" ~value:size sizes]); print (p ["Color? "; popup_menu ~name:"sweater_color" ~value:color colors]); shop_menu print; end else begin if size <> "" then print (hidden ~name:"sweater_size" ~value:size ()); if color <> "" then print (hidden ~name:"sweater_color" ~value:color ()); if count <> "" then print (hidden ~name:"sweater_count" ~value:count ()); end let calculate_price (cgi : Netcgi.cgi) = let shirts = try int_of_string (cgi#argument_value "shirt_count") with Failure _ -> 0 in let sweaters = try int_of_string (cgi#argument_value "shirt_count") with Failure _ -> 0 in sprintf "$%.2f" (float shirts *. 33.0 +. float sweaters *. 49.99) (* Returns HTML for the current order ("You have ordered ...") *) let order_text (cgi : Netcgi.cgi) = let shirt_count = cgi#argument_value "shirt_count" in let shirt_size = cgi#argument_value "shirt_size" in let shirt_color = cgi#argument_value "shirt_color" in let sweater_count = cgi#argument_value "sweater_count" in let sweater_size = cgi#argument_value "sweater_size" in let sweater_color = cgi#argument_value "sweater_color" in let html = Buffer.create 0 in if not (List.mem shirt_count [""; "0"]) then Buffer.add_string html (p ["You have ordered "; escape_html shirt_count; " shirts of size "; escape_html shirt_size; " and color "; escape_html shirt_color; "."]); if not (List.mem sweater_count [""; "0"]) then Buffer.add_string html (p ["You have ordered "; escape_html sweater_count; " sweaters of size "; escape_html sweater_size; " and color "; escape_html sweater_color; "."]); let html = Buffer.contents html in match html with | "" -> p ["Nothing!"] | html -> html ^ p ["For a total cost of "; calculate_price cgi] (* Page to display current order for confirmation. *) let checkout (cgi : Netcgi.cgi) print active = if active then begin print (h1 ["Order Confirmation"]); print (p ["You ordered the following:"]); print (order_text cgi); print (p ["Is this right? Select 'Card' to pay for the items "; "or 'Shirt' or 'Sweater' to continue shopping."]); print (p [to_page "Card"; to_page "Shirt"; to_page "Sweater"]); end (* Page to gather credit-card information. *) let credit_card (cgi : Netcgi.cgi) print active = let widgets = ["Name"; "Address1"; "Address2"; "City"; "Zip"; "State"; "Phone"; "Card"; "Expiry"] in if active then begin print (pre [p ["Name: "; textfield ~name:"Name" ~value:(cgi#argument_value "Name") ()]; p ["Address: "; textfield ~name:"Address1" ~value:(cgi#argument_value "Address1") ()]; p [" "; textfield ~name:"Address2" ~value:(cgi#argument_value "Address2") ()]; p ["City: "; textfield ~name:"City" ~value:(cgi#argument_value "City") ()]; p ["Zip: "; textfield ~name:"Zip" ~value:(cgi#argument_value "Zip") ()]; p ["State: "; textfield ~name:"State" ~value:(cgi#argument_value "State") ()]; p ["Phone: "; textfield ~name:"Phone" ~value:(cgi#argument_value "Phone") ()]; p ["Credit Card *: "; textfield ~name:"Card" ~value:(cgi#argument_value "Card") ()]; p ["Expiry: "; textfield ~name:"Expiry" ~value:(cgi#argument_value "Expiry") ()]]); print (p ["Click on 'Order' to order the items. "; "Click on 'Cancel' to return shopping."]); print (p [to_page "Order"; to_page "Cancel"]); end else begin List.iter (fun widget -> print (hidden ~name:widget ~value:(cgi#argument_value widget) ())) widgets end (* Page to complete an order. *) let order cgi print active = if active then begin (* you'd check credit card values here *) print (h1 ["Ordered!"]); print (p ["You have ordered the following toppings:"]); print (order_text cgi); print (p [defaults "Begin Again"]); end (* state table mapping pages to functions *) type page = Netcgi.cgi -> (string -> unit) -> bool -> unit let (states : (string * page) list) = [ "Default" => front_page; "Shirt" => shirt; "Sweater" => sweater; "Checkout" => checkout; "Card" => credit_card; "Order" => order; "Cancel" => front_page; ] let no_such_page (cgi : Netcgi.cgi) print current_screen = print ("No screen for " ^ current_screen) let process (cgi : Netcgi.cgi) = let current_screen = cgi#argument_value ~default:"Default" ".State" in let print s = cgi#out_channel#output_string s; cgi#out_channel#output_string "\n" in (* Generate the current page. *) cgi#set_header ~content_type:"text/html" (); standard_header print; if List.mem_assoc current_screen states then List.iter (fun (state, sub) -> sub cgi print (current_screen = state)) states else no_such_page cgi print current_screen; standard_footer print; cgi#out_channel#commit_work () let () = let config = Netcgi.default_config in let buffered _ ch = new Netchannels.buffered_trans_channel ch in let output_type = `Transactional buffered in if Unix.isatty Unix.stdin then Netcgi_test.run ~config ~output_type process else Netcgi_cgi.run ~config ~output_type process (* @@PLEAC@@_20.0 *) (* Libraries for HTTP clients and servers are listed at The Caml Hump: *) http://caml.inria.fr/cgi-bin/hump.en.cgi?browse=40 (* @@PLEAC@@_20.1 *) (* If you just want to read a URL as a string, Ocamlnet's "Convenience" interface to Http_client is as easy as it gets. For the more powerful general interface to Http_client, see the next example. *) #use "topfind";; #require "netclient";; open Http_client.Convenience let content = http_get url (*-----------------------------*) #!/usr/bin/ocaml (* titlebytes - find the title and size of documents *) #use "topfind";; #require "str";; #require "netclient";; let raw_url = Sys.argv.(1) let url = Neturl.parse_url raw_url let () = Printf.printf "%s =>\n\t%!" (Neturl.string_of_url url); let call = new Http_client.get (Neturl.string_of_url url) in call#set_req_header "User-Agent" "Schmozilla/v9.14 Platinum"; call#set_req_header "Referer" "http://wizard.yellowbrick.oz"; let pipeline = new Http_client.pipeline in pipeline#add call; pipeline#run (); match call#status with | `Successful -> let content = call#get_resp_body () in let bytes = String.length content in let count = ref 0 in String.iter (function '\n' -> incr count | _ -> ()) content; let regexp = Str.regexp_case_fold ".*
*)
let tag, body =
if String.length para > 0 && String.contains " \t" para.[0]
then "pre", [Nethtml.Data "\n";
Nethtml.Data para; (* indented verbatim *)
Nethtml.Data "\n"]
else "p", text2html para in (* add paragraph tag *)
write [Nethtml.Element (tag, [], body)])
paragraphs;
print_endline (Buffer.contents buffer)
(*-----------------------------*)
(* To format mail headers as a table, add the following just before
the main loop. *)
let () =
let colon_delim = Str.regexp "[ \t]*:[ \t]*" in
let continuation = Str.regexp "\n[ \t]+" in
try
let headers = Stream.next paragraphs in
let headers = Str.global_replace continuation " " headers in
let lines = Str.split (Str.regexp "\n") headers in
let rows =
List.flatten
(List.map
(fun line ->
(* parse heading *)
let key, value =
match Str.bounded_split_delim colon_delim line 2 with
| [key; value] -> key, value
| _ -> "", line in
[Nethtml.Element
("tr", [],
[Nethtml.Element
("th", ["align", "left"], [Nethtml.Data key]);
Nethtml.Element
("td", [], [Nethtml.Data value])]);
Nethtml.Data "\n"])
lines) in
write [Nethtml.Element ("table", [], Nethtml.encode rows);
Nethtml.Element ("hr", [], []);
Nethtml.Data "\n\n"]
with Stream.Failure -> ()
(* @@PLEAC@@_20.5 *)
#load "unix.cma";;
let slurp_channel channel =
let buffer_size = 4096 in
let buffer = Buffer.create buffer_size in
let string = String.create buffer_size in
let chars_read = ref 1 in
while !chars_read <> 0 do
chars_read := input channel string 0 buffer_size;
Buffer.add_substring buffer string 0 !chars_read
done;
Buffer.contents buffer
let () =
let process = Unix.open_process_in ("lynx -dump " ^ filename) in
let ascii = slurp_channel process in
ignore (Unix.close_process_in process);
(* ... *)
(* @@PLEAC@@_20.6 *)
(* Nethtml can be used to safely isolate and extract the text elements
from an HTML document. *)
#use "topfind";;
#require "netstring";;
(* Load the HTML document. *)
let channel = new Netchannels.input_channel (open_in filename)
let html = Nethtml.parse channel
let () = channel#close_in ()
(* Convert the document to plain text. *)
let plain_text =
let text = ref [] in
let rec loop html =
List.iter
(function
| Neth