Skip to content

Commit 8c2b682

Browse files
author
Vincent Balat
committed
Merge pull request #20 from edwintorok/put_100continue
ocsigenserver: implement "Expect: 100-continue" support
2 parents 41f780f + 6bcef78 commit 8c2b682

File tree

7 files changed

+66
-4
lines changed

7 files changed

+66
-4
lines changed

src/http/http_headers.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ let content_type = name "Content-Type"
3636
let cookie = name "Cookie"
3737
let date = name "Date"
3838
let etag = name "ETag"
39+
let expect = name "Expect"
3940
let expires = name "Expires"
4041
let host = name "Host"
4142
let if_match = name "If-Match"

src/http/http_headers.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ val content_range : name
4343
val cookie : name
4444
val date : name
4545
val etag : name
46+
val expect: name
4647
val expires : name
4748
val host : name
4849
val if_match : name

src/http/ocsigen_headers.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,16 @@ let get_cookie_string http_frame =
187187
with Not_found ->
188188
None
189189

190+
let get_expect http_frame =
191+
try
192+
String.split ',' (
193+
Http_header.get_headers_value
194+
http_frame.Ocsigen_http_frame.frame_header
195+
Http_headers.expect
196+
)
197+
with Not_found ->
198+
[]
199+
190200
let get_if_modified_since http_frame =
191201
try
192202
Some (Netdate.parse_epoch

src/http/ocsigen_headers.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ val get_host_from_host_header : Ocsigen_http_frame.t ->
3939
string option * int option
4040
val get_user_agent : Ocsigen_http_frame.t -> string
4141
val get_cookie_string : Ocsigen_http_frame.t -> string option
42+
val get_expect : Ocsigen_http_frame.t -> string list
4243
val get_if_modified_since : Ocsigen_http_frame.t -> float option
4344
val get_if_unmodified_since : Ocsigen_http_frame.t -> float option
4445
val get_if_none_match : Ocsigen_http_frame.t -> string list option

src/http/ocsigen_http_com.ml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,18 @@ let set_result_observer, observe_result =
731731
observer := (fun a b -> o a b >>= fun () -> f a b)),
732732
(fun a b -> !observer a b))
733733

734+
let send_100_continue slot =
735+
wait_previous_senders slot >>= fun () ->
736+
let out_ch = slot.sl_chan in
737+
Ocsigen_messages.debug2 "writing 100-continue";
738+
let hh = Framepp.string_of_header {
739+
H.mode = H.Answer 100;
740+
proto = H.HTTP11;
741+
headers = Http_headers.empty
742+
} in
743+
Ocsigen_messages.debug2 hh;
744+
Lwt_chan.output_string out_ch hh
745+
734746
(** Sends the HTTP frame.
735747
* The headers are merged with those of the sender, the priority
736748
* being given to the newly defined header in case of conflict.

src/http/ocsigen_http_com.mli

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ val create_sender :
8282
(** Sender with only the server name, and HTTP/1.1 *)
8383
val default_sender : sender_type
8484

85-
85+
(** send an HTTP/1.1 100 Continue message *)
86+
val send_100_continue : slot -> unit Lwt.t
8687

8788
(** send an HTTP message.
8889
[send] may also fail with [Interrupted_stream] exception if the input

src/server/ocsigen_server.ml

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,11 +234,47 @@ and find_post_params_multipart_form_data body_gen ctparams filenames ci =
234234
Ocsigen_stream.consume body_gen >>= fun () ->
235235
Lwt.return (!params, !files)
236236

237+
let wrap_stream f x frame_content =
238+
Ocsigen_stream.make ~finalize:(fun outcome ->
239+
match frame_content with
240+
| Some stream ->
241+
Ocsigen_stream.finalize stream outcome
242+
| None ->
243+
Lwt.return ()
244+
)
245+
(fun () ->
246+
f x >>= fun () ->
247+
match frame_content with
248+
| Some stream ->
249+
Ocsigen_stream.next (Ocsigen_stream.get stream)
250+
| None ->
251+
Ocsigen_stream.empty None
252+
)
237253

254+
let handle_100_continue slot frame =
255+
{ frame with
256+
frame_content = Some (wrap_stream send_100_continue slot
257+
frame.frame_content)
258+
}
259+
260+
let handle_expect slot frame =
261+
let expect_list = Ocsigen_headers.get_expect frame in
262+
let proto = Http_header.get_proto frame.frame_header in
263+
List.fold_left (fun frame tok ->
264+
match String.lowercase tok with
265+
| "100-continue" ->
266+
if proto = Http_header.HTTP11 then
267+
handle_100_continue slot frame
268+
else
269+
frame
270+
| _ ->
271+
raise (Ocsigen_http_error (Ocsigen_cookies.empty_cookieset, 417))
272+
) frame expect_list
238273

239274
(* reading the request *)
240275
let get_request_infos
241-
meth clientproto url http_frame filenames sockaddr port receiver =
276+
meth clientproto url http_frame filenames sockaddr port receiver
277+
sender_slot =
242278

243279
Lwt.catch
244280
(fun () ->
@@ -395,7 +431,7 @@ let get_request_infos
395431
ri_accept_charset = accept_charset;
396432
ri_accept_encoding = accept_encoding;
397433
ri_accept_language = accept_language;
398-
ri_http_frame = http_frame;
434+
ri_http_frame = handle_expect sender_slot http_frame;
399435
ri_request_cache = Polytables.create ();
400436
ri_client = Ocsigen_extensions.client_of_connection receiver;
401437
ri_range = lazy (Ocsigen_range.get_range http_frame);
@@ -657,7 +693,7 @@ let service receiver sender_slot request meth url port sockaddr =
657693
(fun () ->
658694
get_request_infos
659695
meth clientproto url request filenames sockaddr
660-
port receiver)
696+
port receiver sender_slot)
661697
(fun ri ->
662698
(* *** Now we generate the page and send it *)
663699
(* Log *)

0 commit comments

Comments
 (0)