File: easy_daemon.ml

package info (click to toggle)
ocamlnet 2.2.9-8
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 17,724 kB
  • ctags: 10,053
  • sloc: ml: 63,928; ansic: 1,973; makefile: 800; sh: 651
file content (160 lines) | stat: -rw-r--r-- 4,187 bytes parent folder | download | duplicates (2)
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
(* 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;
;;

class config 
        ?(max_reqline_length = 256)
        ?(max_header_length = 32768)
        ?(max_trailer_length = 32768)
        ?(limit_pipeline_length = 5)
        ?(limit_pipeline_size = max_int)
        () : Nethttpd_kernel.http_protocol_config =
object
  method config_max_reqline_length = max_reqline_length
  method config_max_header_length = max_header_length
  method config_max_trailer_length = max_trailer_length
  method config_limit_pipeline_length = limit_pipeline_length
  method config_limit_pipeline_size = limit_pipeline_size
  method config_announce_server = `Ocamlnet
end
;;

let serve fd =
  let config = new 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
;;


Sys.set_signal Sys.sigpipe Sys.Signal_ignore;
start();;