patch #7372
[mldonkey.git] / src / networks / openFT / openFTProtocol.ml
blob9ac1c1888433f4a05b5a376757da2d6aed3a19d3
1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
2 (*
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 open Md4
22 open OpenFTTypes
23 open CommonGlobals
24 open BigEndian
25 open TcpBufferedSocket
27 let buf_ip buf ip=
28 buf_int16 buf 4;
29 LittleEndian.buf_ip buf ip;
30 buf_int buf 0;
31 buf_int buf 0;
32 buf_int buf 0
34 let get_string s pos =
35 try
36 let end_pos = String.index_from s pos '\000' in
37 String.sub s pos (end_pos - pos), end_pos+1
38 with _ ->
39 lprintf "No ending zero !!!"; lprint_newline ();
40 let len = String.length s in
41 String.sub s pos (len - pos), len
43 let buf_string buf s =
44 Buffer.add_string buf s;
45 buf_int8 buf 0
49 module Empty = functor(M: sig val msg : string end) ->
50 struct
52 let parse s = ()
54 let print t =
55 lprintf "message %s" M.msg
57 let write buf t = ()
59 end
61 module NotImplemented = functor(M: sig val msg : string end) ->
62 struct
64 type t
66 let parse s =
67 lprintf "PARSE FOR Message %s not implemented" M.msg;
68 lprint_newline ();
69 assert false
71 let print t =
72 lprintf "message %s" M.msg
74 let write buf t =
75 lprintf "WRITE FOR Message %s not implemented" M.msg;
76 lprint_newline ();
77 assert false
78 end
80 module VersionReply = struct
81 type t = {
82 major_num : int;
83 minor_num : int;
84 micro_num : int;
87 let parse s =
88 let major_num = get_int16 s 0 in
89 let minor_num = get_int16 s 2 in
90 let micro_num = get_int16 s 4 in
91 { major_num = major_num; minor_num = minor_num; micro_num = micro_num }
93 let print t =
94 lprintf "VersionReply %d.%d.%d" t.major_num t.minor_num t.micro_num
96 let write buf t =
97 buf_int16 buf t.major_num;
98 buf_int16 buf t.minor_num;
99 buf_int16 buf t.micro_num
103 module NodeInfoReply = struct
104 type t = {
105 ip : Ip.t;
106 port : int;
107 http_port : int;
110 let parse s =
111 let ip = LittleEndian.get_ip s 2 in
112 let port = get_int16 s 18 in
113 let http_port = get_int16 s 20 in
115 ip = ip;
116 port = port;
117 http_port = http_port;
120 let print t =
121 lprintf "NodeInfoReply %s:%d (http:%d)"
122 (Ip.to_string t.ip) t.port t.http_port
124 let write buf t =
125 buf_ip buf t.ip;
126 buf_int16 buf t.port;
127 buf_int16 buf t.http_port
131 let string_of_node_type t = match t with
132 User_node -> "User_node"
133 | Search_node -> "Search_node"
134 | Index_node -> "Index_node"
136 module NodeListReply = struct
137 type node = {
138 ip : Ip.t;
139 port : int;
140 node_type : node_type;
143 type t = node option
145 let parse s =
146 if s = "" then None else
147 let ip = LittleEndian.get_ip s 2 in
148 let port = get_int16 s 18 in
149 let node_type = get_int16 s 20 in
150 let node_type =
151 if node_type land 2 <> 0 then Search_node else
152 if node_type land 4 <> 0 then Index_node else User_node
154 Some {
155 ip = ip;
156 port = port;
157 node_type = node_type;
160 let print t =
161 match t with
162 None -> lprintf "NodeListReply"
163 | Some t ->
164 lprintf "NodeInfoReply %s:%d type %s"
165 (Ip.to_string t.ip) t.port
166 (string_of_node_type t.node_type)
168 let write buf t =
169 match t with
170 None -> ()
171 | Some t ->
172 buf_ip buf t.ip;
173 buf_int16 buf t.port;
174 buf_int16 buf (match t.node_type with
175 User_node -> 1
176 | Search_node -> 2
177 | Index_node -> 3)
181 module ClassReply = struct
183 type t = node_type
185 let parse s =
186 let node_type = get_int16 s 0 in
187 let node_type =
188 if node_type land 2 <> 0 then Search_node else
189 if node_type land 4 <> 0 then Index_node else User_node
191 node_type
193 let print t =
194 lprintf "ClassReply %s"
195 (string_of_node_type t)
197 let write buf t =
198 buf_int16 buf (match t with
199 User_node -> 1
200 | Search_node -> 2
201 | Index_node -> 3)
206 module NodeCapReply = struct
207 type t = string list
209 let parse s =
210 let len = String.length s in
211 let rec iter pos =
212 let ok = get_int16 s pos in
213 if ok <> 0 then
214 let s, pos = get_string s (pos+2) in
215 s :: (iter pos)
216 else
219 iter 0
221 let print t=
222 lprintf "NodeCapReply:"; lprint_newline ();
223 List.iter (fun s -> lprintf "%s " s) t
225 let write buf t =
226 List.iter (fun s ->
227 buf_int16 buf 1;
228 buf_string buf s
229 ) t;
230 buf_int16 buf 0
234 module Child = struct
235 type t = bool option
237 let parse s =
238 if s = "" then None else
239 Some (get_int16 s 0 = 1)
241 let print t =
242 lprintf "Child %s"
243 (match t with None -> "" | Some true -> "OK" | _ -> "NO")
245 let write buf t =
246 match t with
247 None -> ()
248 | Some true -> buf_int16 buf 1
249 | Some false -> buf_int16 buf 0
252 module ChildReply = struct
253 type t = bool
255 let parse s =
256 get_int16 s 0 = 1
258 let print t =
259 lprintf "ChildReply %s"
260 (match t with true -> "OK" | _ -> "NO")
262 let write buf t =
263 match t with
264 | true -> buf_int16 buf 1
265 | false -> buf_int16 buf 0
269 Sending on FileDescr 19 (len 512): FT_STATS_REQUEST
270 (0)(2) len
271 (0)(106) opcode
272 (0)(1) /* retrieve info */ 2 = (submit digest)
275 module Stats = struct
276 type t = Retrieve_info | Submit_digest
278 let parse s =
279 match get_int16 s 0 with
280 2 -> Submit_digest
281 | _ -> Retrieve_info
283 let print t =
284 lprintf "Stats %s"
285 (match t with
286 Submit_digest -> "Submit_digest"
287 | _ -> "Retrieve_info")
289 let write buf t =
290 match t with
291 | Retrieve_info -> buf_int16 buf 1
292 | Submit_digest -> buf_int16 buf 2
296 Received from FileDescr 19 (len 12): FT_STATS_RESPONSE
297 Command : 107
298 dec:[
299 (0)(0)(1)(114) USERS
300 (0)(6)(73)(-76) SHARES
301 (0)(0)(12)(20) SIZE (MB)
305 module StatsReply = struct
306 type t = {
307 nusers : int;
308 nfiles : int;
309 size : int;
312 let parse s =
313 let nusers = get_int16 s 0 in
314 let nfiles = get_int16 s 2 in
315 let size = get_int16 s 4 in
316 { nusers = nusers; nfiles = nfiles; size = size }
318 let print t =
319 lprintf "StatsReply %d.%d.%d" t.nusers t.nfiles t.size
321 let write buf t =
322 buf_int16 buf t.nusers;
323 buf_int16 buf t.nfiles;
324 buf_int16 buf t.size
330 (* SEARCH *)
332 int32 : id
333 int16 : type SEARCH_HIDDEN | SEARCH_MD5 | SEARCH_HOST
335 type: SEARCH_HIDDEN
336 query: get_array 4
337 exclude : ge_array 2
338 query_str : "*hidden*"
339 exclude_str : ""
340 else
341 query : str
342 exclude : str
345 realm : str
346 size_min : int32
347 size_max : int32
348 kbps_min : int32
349 kbps_max : int32
352 Search 2 for [mp3] without []
353 ascii: [(0)(28)(0) l(0)(0)(0)(2)(0)(1) m p 3(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)]
354 dec: [(0)(28)(0)(108)(0)(0)(0)(2)(0)(1)(109)(112)(51)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)]
355 SENDING:
356 Search 2 for [mp3] without []
357 ascii: [(0)(28)(0) l(0)(0)(0)(2)(0)(1) m p 3(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)]
358 dec: [
359 (0)(28)(0)(108)(0)(0)(0)(2)(0)(1)(109)(112)(51)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)(0)]
362 dec:[
363 (0)(31)
364 (0)(200)
365 (0)(0)(0)(6) id
366 (0)(1) type
367 (106)(111)(104)(110)(110)(121)(0) johnny
368 (0) exclude
369 (0) realm
370 (0)(0)(0)(0) size_min
371 (0)(0)(0)(0) size_max
372 (0)(0)(0)(0) kbps_min
373 (0)(0)(0)(0) kbps_max
376 SEARCH_FILENAME = 0x01,
377 SEARCH_MD5 = 0x02,
378 SEARCH_HOST = 0x04,
379 SEARCH_LOCAL = 0x08,
380 SEARCH_HIDDEN = 0x10 /* the HIDDEN flag indicates that the human
381 * readable search string will be substituted
382 * by the hashed/tokenized query...this is up to
383 * the implementation how paranoid they wish to
384 * be ;) */
385 return;
388 module Search = struct
390 type search_type =
391 Search_filename
392 | Search_md5
393 | Search_host
394 | Search_local
395 | Search_hidden
397 type t = {
398 id : int;
399 search_type : search_type;
400 words : string;
401 exclude : string;
402 realm : string;
403 size_min : int64;
404 size_max : int64;
405 kbps_min : int64;
406 kbps_max : int64;
409 let parse s =
410 let id = get_int s 0 in
411 let stype = match get_int16 s 4 with
412 1 -> Search_filename
413 | 2 -> Search_md5
414 | 3 -> Search_host
415 | 4 -> Search_local
416 | _ -> Search_hidden
418 if stype = Search_hidden then assert false;
419 let words, pos = get_string s 6 in
420 let exclude, pos = get_string s pos in
421 let realm, pos = get_string s pos in
422 let size_min = get_int64_32 s pos in
423 let size_max = get_int64_32 s (pos+4) in
424 let kbps_min = get_int64_32 s (pos+8) in
425 let kbps_max = get_int64_32 s (pos+12) in
427 id = id;
428 search_type = stype;
429 words = words;
430 exclude = exclude;
431 realm = realm;
432 size_min = size_min;
433 size_max = size_max;
434 kbps_min = kbps_min;
435 kbps_max = kbps_max;
438 let print t =
439 lprintf "Search %d for [%s] without [%s]"
440 t.id t.words t.exclude
442 let write buf t =
443 buf_int buf t.id;
444 buf_int16 buf (match t.search_type with
445 Search_filename -> 1
446 | Search_md5 -> 2
447 | Search_host -> 3
448 | Search_local -> 4
449 | Search_hidden -> 5);
450 buf_string buf t.words;
451 buf_string buf t.exclude;
452 buf_string buf t.realm;
453 buf_int64_32 buf t.size_min;
454 buf_int64_32 buf t.size_max;
455 buf_int64_32 buf t.kbps_min;
456 buf_int64_32 buf t.kbps_max
460 module SearchReply = struct
461 type t = {
462 id : int;
463 ip : Ip.t;
464 port : int;
465 http_port : int;
466 avail : int;
467 size : int64;
468 md5 : Md4.t;
469 filename : string;
472 let parse s =
473 let id = get_int s 0 in
474 let ip = LittleEndian.get_ip s 6 in
475 let port = get_int16 s 22 in
476 let http_port = get_int16 s 24 in
477 let avail = get_int s 26 in
478 let size = get_int64_32 s 30 in
479 let md5,pos = get_string s 34 in
480 let filename, pos = get_string s pos in
482 id = id;
483 ip = ip;
484 port = port;
485 http_port = http_port;
486 avail = avail;
487 size = size;
488 md5 = Md4.of_string md5;
489 filename = filename
492 let print t =
493 lprintf "SearchReply for %d : %s size %Ld"
494 t.id t.filename t.size
496 let write buf t =
497 buf_int buf t.id;
498 buf_ip buf t.ip;
499 buf_int16 buf t.port;
500 buf_int16 buf t.http_port;
501 buf_int buf t.avail;
502 buf_int64_32 buf t.size;
503 buf_string buf (String.lowercase (Md4.to_string t.md5));
504 buf_string buf t.filename
508 module Share = NotImplemented(struct let msg = "Share" end)
509 module ShareReply = NotImplemented(struct let msg = "ShareReply" end)
510 module ModShare = NotImplemented(struct let msg = "ModShare" end)
511 module ModShareReply = NotImplemented(struct let msg = "ModShareReply" end)
513 module Push = NotImplemented(struct let msg = "Push" end)
514 module PushReply = NotImplemented(struct let msg = "PushReply" end)
516 type t =
517 VersionReq
518 | VersionReplyReq of VersionReply.t
519 | ClassReq
520 | ClassReplyReq of ClassReply.t
521 | NodeInfoReq
522 | NodeInfoReplyReq of NodeInfoReply.t
523 | NodeListReq
524 | NodeListReplyReq of NodeListReply.t
525 | NodeCapReq
526 | NodeCapReplyReq of NodeCapReply.t
527 | PingReq
528 | PingReplyReq
530 | ChildReq of Child.t
531 | ChildReplyReq of ChildReply.t
532 | ShareReq of Share.t
533 | ShareReplyReq of ShareReply.t
534 | ModShareReq of ModShare.t
535 | ModShareReplyReq of ModShareReply.t
536 | StatsReq of Stats.t
537 | StatsReplyReq of StatsReply.t
539 | SearchReq of Search.t
540 | SearchReplyReq of SearchReply.t
542 | PushReq of Push.t
543 | PushReplyReq of PushReply.t
545 | UnknownReq of int * string
547 let parse opcode s =
549 match opcode with
550 0 -> VersionReq
551 | 1 -> VersionReplyReq (VersionReply.parse s)
552 | 2 -> ClassReq
553 | 3 -> ClassReplyReq (ClassReply.parse s)
554 | 4 -> NodeInfoReq
555 | 5 -> NodeInfoReplyReq (NodeInfoReply.parse s)
556 | 6 -> NodeListReq
557 | 7 -> NodeListReplyReq (NodeListReply.parse s)
558 | 8 -> NodeCapReq
559 | 9 -> NodeCapReplyReq (NodeCapReply.parse s)
560 | 10 -> PingReq
561 | 11 -> PingReplyReq
563 | 100 -> ChildReq (Child.parse s)
564 | 101 -> ChildReplyReq (ChildReply.parse s)
565 | 102 -> ShareReq (Share.parse s)
566 | 103 -> ShareReplyReq (ShareReply.parse s)
567 | 104 -> ModShareReq (ModShare.parse s)
568 | 105 -> ModShareReplyReq (ModShareReply.parse s)
569 | 106 -> StatsReq (Stats.parse s)
570 | 107 -> StatsReplyReq (StatsReply.parse s)
572 | 200 -> SearchReq (Search.parse s)
573 | 201 -> SearchReplyReq (SearchReply.parse s)
575 | 300 -> PushReq (Push.parse s)
576 | 301 -> PushReplyReq (PushReply.parse s)
577 | _ -> raise Not_found
579 with e ->
580 lprintf "Exception in parse (OPCODE %d): %s" opcode (Printexc2.to_string e);
581 lprint_newline ();
582 LittleEndian.dump s;
583 UnknownReq (opcode, s)
585 let write buf t =
586 match t with
587 VersionReq -> buf_int16 buf 0
588 | VersionReplyReq t -> buf_int16 buf 1; VersionReply.write buf t
589 | ClassReq -> buf_int16 buf 2
590 | ClassReplyReq t -> buf_int16 buf 3; ClassReply.write buf t
591 | NodeInfoReq -> buf_int16 buf 4
592 | NodeInfoReplyReq t -> buf_int16 buf 5; NodeInfoReply.write buf t
593 | NodeListReq -> buf_int16 buf 6
594 | NodeListReplyReq t -> buf_int16 buf 7; NodeListReply.write buf t
595 | NodeCapReq -> buf_int16 buf 8
596 | NodeCapReplyReq t -> buf_int16 buf 9; NodeCapReply.write buf t
597 | PingReq -> buf_int16 buf 10
598 | PingReplyReq -> buf_int16 buf 11
600 | ChildReq t -> buf_int16 buf 100; Child.write buf t
601 | ChildReplyReq t -> buf_int16 buf 101; ChildReply.write buf t
602 | ShareReq t -> buf_int16 buf 102; Share.write buf t
603 | ShareReplyReq t -> buf_int16 buf 103; ShareReply.write buf t
604 | ModShareReq t -> buf_int16 buf 104; ModShare.write buf t
605 | ModShareReplyReq t -> buf_int16 buf 105; ModShareReply.write buf t
606 | StatsReq t -> buf_int16 buf 106; Stats.write buf t
607 | StatsReplyReq t -> buf_int16 buf 107; StatsReply.write buf t
609 | SearchReq t -> buf_int16 buf 200; Search.write buf t
610 | SearchReplyReq t -> buf_int16 buf 201; SearchReply.write buf t
612 | PushReq t -> buf_int16 buf 300; Push.write buf t
613 | PushReplyReq t -> buf_int16 buf 301; PushReply.write buf t
615 | UnknownReq (opcode, s) -> buf_int16 buf opcode; Buffer.add_string buf s
618 let print t =
619 begin
620 match t with
621 VersionReq -> lprintf "VersionReq"
622 | VersionReplyReq t -> VersionReply.print t
623 | ClassReq -> lprintf "ClassReq"
624 | ClassReplyReq t -> ClassReply.print t
625 | NodeInfoReq -> lprintf "NodeInfoReq"
626 | NodeInfoReplyReq t -> NodeInfoReply.print t
627 | NodeListReq -> lprintf "NodeListReq"
628 | NodeListReplyReq t -> NodeListReply.print t
629 | NodeCapReq -> lprintf "NodeCapReq"
630 | NodeCapReplyReq t -> NodeCapReply.print t
631 | PingReq -> lprintf "PingReq"
632 | PingReplyReq -> lprintf "PingReplyReq"
634 | ChildReq t -> Child.print t
635 | ChildReplyReq t -> ChildReply.print t
636 | ShareReq t -> Share.print t
637 | ShareReplyReq t -> ShareReply.print t
638 | ModShareReq t -> ModShare.print t
639 | ModShareReplyReq t -> ModShareReply.print t
640 | StatsReq t -> Stats.print t
641 | StatsReplyReq t -> StatsReply.print t
643 | SearchReq t -> Search.print t
644 | SearchReplyReq t -> SearchReply.print t
646 | PushReq t -> Push.print t
647 | PushReplyReq t -> PushReply.print t
649 | UnknownReq (opcode,s) ->
650 lprintf "UNKNOWN %d" opcode; lprint_newline ();
651 LittleEndian.dump s
652 end;
653 lprint_newline ()
655 let buf = Buffer.create 1000
657 let server_msg_to_string t =
658 Buffer.reset buf;
659 buf_int16 buf 0;
660 write buf t;
661 let s = Buffer.contents buf in
662 let len = String.length s - 4 in
663 str_int16 s 0 len;
667 let server_send sock t =
669 lprintf "SENDING:"; lprint_newline ();
670 print t;
672 let s = server_msg_to_string t in
673 (* LittleEndian.dump s;*)
674 write_string sock s
676 let cut_messages parse f sock nread =
677 let b = TcpBufferedSocket.buf sock in
679 while b.len >= 4 do
680 let msg_len = get_int16 b.buf b.pos in
681 if b.len >= 4 + msg_len then
682 begin
683 let opcode = get_int16 b.buf (b.pos+2) in
684 let s = String.sub b.buf (b.pos+4) msg_len in
685 TcpBufferedSocket.buf_used sock (msg_len + 4);
686 let t = parse opcode s in
687 f t sock
689 else raise Not_found
690 done
691 with Not_found -> ()
695 let write buf t =
696 match t with
697 | PingReq t -> Ping.write buf t
698 | PongReq t -> Pong.write buf t
699 | PushReq t -> Push.write buf t
700 | QueryReq t -> Query.write buf t
701 | QueryReplyReq t -> QueryReply.write buf t
702 | UnknownReq (i,s) -> Buffer.add_string buf s
704 let print p =
705 match p.pkt_payload with
706 | PingReq t -> Ping.print t
707 | PongReq t -> Pong.print t
708 | PushReq t -> Push.print t
709 | QueryReq t -> Query.print t
710 | QueryReplyReq t -> QueryReply.print t
711 | UnknownReq (i,s) ->
712 lprintf "UNKNOWN message:"; lprint_newline ();
713 dump s
715 let buf = Buffer.create 1000
717 let server_msg_to_string pkt =
718 Buffer.reset buf;
719 buf_md4 buf pkt.pkt_uid;
720 buf_int8 buf (match pkt.pkt_type with
721 PING -> 0
722 | PONG -> 1
723 | PUSH -> 64
724 | QUERY -> 128
725 | QUERY_REPLY -> 129
726 | UNKNOWN i -> i);
727 buf_int8 buf pkt.pkt_ttl;
728 buf_int8 buf pkt.pkt_hops;
729 buf_int buf 0;
730 write buf pkt.pkt_payload;
731 let s = Buffer.contents buf in
732 let len = String.length s - 23 in
733 str_int s 19 len;
736 let new_packet t =
738 pkt_uid = Md4.random ();
739 pkt_type = (match t with
740 PingReq _ -> PING
741 | PongReq _ -> PONG
742 | PushReq _ -> PUSH
743 | QueryReq _ -> QUERY
744 | QueryReplyReq _ -> QUERY_REPLY
745 | UnknownReq (i,_) -> i);
746 pkt_ttl = 7;
747 pkt_hops = 0;
748 pkt_payload =t;
751 let server_send_new sock t =
752 write_string sock (server_msg_to_string (new_packet t))
754 let gnutella_handler parse f sock nread =
755 let b = TcpBufferedSocket.buf sock in
756 (* lprintf "GNUTELLA HANDLER"; lprint_newline ();
757 dump (String.sub b.buf b.pos b.len);
760 while b.len >= 23 do
761 let msg_len = get_int b.buf (b.pos+19) in
762 if b.len >= 23 + msg_len then
763 begin
764 let pkt_uid = get_md4 b.buf b.pos in
765 let pkt_type = match get_int8 b.buf (b.pos+16) with
766 0 -> PING
767 | 1 -> PONG
768 | 64 -> PUSH
769 | 128 -> QUERY
770 | 129 -> QUERY_REPLY
771 | n -> UNKNOWN n
773 let pkt_ttl = get_int8 b.buf (b.pos+17) in
774 let pkt_hops = get_int8 b.buf (b.pos+18) in
775 let data = String.sub b.buf (b.pos+23) msg_len in
776 TcpBufferedSocket.buf_used sock (msg_len + 23);
777 let pkt = {
778 pkt_uid = pkt_uid;
779 pkt_type = pkt_type;
780 pkt_ttl = pkt_ttl;
781 pkt_hops = pkt_hops;
782 pkt_payload = data;
783 } in
784 let pkt = parse pkt in
785 f pkt sock
787 else raise Not_found
788 done
789 with
790 | Not_found -> ()
793 let handler info header_handler body_handler =
794 let header_done = ref false in
795 fun sock nread ->
797 let b = TcpBufferedSocket.buf sock in
798 if !header_done then body_handler sock nread else
799 let end_pos = b.pos + b.len in
800 let begin_pos = max b.pos (end_pos - nread - 3) in
801 let rec iter i n_read =
802 if i < end_pos then
803 if b.buf.[i] = '\r' then
804 iter (i+1) n_read
805 else
806 if b.buf.[i] = '\n' then
807 if n_read then begin
808 let header = String.sub b.buf b.pos (i - b.pos) in
810 if info > 10 then begin
811 lprintf "HEADER : ";
812 LittleEndian.dump header; lprint_newline ();
813 end;
814 header_done := true;
816 header_handler sock header;
817 let nused = i - b.pos + 1 in
818 buf_used sock nused;
819 if nread - nused > 20 then begin
821 lprintf "BEGINNING OF BLOC (6 bytes from header)";
822 lprint_newline ();
823 dump (String.sub b.buf (b.pos-6) (min 20 (b.len - b.pos + 6)));
824 lprintf "LEFT %d" (nread - nused); lprint_newline ();
827 end;
828 body_handler sock (nread - nused)
829 end else
830 iter (i+1) true
831 else
832 iter (i+1) false
833 else begin
834 if info > 0 then (
835 lprintf "END OF HEADER WITHOUT END"; lprint_newline ();
836 let header = String.sub b.buf b.pos b.len in
837 LittleEndian.dump header;
841 iter begin_pos false
842 with e ->
843 lprintf "Exception %s in handler" (Printexc2.to_string e);
844 lprint_newline ();
845 raise e
847 let handlers header_handlers body_handler =
848 let headers = ref header_handlers in
849 let rec iter_read sock nread =
850 let b = TcpBufferedSocket.buf sock in
851 match !headers with
852 [] -> body_handler sock nread
853 | header_handler :: tail ->
854 let end_pos = b.pos + b.len in
855 let begin_pos = max b.pos (end_pos - nread - 3) in
856 let rec iter i n_read =
857 if i < end_pos then
858 if b.buf.[i] = '\r' then
859 iter (i+1) n_read
860 else
861 if b.buf.[i] = '\n' then
862 if n_read then begin
863 let header = String.sub b.buf b.pos (i - b.pos) in
865 lprintf "HEADER : ";
866 dump header; lprint_newline ();
868 headers := tail;
869 header_handler sock header;
870 let nused = i - b.pos + 1 in
871 buf_used sock nused;
872 iter_read sock (nread - nused)
873 end else
874 iter (i+1) true
875 else
876 iter (i+1) false
878 iter begin_pos false
880 iter_read