Skip to content

Commit 263f5b8

Browse files
authored
Merge pull request #260 from Julow/ocsigen_response_eio
Eio-compatible representation for response Body
2 parents 06ad0a8 + 480d5e6 commit 263f5b8

File tree

11 files changed

+236
-176
lines changed

11 files changed

+236
-176
lines changed

Makefile.options

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ INCS= -I ${BLD}/server/.ocsigenserver.objs/byte \
2323
## ${SERVER_PACKAGE} is not only used to build the 'ocsigenserver' executable
2424
## but also to generate src/baselib/ocsigen_config_static.ml
2525

26-
SERVER_PACKAGE := lwt_ssl,bytes,lwt.unix,logs,logs-syslog,syslog-message,ipaddr,findlib,cryptokit,re,str,xml-light,dynlink,cohttp-lwt-unix
26+
SERVER_PACKAGE := lwt_ssl,bytes,lwt.unix,logs,logs-syslog,syslog-message,ipaddr,findlib,cryptokit,re,str,xml-light,dynlink,cohttp-lwt-unix,http
2727

2828
LIBS := -package ${SERVER_PACKAGE} ${INCS}

configure

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ check_library cohttp "See: https://github.com/mirage/ocaml-cohttp"
396396
check_library cohttp-lwt-unix "Missing support for 'lwt' in cohttp."
397397
check_library react "See: http://erratique.ch/software/react"
398398
check_library ssl "See: http://sourceforge.net/projects/savonet/files/ocaml-ssl"
399+
check_library http ""
399400

400401
check_library lwt "See: http://ocsigen.org/lwt"
401402
check_library lwt.unix "Missing support for 'unix' in lwt."

dune-project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
(camlzip (>= 1.04))
2121
(cohttp-lwt-unix (and (>= 5.0) (< 6.0)))
2222
(conduit-lwt-unix (and (>= 2.0) (< 7.0)))
23+
http
2324
cryptokit
2425
(ipaddr (>= 2.1))
2526
(lwt (>= 3.0))

ocsigenserver.opam

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ depends: [
1515
"camlzip" {>= "1.04"}
1616
"cohttp-lwt-unix" {>= "5.0" & < "6.0"}
1717
"conduit-lwt-unix" {>= "2.0" & < "7.0"}
18+
"http"
1819
"cryptokit"
1920
"ipaddr" {>= "2.1"}
2021
"lwt" {>= "3.0"}

src/extensions/deflatemod.ml

Lines changed: 59 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -59,131 +59,83 @@ let gzip_header =
5959
type output_buffer =
6060
{ stream : Zlib.stream
6161
; buf : bytes
62-
; mutable pos : int
63-
; mutable avail : int
62+
; flush : string -> unit Lwt.t
6463
; mutable size : int32
65-
; mutable crc : int32
66-
; mutable add_trailer : bool }
64+
; mutable crc : int32 }
6765

68-
let write_int32 oz n =
66+
let write_int32 buf offset n =
6967
for i = 0 to 3 do
70-
Bytes.set oz.buf (oz.pos + i)
68+
Bytes.set buf (offset + i)
7169
(Char.chr (Int32.to_int (Int32.shift_right_logical n (8 * i)) land 0xff))
72-
done;
73-
oz.pos <- oz.pos + 4;
74-
oz.avail <- oz.avail - 4;
75-
assert (oz.avail >= 0)
70+
done
7671

77-
(* puts in oz the content of buf, from pos to pos + len ;
78-
* f is the continuation of the current stream *)
79-
let rec output oz f buf pos len =
80-
assert (pos >= 0 && len >= 0 && pos + len <= String.length buf);
81-
if oz.avail = 0
82-
then (
83-
let cont () = output oz f buf pos len in
84-
Logs.info ~src:section (fun fmt ->
85-
fmt "Flushing because output buffer is full");
86-
flush oz cont)
87-
else if len = 0
88-
then next_cont oz f
72+
let compress_flush oz used_out =
73+
Logs.debug ~src:section (fun fmt -> fmt "Flushing %d bytes" used_out);
74+
if used_out > 0
75+
then oz.flush (Bytes.sub_string oz.buf 0 used_out)
76+
else Lwt.return_unit
77+
78+
(* gzip trailer *)
79+
let write_trailer oz =
80+
write_int32 oz.buf 0 oz.crc;
81+
write_int32 oz.buf 4 oz.size;
82+
compress_flush oz 8
83+
84+
(* puts in oz the content of buf, from pos to pos + len ; *)
85+
let rec compress_output oz inbuf pos len =
86+
if len = 0
87+
then Lwt.return_unit
8988
else
9089
let (_ : bool), used_in, used_out =
9190
try
92-
Zlib.deflate oz.stream
93-
(Bytes.unsafe_of_string buf)
94-
pos len oz.buf oz.pos oz.avail Zlib.Z_NO_FLUSH
91+
Zlib.deflate_string oz.stream inbuf pos len oz.buf 0
92+
(Bytes.length oz.buf) Zlib.Z_NO_FLUSH
9593
with Zlib.Error (s, s') ->
9694
raise
9795
(Ocsigen_stream.Stream_error
9896
("Error during compression: " ^ s ^ " " ^ s'))
9997
in
100-
oz.pos <- oz.pos + used_out;
101-
oz.avail <- oz.avail - used_out;
102-
oz.size <- Int32.add oz.size (Int32.of_int used_in);
103-
oz.crc <- Zlib.update_crc_string oz.crc buf pos used_in;
104-
output oz f buf (pos + used_in) (len - used_in)
98+
compress_flush oz used_out >>= fun () ->
99+
compress_output oz inbuf (pos + used_in) (len - used_in)
105100

106-
(* Flush oz, ie. produces a new_stream with the content of oz, cleans it
107-
* and returns the continuation of the stream *)
108-
and flush oz cont =
109-
let len = oz.pos in
110-
if len = 0
111-
then cont ()
112-
else
113-
let buf_len = Bytes.length oz.buf in
114-
let s =
115-
if len = buf_len
116-
then Bytes.to_string oz.buf
117-
else Bytes.sub_string oz.buf 0 len
118-
in
119-
Logs.info ~src:section (fun fmt -> fmt "Flushing!");
120-
oz.pos <- 0;
121-
oz.avail <- buf_len;
122-
Ocsigen_stream.cont s cont
123-
124-
and next_cont oz stream =
125-
Ocsigen_stream.next (stream : string Ocsigen_stream.stream) >>= fun e ->
126-
match e with
127-
| Ocsigen_stream.Finished None ->
128-
Logs.info ~src:section (fun fmt ->
129-
fmt "End of stream: big cleaning for zlib");
130-
(* loop until there is nothing left to compress and flush *)
131-
let rec finish () =
132-
(* buffer full *)
133-
if oz.avail = 0
134-
then flush oz finish
135-
else
136-
(* no more input, deflates only what were left because output buffer
137-
* was full *)
138-
let finished, (_ : int), used_out =
139-
Zlib.deflate oz.stream oz.buf 0 0 oz.buf oz.pos oz.avail
140-
Zlib.Z_FINISH
141-
in
142-
oz.pos <- oz.pos + used_out;
143-
oz.avail <- oz.avail - used_out;
144-
if not finished then finish () else write_trailer ()
145-
and write_trailer () =
146-
if oz.add_trailer && oz.avail < 8
147-
then flush oz write_trailer
148-
else (
149-
if oz.add_trailer then (write_int32 oz oz.crc; write_int32 oz oz.size);
150-
Logs.info ~src:section (fun fmt ->
151-
fmt "Zlib.deflate finished, last flush");
152-
flush oz (fun () -> Ocsigen_stream.empty None))
153-
in
154-
finish ()
155-
| Ocsigen_stream.Finished (Some s) -> next_cont oz s
156-
| Ocsigen_stream.Cont (s, f) -> output oz f s 0 (String.length s)
101+
let rec compress_finish oz =
102+
Logs.debug ~src:section (fun fmt -> fmt "Finishing");
103+
(* loop until there is nothing left to compress and flush *)
104+
let finished, (_ : int), used_out =
105+
Zlib.deflate oz.stream oz.buf 0 0 oz.buf 0 (Bytes.length oz.buf)
106+
Zlib.Z_FINISH
107+
in
108+
compress_flush oz used_out >>= fun () ->
109+
if not finished then compress_finish oz else Lwt.return_unit
157110

158111
(* deflate param : true = deflate ; false = gzip (no header in this case) *)
159-
let compress deflate stream : string Ocsigen_stream.t =
112+
let compress_body deflate body =
113+
fun flush ->
160114
let zstream = Zlib.deflate_init !compress_level deflate in
161-
let finalize status =
162-
Ocsigen_stream.finalize stream status >>= fun _e ->
163-
(try Zlib.deflate_end zstream
164-
with
165-
(* ignore errors, deflate_end cleans everything anyway *)
166-
| Zlib.Error _ ->
167-
());
168-
Lwt.return (Logs.info ~src:section (fun fmt -> fmt "Zlib stream closed"))
169-
in
170115
let oz =
171116
let buffer_size = !buffer_size in
172117
{ stream = zstream
173118
; buf = Bytes.create buffer_size
174-
; pos = 0
175-
; avail = buffer_size
119+
; flush
176120
; size = 0l
177-
; crc = 0l
178-
; add_trailer = not deflate }
121+
; crc = 0l }
179122
in
180-
let new_stream () = next_cont oz (Ocsigen_stream.get stream) in
181-
Logs.info ~src:section (fun fmt -> fmt "Zlib stream initialized");
182-
if deflate
183-
then Ocsigen_stream.make ~finalize new_stream
184-
else
185-
Ocsigen_stream.make ~finalize (fun () ->
186-
Ocsigen_stream.cont gzip_header new_stream)
123+
(if deflate then Lwt.return_unit else flush gzip_header) >>= fun () ->
124+
body (fun inbuf ->
125+
let len = String.length inbuf in
126+
oz.size <- Int32.add oz.size (Int32.of_int len);
127+
oz.crc <- Zlib.update_crc_string oz.crc inbuf 0 len;
128+
compress_output oz inbuf 0 len)
129+
>>= fun () ->
130+
compress_finish oz >>= fun () ->
131+
(if deflate then Lwt.return_unit else write_trailer oz) >>= fun () ->
132+
Logs.debug ~src:section (fun fmt -> fmt "Close stream");
133+
(try Zlib.deflate_end zstream
134+
with
135+
(* ignore errors, deflate_end cleans everything anyway *)
136+
| Zlib.Error _ ->
137+
());
138+
Lwt.return_unit
187139

188140
(* We implement Content-Encoding, not Transfer-Encoding *)
189141
type encoding = Deflate | Gzip | Id | Star | Not_acceptable
@@ -252,8 +204,8 @@ let stream_filter contentencoding url deflate choice res =
252204
match Ocsigen_header.Mime_type.parse contenttype with
253205
| None, _ | _, None -> Lwt.return res
254206
| Some a, Some b when should_compress (a, b) url choice ->
255-
let response, body = Ocsigen_response.to_cohttp res in
256207
let response =
208+
let response = Ocsigen_response.response res in
257209
let headers = Cohttp.Response.headers response in
258210
let headers =
259211
let name = Ocsigen_header.Name.(to_string etag) in
@@ -273,10 +225,10 @@ let stream_filter contentencoding url deflate choice res =
273225
Cohttp.Response.headers
274226
; Cohttp.Response.encoding = Cohttp.Transfer.Chunked }
275227
and body =
276-
Cohttp_lwt.Body.to_stream body
277-
|> Ocsigen_stream.of_lwt_stream |> compress deflate
278-
|> Ocsigen_stream.to_lwt_stream
279-
|> Cohttp_lwt.Body.of_stream
228+
Ocsigen_response.Body.make Cohttp.Transfer.Chunked
229+
(compress_body deflate
230+
(Ocsigen_response.Body.write
231+
(Ocsigen_response.body res)))
280232
in
281233
Lwt.return (Ocsigen_response.update res ~body ~response)
282234
| _ -> Lwt.return res)

src/files/ocsigenserver.conf/gen.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ let deps () =
8484
; "ocsigenserver" ]
8585
in
8686
let packages =
87-
"lwt_ssl,bytes,lwt.unix,logs,logs-syslog.unix,syslog-message,ipaddr,findlib,cryptokit,re,str,xml-light,dynlink,cohttp-lwt-unix"
87+
"lwt_ssl,bytes,lwt.unix,logs,logs-syslog.unix,syslog-message,ipaddr,findlib,cryptokit,re,str,xml-light,dynlink,cohttp-lwt-unix,http"
8888
in
8989
let deps = ref [] in
9090
let cmd = "ocamlfind query -p-format -recursive " ^ packages in

src/server/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
(libraries
66
xml-light
77
cohttp-lwt-unix
8+
http
89
polytables
910
ocsigen_cookie_map
1011
baselib

src/server/ocsigen_cohttp.ml

Lines changed: 8 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -54,32 +54,6 @@ module Cookie = struct
5454
Ocsigen_cookie_map.Map_path.fold serialize_cookies cookies headers
5555
end
5656

57-
(* FIXME: secure *)
58-
let make_cookies_header path exp name c _secure =
59-
Format.sprintf "%s=%s%s%s" name c
60-
(*VVV encode = true? *)
61-
("; path=/" ^ Ocsigen_lib.Url.string_of_url_path ~encode:true path)
62-
(* (if secure && slot.sl_ssl then "; secure" else "")^ *)
63-
""
64-
^
65-
match exp with
66-
| Some s -> "; expires=" ^ Ocsigen_lib.Date.to_string s
67-
| None -> ""
68-
69-
let make_cookies_headers path t hds =
70-
Ocsigen_cookie_map.Map_inner.fold
71-
(fun name c h ->
72-
let open Ocsigen_cookie_map in
73-
let exp, v, secure =
74-
match c with
75-
| OUnset -> Some 0., "", false
76-
| OSet (t, v, secure) -> t, v, secure
77-
in
78-
Cohttp.Header.add h
79-
Ocsigen_header.Name.(to_string set_cookie)
80-
(make_cookies_header path exp name v secure))
81-
t hds
82-
8357
let handler ~ssl ~address ~port ~connector (flow, conn) request body =
8458
let filenames = ref [] in
8559
let edn = Conduit_lwt_unix.endp_of_flow flow in
@@ -130,7 +104,7 @@ let handler ~ssl ~address ~port ~connector (flow, conn) request body =
130104
| `Not_found -> "Not Found"
131105
| _ -> Printexc.to_string exn
132106
in
133-
Cohttp_lwt_unix.Server.respond_error ?headers
107+
Ocsigen_response.respond_error ?headers
134108
~status:(ret_code :> Cohttp.Code.status_code)
135109
~body ()
136110
in
@@ -155,32 +129,18 @@ let handler ~ssl ~address ~port ~connector (flow, conn) request body =
155129
Ocsigen_header.Name.x_forwarded_for))
156130
(Uri.path (Ocsigen_request.uri request)));
157131
Lwt.catch
158-
(fun () ->
159-
connector request >>= fun response ->
160-
let response, body = Ocsigen_response.to_cohttp response
161-
and cookies = Ocsigen_response.cookies response in
162-
let response =
163-
let headers =
164-
Cohttp.Header.add_unless_exists
165-
(Cohttp.Header.add_unless_exists
166-
(Ocsigen_cookie_map.Map_path.fold make_cookies_headers
167-
cookies
168-
(Cohttp.Response.headers response))
169-
"server" Ocsigen_config.server_name)
170-
"date"
171-
(Ocsigen_lib.Date.to_string (Unix.time ()))
172-
in
173-
{response with Cohttp.Response.headers}
174-
in
175-
Lwt.return (response, body))
132+
(fun () -> connector request)
176133
(function
177134
| Ocsigen_is_dir fun_request ->
178135
let headers =
179136
fun_request request |> Uri.to_string
180137
|> Cohttp.Header.init_with "location"
181138
and status = `Moved_permanently in
182-
Cohttp_lwt_unix.Server.respond ~headers ~status ~body:`Empty ()
183-
| exn -> handle_error exn))
139+
Lwt.return
140+
(Ocsigen_response.respond_string ~headers ~status ~body:"" ())
141+
| exn -> Lwt.return (handle_error exn))
142+
>>= fun response ->
143+
Lwt.return (Ocsigen_response.to_response_expert response))
184144
(fun () ->
185145
if !filenames <> []
186146
then
@@ -236,7 +196,7 @@ let service ?ssl ~address ~port ~connector () =
236196
let ssl = match ssl with Some _ -> true | None -> false in
237197
handler ~ssl ~address ~port ~connector
238198
in
239-
let config = Cohttp_lwt_unix.Server.make ~conn_closed ~callback () in
199+
let config = Cohttp_lwt_unix.Server.make_expert ~conn_closed ~callback () in
240200
let mode =
241201
match address, tls_own_key with
242202
| `Unix f, _ -> `Unix_domain_socket (`File f)

0 commit comments

Comments
 (0)