refactor: modify API

This commit is contained in:
Simon Cruanes 2019-11-17 11:37:42 -06:00
parent 2e66a92e68
commit 6b4deb55f9
3 changed files with 28 additions and 18 deletions

View file

@ -159,7 +159,7 @@ module Request = struct
in in
let meth = Meth.of_string meth in let meth = Meth.of_string meth in
let headers = Headers.parse_ is in let headers = Headers.parse_ is in
debug_ (fun k->k "got meth: %s" (Meth.to_string meth)); debug_ (fun k->k "got meth: %s, path %S" (Meth.to_string meth) path);
Ok (Some {meth; path; headers; body=""}) Ok (Some {meth; path; headers; body=""})
with with
| End_of_file | Sys_error _ -> Ok None | End_of_file | Sys_error _ -> Ok None
@ -199,16 +199,20 @@ module Response = struct
(* TODO: if query had ["Accept-Encoding", "chunked"], we cna reply with chunks, (* TODO: if query had ["Accept-Encoding", "chunked"], we cna reply with chunks,
if [body] was a stream|string instead of just a string *) if [body] was a stream|string instead of just a string *)
let make ?(headers=[]) ~code body : t = let make_raw ?(headers=[]) ~code body : t =
(* add content length to response *) (* add content length to response *)
let headers = let headers =
Headers.set "Content-Length" (string_of_int (String.length body)) headers Headers.set "Content-Length" (string_of_int (String.length body)) headers
in in
{ code; headers; body; } { code; headers; body; }
let make_ok ?headers body = make ~code:200 ?headers body let make ?headers r : t = match r with
let make_not_found ?headers body = make ~code:404 ?headers body | Ok body -> make_raw ?headers ~code:200 body
let make_error ?headers body = make ~code:500 ?headers body | Error (code,msg) ->
make_raw ?headers ~code msg
let fail ?headers ~code fmt =
Printf.ksprintf (fun msg -> make_raw ?headers ~code msg) fmt
let pp out self : unit = let pp out self : unit =
Format.fprintf out "{@[code=%d;@ headers=%a;@ body=%S@]}" Format.fprintf out "{@[code=%d;@ headers=%a;@ body=%S@]}"
@ -257,7 +261,7 @@ let create
?(masksigpipe=true) ?(masksigpipe=true)
?(fork=(fun f -> ignore (Thread.create f () : Thread.t))) ?(fork=(fun f -> ignore (Thread.create f () : Thread.t)))
?(addr="127.0.0.1") ?(port=8080) () : t = ?(addr="127.0.0.1") ?(port=8080) () : t =
let handler _req = Response.make_not_found "no top handler" in let handler _req = Response.fail ~code:404 "no top handler" in
{ fork; addr; port; masksigpipe; handler; running= true; { fork; addr; port; masksigpipe; handler; running= true;
path_handlers=[]; path_handlers=[];
req_cbs=[]; res_cbs=[]; req_cbs=[]; res_cbs=[];
@ -287,7 +291,7 @@ let handle_client_ (self:t) (client_sock:Unix.file_descr) : unit =
match Request.parse_req_start is with match Request.parse_req_start is with
| Ok None -> continue := false | Ok None -> continue := false
| Error (c,s) -> | Error (c,s) ->
let res = Response.make ~code:c s in let res = Response.make_raw ~code:c s in
Response.output_ oc res Response.output_ oc res
| Ok (Some req) -> | Ok (Some req) ->
let res = let res =
@ -296,7 +300,7 @@ let handle_client_ (self:t) (client_sock:Unix.file_descr) : unit =
begin match List.assoc "Expect" req.Request.headers with begin match List.assoc "Expect" req.Request.headers with
| "100-continue" -> | "100-continue" ->
debug_ (fun k->k "send back: 100 CONTINUE"); debug_ (fun k->k "send back: 100 CONTINUE");
Response.output_ oc (Response.make ~code:100 ""); Response.output_ oc (Response.make_raw ~code:100 "");
| s -> bad_reqf 417 "unknown expectation %s" s | s -> bad_reqf 417 "unknown expectation %s" s
| exception Not_found -> () | exception Not_found -> ()
end; end;
@ -320,11 +324,11 @@ let handle_client_ (self:t) (client_sock:Unix.file_descr) : unit =
resp self.res_cbs resp self.res_cbs
with with
| e -> | e ->
Response.make ~code:500 ("server error: " ^ Printexc.to_string e) Response.fail ~code:500 "server error: %s" (Printexc.to_string e)
in in
Response.output_ oc res Response.output_ oc res
| exception Bad_req (code,s) -> | exception Bad_req (code,s) ->
Response.output_ oc (Response.make ~code s); Response.output_ oc (Response.make_raw ~code s);
continue := false continue := false
| exception Sys_error _ -> | exception Sys_error _ ->
continue := false; (* connection broken somehow *) continue := false; (* connection broken somehow *)

View file

@ -44,15 +44,21 @@ end
module Response : sig module Response : sig
type t type t
val make : val make_raw :
?headers:Headers.t -> ?headers:Headers.t ->
code:Response_code.t -> code:Response_code.t ->
string -> string ->
t t
val make_ok : ?headers:Headers.t -> string -> t val make :
val make_not_found : ?headers:Headers.t -> string -> t ?headers:Headers.t ->
val make_error : ?headers:Headers.t -> string -> t (string, Response_code.t * string) result -> t
val fail : ?headers:Headers.t -> code:int ->
('a, unit, string, t) format4 -> 'a
(** Make the current request fail with the given code and message.
Example: [fail ~code:404 "oh noes, %s not found" "waldo"]
*)
val pp : Format.formatter -> t -> unit val pp : Format.formatter -> t -> unit
end end

View file

@ -10,10 +10,10 @@ let () =
let server = S.create () in let server = S.create () in
(* say hello *) (* say hello *)
S.add_path_handler ~meth:`GET server S.add_path_handler ~meth:`GET server
"/hello/%s@/" (fun _req name () -> S.Response.make_ok ("hello " ^name ^"!\n")); "/hello/%s@/" (fun _req name () -> S.Response.make (Ok ("hello " ^name ^"!\n")));
(* echo request *) (* echo request *)
S.add_path_handler server S.add_path_handler server
"/echo" (fun req () -> S.Response.make_ok (Format.asprintf "echo:@ %a@." S.Request.pp req)); "/echo" (fun req () -> S.Response.make (Ok (Format.asprintf "echo:@ %a@." S.Request.pp req)));
S.add_path_handler ~meth:`PUT server S.add_path_handler ~meth:`PUT server
"/upload/%s" (fun req path () -> "/upload/%s" (fun req path () ->
debug_ (fun k->k "start upload %S\n%!" path); debug_ (fun k->k "start upload %S\n%!" path);
@ -21,9 +21,9 @@ let () =
let oc = open_out @@ "/tmp/" ^ path in let oc = open_out @@ "/tmp/" ^ path in
output_string oc req.S.Request.body; output_string oc req.S.Request.body;
flush oc; flush oc;
S.Response.make_ok "uploaded file" S.Response.make (Ok "uploaded file")
with e -> with e ->
S.Response.make_error @@ "couldn't upload file " ^ Printexc.to_string e S.Response.fail ~code:500 "couldn't upload file: %s" (Printexc.to_string e)
); );
Printf.printf "listening on http://%s:%d\n%!" (S.addr server) (S.port server); Printf.printf "listening on http://%s:%d\n%!" (S.addr server) (S.port server);
match S.run server with match S.run server with