File: easy_daemon.ml

package info (click to toggle)
ocamlnet 4.1.9-7
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 54,024 kB
  • sloc: ml: 151,939; ansic: 11,071; sh: 2,003; makefile: 1,310
file content (169 lines) | stat: -rw-r--r-- 4,402 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
(* A test daemon, only using the kernel *)

open Printf


let generate resp =
  printf "Generating response\n"; flush stdout;

  let h =
    new Netmime.basic_mime_header
      [ "Content-type", "text/html" ] in

  let data =
    "<html>\n" ^
    "  <head><title>Easy Daemon</title></head>\n" ^
    "  <body>\n" ^
    "    <a href='foo'>GET something</a><br>\n" ^ 
    "    <form method=POST encoding='form-data'>\n" ^
    "      <input type=hidden name=sample value='sample'>\n" ^
    "      <input type=submit value='POST something'>\n" ^
    "    </form>\n" ^
    "  </body>\n" ^
    "</html>" in

  resp # send (`Resp_status_line (200, "OK"));
  resp # send (`Resp_header h);
  resp # send (`Resp_body (data, 0, String.length data));
  resp # send `Resp_end
;;


let generate_error resp =
  printf "Generating error response\n"; flush stdout;

  let h =
    new Netmime.basic_mime_header
      [ "Content-type", "text/html" ] in

  let data =
    "<html>\n" ^
    "  <head><title>Bad Request from Easy Daemon</title></head>\n" ^
    "  <body>\n" ^
    "  Bad Request!\n" ^
    "  </body>\n" ^
    "</html>" in

  resp # send (`Resp_status_line (400, "Bad Request"));
  resp # send (`Resp_header h);
  resp # send (`Resp_body (data, 0, String.length data));
  resp # send `Resp_end;
;;

let serve fd =
  let config = Nethttpd_kernel.default_http_protocol_config in
  let proto = new Nethttpd_kernel.http_protocol config fd in

  let rec next_token () =
    if proto # recv_queue_len = 0 then (
      proto # cycle ~block:(-1.0) ();    (* block forever *)
      next_token()
    )
    else
      proto # receive() 
  in

  let cur_tok = ref ( next_token() ) in
  let cur_resp = ref None in
  while !cur_tok <> `Eof do
    ( match !cur_tok with
	| `Req_header  (((meth, uri), v), hdr, resp) ->
	    printf "Request: method = %s, uri = %s\n" meth uri;
	    flush stdout;
	    cur_resp := Some resp
	| `Req_expect_100_continue ->
	    ( match !cur_resp with
		| Some resp -> resp # send Nethttpd_kernel.resp_100_continue
		| None -> assert false
	    )
	| `Req_end ->
	    printf "Pipeline length: %d\n" proto#pipeline_len;
	    ( match !cur_resp with
		| Some resp -> generate resp
		| None -> assert false
	    );
	    cur_resp := None
	| `Fatal_error e ->
	    let name = Nethttpd_kernel.string_of_fatal_error e in
	    printf "Fatal_error: %s\n" name;
	    flush stdout;
	| `Bad_request_error (e, resp) ->
	    let name = Nethttpd_kernel.string_of_bad_request_error e in
	    printf "Bad_request_error: %s\n" name;
	    flush stdout;
	    generate_error resp
	| `Timeout ->
	    printf "Timeout\n";
	    flush stdout;
	| _ ->
	    ()
    );
    cur_tok := next_token()
  done;
  
  (* Send the remaining responses:*)
  while proto # resp_queue_len > 0 do
    proto # cycle ~block:(-1.0) ();
  done;

  proto # shutdown();

  if proto # need_linger then (
    printf "Lingering close!\n";
    flush stdout;
    let lc = new Nethttpd_kernel.lingering_close fd in
    while lc # lingering do
      lc # cycle ~block:true ()
    done
  )
  else
    Unix.close fd
;;

let start() =
  let master_sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
  Unix.setsockopt master_sock Unix.SO_REUSEADDR true;
  Unix.bind master_sock (Unix.ADDR_INET(Unix.inet_addr_any, 8765));
  Unix.listen master_sock 100;
  printf "Listening on port 8765\n";
  flush stdout;
  
  while true do
    try
      let conn_sock, _ = Unix.accept master_sock in
      Unix.set_nonblock conn_sock;
      serve conn_sock
    with
	Unix.Unix_error(Unix.EINTR,_,_) -> ()  (* ignore *)
  done
;;


let conf_debug() =
  (* Set the environment variable DEBUG to either:
       - a list of Netlog module names
       - the keyword "ALL" to output all messages
       - the keyword "LIST" to output a list of modules
     By setting DEBUG_WIN32 additional debugging for Win32 is enabled.
   *)
  let debug = try Sys.getenv "DEBUG" with Not_found -> "" in
  if debug = "ALL" then
    Netlog.Debug.enable_all()
  else if debug = "LIST" then (
    List.iter print_endline (Netlog.Debug.names());
    exit 0
  )
  else (
    let l = Netstring_str.split (Netstring_str.regexp "[ \t\r\n]+") debug in
    List.iter
      (fun m -> Netlog.Debug.enable_module m)
      l
  );
  if (try ignore(Sys.getenv "DEBUG_WIN32"); true with Not_found -> false) then
    Netsys_win32.Debug.debug_c_wrapper true
;;


Netsys_signal.init();
conf_debug();
start();;