---------------------------------------------------------------------------- 
     Copyright ( c ) 2017 Inhabited Type LLC . 

     All rights reserved . 

     Redistribution and use in source and binary forms , with or without 
     modification , are permitted provided that the following conditions 
     are met : 

     1 . Redistributions of source code must retain the above copyright 
        notice , this list of conditions and the following disclaimer . 

     2 . Redistributions in binary form must reproduce the above copyright 
        notice , this list of conditions and the following disclaimer in the 
        documentation and/or other materials provided with the distribution . 

     3 . Neither the name of the author nor the names of his contributors 
        may be used to endorse or promote products derived from this software 
        without specific prior written permission . 

     THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ` ` AS IS '' AND ANY EXPRESS 
     OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED 
     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
     DISCLAIMED .   IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 
     ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL 
     DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS 
     OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) 
     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , 
     STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN 
     ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE 
     POSSIBILITY OF SUCH DAMAGE . 
   ----------------------------------------------------------------------------
    Copyright (c) 2017 Inhabited Type LLC.

    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

    3. Neither the name of the author nor the names of his contributors
       may be used to endorse or promote products derived from this software
       without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
  ----------------------------------------------------------------------------*)

* Http / af is a high - performance , memory - efficient , and scalable web server 
     for OCaml . It implements the HTTP 1.1 specification with respect to 
     parsing , serialization , and connection pipelining . For compatibility , 
     http / af respects the imperatives of the [ Server_connection ] header when handling 
     HTTP 1.0 connections . 

     To use this library effectively , the user must be familiar with the HTTP 
     1.1 specification , and the basic principles of memory management and 
     vectorized IO .
    for OCaml. It implements the HTTP 1.1 specification with respect to
    parsing, serialization, and connection pipelining. For compatibility,
    http/af respects the imperatives of the [Server_connection] header when handling
    HTTP 1.0 connections.

    To use this library effectively, the user must be familiar with the HTTP
    1.1 specification, and the basic principles of memory management and
    vectorized IO. *)


open Result
open Eio.Std

* { 2 Basic HTTP Types }


(** Protocol Version

    HTTP uses a "<major>.<minor>" numbering scheme to indicate versions of the
    protocol. The protocol version as a whole indicates the sender's conformance
    with the set of requirements laid out in that version's corresponding
    specification of HTTP.

    See {{:#section-2.6} RFC7230§2.6} for
    more details. *)
module Version : sig
  type t =
    { major : int (** The major protocol number. *)
    ; minor : int (** The minor protocol number. *)
    }

  val compare : t -> t -> int

  val to_string : t -> string
  val of_string : string -> t

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


(** Request Method

    The request method token is the primary source of request semantics;
    it indicates the purpose for which the client has made this request
    and what is expected by the client as a successful result.

    See {{:#section-4} RFC7231§4} for more
    details. *)
module Method : sig
  type standard = [
    | `GET
* { { : #section-4.3.1 } RFC7231§4.3.1 } . Safe , Cacheable .
    | `HEAD
* { { : #section-4.3.2 } RFC7231§4.3.2 } . Safe , Cacheable .
    | `POST
* { { : #section-4.3.3 } RFC7231§4.3.3 } . Cacheable .
    | `PUT
    (** {{:#section-4.3.4} RFC7231§4.3.4}. Idempotent. *)
    | `DELETE
    (** {{:#section-4.3.5} RFC7231§4.3.5}. Idempotent. *)
    | `CONNECT
    (** {{:#section-4.3.6} RFC7231§4.3.6}. *)
    | `OPTIONS
    (** {{:#section-4.3.7} RFC7231§4.3.7}. Safe.*)
    | `TRACE
    (** {{:#section-4.3.8} RFC7231§4.3.8}. Safe.*)
    ]

  type t = [
    | standard
    | `Other of string
* Methods defined outside of RFC7231 , or custom methods .
    ]

  val is_safe : standard -> bool
  (** Request methods are considered "safe" if their defined semantics are
      essentially read-only; i.e., the client does not request, and does not
      expect, any state change on the origin server as a result of applying a
      safe method to a target resource.  Likewise, reasonable use of a safe
      method is not expected to cause any harm, loss of property, or unusual
      burden on the origin server.

      See {{:#section-4.2.1} RFC7231§4.2.1}
      for more details. *)

  val is_cacheable  : standard -> bool
*   Request methods can be defined as " cacheable " to indicate that responses 
        to them are allowed to be stored for future reuse . 

        See { { :  }  } for more details .
       to them are allowed to be stored for future reuse.

       See {{:} RFC7234} for more details. *)

  val is_idempotent : standard -> bool
* A request method is considered " idempotent " if the intended effect on 
       the server of multiple identical requests with that method is the same as 
       the effect for a single such request .   Of the request methods defined by 
       this specification , PUT , DELETE , and safe request methods are idempotent . 

       See { { : #section-4.2.2 } RFC7231§4.2.2 } 
       for more details .
      the server of multiple identical requests with that method is the same as
      the effect for a single such request.  Of the request methods defined by
      this specification, PUT, DELETE, and safe request methods are idempotent.

      See {{:#section-4.2.2} RFC7231§4.2.2}
      for more details. *)

  val to_string : t -> string
  val of_string : string -> t

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


* Response Status Codes 

    The status - code element is a three - digit integer code giving the result of 
    the attempt to understand and satisfy the request . 

    See { { : #section-6 } RFC7231§6 } for more 
    details .

   The status-code element is a three-digit integer code giving the result of
   the attempt to understand and satisfy the request.

   See {{:#section-6} RFC7231§6} for more
   details. *)
module Status : sig
  type informational = [
    | `Continue
    | `Switching_protocols
    ]
* The 1xx ( Informational ) class of status code indicates an interim 
       response for communicating connection status or request progress 
       prior to completing the requested action and sending a final 
       response . 

       See { { : #section-6.2 } RFC7231§6.2 } 
       for more details .
      response for communicating connection status or request progress
      prior to completing the requested action and sending a final
      response.

      See {{:#section-6.2} RFC7231§6.2}
      for more details. *)

  type successful = [
    | `OK
    | `Created
    | `Accepted
    | `Non_authoritative_information
    | `No_content
    | `Reset_content
    | `Partial_content
    ]
* The 2xx ( Successful ) class of status code indicates that the client 's 
       request was successfully received , understood , and accepted . 

       See { { : #section-6.3 } RFC7231§6.3 } 
       for more details .
      request was successfully received, understood, and accepted.

      See {{:#section-6.3} RFC7231§6.3}
      for more details. *)

  type redirection = [
    | `Multiple_choices
    | `Moved_permanently
    | `Found
    | `See_other
    | `Not_modified
    | `Use_proxy
    | `Temporary_redirect
    ]
* The  ( Redirection ) class of status code indicates that further 
       action needs to be taken by the user agent in order to fulfill the 
       request . 

       See { { : #section-6.4 } RFC7231§6.4 } for 
       more details .
      action needs to be taken by the user agent in order to fulfill the
      request.

      See {{:#section-6.4} RFC7231§6.4} for
      more details. *)

  type client_error = [
    | `Bad_request
    | `Unauthorized
    | `Payment_required
    | `Forbidden
    | `Not_found
    | `Method_not_allowed
    | `Not_acceptable
    | `Proxy_authentication_required
    | `Request_timeout
    | `Conflict
    | `Gone
    | `Length_required
    | `Precondition_failed
    | `Payload_too_large
    | `Uri_too_long
    | `Unsupported_media_type
    | `Range_not_satisfiable
    | `Expectation_failed
    | `Upgrade_required
    | `I_m_a_teapot
    | `Enhance_your_calm
    ]
* The 4xx ( Client Error ) class of status code indicates that the client 
       seems to have erred . 

       See { { :  } RFC7231§6.5 } for 
       more details .
      seems to have erred.

      See {{:#section-6.5} RFC7231§6.5} for
      more details. *)

  type server_error = [
    | `Internal_server_error
    | `Not_implemented
    | `Bad_gateway
    | `Service_unavailable
    | `Gateway_timeout
    | `Http_version_not_supported
    ]
* The 5xx ( Server Error ) class of status code indicates that the server is 
       aware that it has erred or is incapable of performing the requested 
       method . 

       See { { : #section-6.6 } RFC7231§6.6 } for 
       more details .
      aware that it has erred or is incapable of performing the requested
      method.

      See {{:#section-6.6} RFC7231§6.6} for
      more details. *)

  type standard = [
    | informational
    | successful
    | redirection
    | client_error
    | server_error
    ]
* The status codes defined in the HTTP 1.1 RFCs

  type t = [
    | standard
    | `Code of int ]
  (** The standard codes along with support for custom codes. *)

  val default_reason_phrase : standard -> string
* [ default_reason_phrase standard ] is the example reason phrase provided 
       by  for the [ standard ] status code . The RFC allows servers to use 
       reason phrases besides these in responses .
      by RFC7231 for the [standard] status code. The RFC allows servers to use
      reason phrases besides these in responses. *)

  val to_code : t -> int
  (** [to_code t] is the integer representation of [t]. *)

  val of_code : int -> t
* [ of_code i ] is the [ t ] representation of [ i ] . [ of_code ] raises [ Failure ] 
       if [ i ] is not a positive three - digit number .
      if [i] is not a positive three-digit number. *)

  val unsafe_of_code : int -> t
  (** [unsafe_of_code i] is equivalent to [of_code i], except it accepts any
      positive code, regardless of the number of digits it has. On negative
      codes, it will still raise [Failure]. *)

  val is_informational : t -> bool
  (** [is_informational t] is true iff [t] belongs to the Informational class
      of status codes. *)

  val is_successful : t -> bool
  (** [is_successful t] is true iff [t] belongs to the Successful class of
      status codes. *)

  val is_redirection : t -> bool
* [ is_redirection t ] is true iff [ t ] belongs to the Redirection class of 
       status codes .
      status codes. *)

  val is_client_error : t -> bool
  (** [is_client_error t] is true iff [t] belongs to the Client Error class of
      status codes. *)

  val is_server_error : t -> bool
  (** [is_server_error t] is true iff [t] belongs to the Server Error class of
      status codes. *)

  val is_error : t -> bool
  (** [is_error t] is true iff [t] belongs to the Client Error or Server Error
      class of status codes. *)

  val to_string : t -> string
  val of_string : string -> t

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


* Header  

     Each header field consists of a case - insensitive { b field name } and a { b 
     field value } . The order in which header fields { i with differing field 
     names } are received is not significant . However , it is good practice to 
     send header fields that contain control data first so that implementations 
     can decide when not to handle a message as early as possible . 

     A sender MUST NOT generate multiple header fields with the same field name 
     in a message unless either the entire field value for that header field is 
     defined as a comma - separated list or the header field is a well - known 
     exception , e.g. , [ Set - Cookie ] . 

     A recipient  combine multiple header fields with the same field name 
     into one " field - name : field - value " pair , without changing the semantics of 
     the message , by appending each subsequent field value to the combined field 
     value in order , separated by a comma . { i The order in which header fields 
     with the same field name are received is therefore significant to the 
     interpretation of the combined field value } ; a proxy MUST NOT change the 
     order of these field values when forwarding a message . 

     { i Note . } Unless otherwise specified , all operations preserve header field 
     order and all reference to equality on names is assumed to be 
     case - insensitive . 

     See { { : #section-3.2 } RFC7230§3.2 } for 
     more details .

    Each header field consists of a case-insensitive {b field name} and a {b
    field value}. The order in which header fields {i with differing field
    names} are received is not significant. However, it is good practice to
    send header fields that contain control data first so that implementations
    can decide when not to handle a message as early as possible.

    A sender MUST NOT generate multiple header fields with the same field name
    in a message unless either the entire field value for that header field is
    defined as a comma-separated list or the header field is a well-known
    exception, e.g., [Set-Cookie].

    A recipient MAY combine multiple header fields with the same field name
    into one "field-name: field-value" pair, without changing the semantics of
    the message, by appending each subsequent field value to the combined field
    value in order, separated by a comma. {i The order in which header fields
    with the same field name are received is therefore significant to the
    interpretation of the combined field value}; a proxy MUST NOT change the
    order of these field values when forwarding a message.

    {i Note.} Unless otherwise specified, all operations preserve header field
    order and all reference to equality on names is assumed to be
    case-insensitive.

    See {{:#section-3.2} RFC7230§3.2} for
    more details. *)
module Headers : sig
  type t

  type name = string
  (** The type of a case-insensitive header name. *)

  type value = string
  (** The type of a header value. *)

  (** {3 Constructor} *)

  val empty : t
  (** [empty] is the empty collection of header fields. *)

  val of_list : (name * value) list -> t
  (** [of_list assoc] is a collection of header fields defined by the
      association list [assoc]. [of_list] assumes the order of header fields in
      [assoc] is the intended transmission order. The following equations
      should hold:

        {ul
        {- [to_list (of_list lst) = lst] }
        {- [get (of_list [("k", "v1"); ("k", "v2")]) "k" = Some "v2"]. }} *)

  val of_rev_list : (name * value) list -> t
* [ of_list assoc ] is a collection of header fields defined by the 
       association list [ assoc ] . [ of_list ] assumes the order of header fields in 
       [ assoc ] is the { i reverse } of the intended trasmission order . The 
       following equations should hold : 

         { ul 
         { - [ to_list ( of_rev_list lst ) = List.rev lst ] } 
         { - [ get ( of_rev_list [ ( " k " , " v1 " ) ; ( " k " , " v2 " ) ] ) " k " = Some " v1 " ] . } }
      association list [assoc]. [of_list] assumes the order of header fields in
      [assoc] is the {i reverse} of the intended trasmission order. The
      following equations should hold:

        {ul
        {- [to_list (of_rev_list lst) = List.rev lst] }
        {- [get (of_rev_list [("k", "v1"); ("k", "v2")]) "k" = Some "v1"]. }} *)

  val to_list : t -> (name * value) list
  (** [to_list t] is the association list of header fields contained in [t] in
      transmission order. *)

  val to_rev_list : t -> (name * value) list
  (** [to_rev_list t] is the association list of header fields contained in [t]
      in {i reverse} transmission order. *)

  val add : t -> name -> value -> t
  (** [add t name value] is a collection of header fields that is the same as
      [t] except with [(name, value)] added at the end of the trasmission order.
      The following equations should hold:

        {ul
        {- [get (add t name value) name = Some value] }} *)

  val add_unless_exists : t -> name -> value -> t
  (** [add_unless_exists t name value] is a collection of header fields that is
      the same as [t] if [t] already inclues [name], and otherwise is
      equivalent to [add t name value]. *)

  val add_list : t -> (name * value) list -> t
  (** [add_list t assoc] is a collection of header fields that is the same as
      [t] except with all the header fields in [assoc] added to the end of the
      transmission order, in reverse order. *)

  val add_multi : t -> (name * value list) list -> t
* [ add_multi t assoc ] is the same as 

       { [ 
         add_list t ( List.concat_map assoc ~f:(fun ( name , values ) - > 
           List.map values ~f:(fun value - > ( name , value ) ) ) ) 
       ] } 

       but is implemented more efficiently . For example , 

       { [ 
         add_multi t [ " name1 " , [ " x " , " y " ] ; "  " , [ " p " , " q " ] ] 
           = add_list [ " name1 " , " x " ; " name1 " , " y " ; "  " , " p " ; "  " , " q " ] 
       ] }

      {[
        add_list t (List.concat_map assoc ~f:(fun (name, values) ->
          List.map values ~f:(fun value -> (name, value))))
      ]}

      but is implemented more efficiently. For example,

      {[
        add_multi t ["name1", ["x", "y"]; "name2", ["p", "q"]]
          = add_list ["name1", "x"; "name1", "y"; "name2", "p"; "name2", "q"]
      ]} *)

  val remove : t -> name -> t
  (** [remove t name] is a collection of header fields that contains all the
      header fields of [t] except those that have a header-field name that are
      equal to [name]. If [t] contains multiple header fields whose name is
      [name], they will all be removed. *)

  val replace : t -> name -> value -> t
* [ replace t name value ] is a collection of header fields that is the same 
       as [ t ] except with all header fields with a name equal to [ name ] removed 
       and replaced with a single header field whose name is [ name ] and whose 
       value is [ value ] . This new header field will appear in the transmission 
       order where the first occurrence of a header field with a name matching 
       [ name ] was found . 

       If no header field with a name equal to [ name ] is present in [ t ] , then 
       the result is simply [ t ] , unchanged .
      as [t] except with all header fields with a name equal to [name] removed
      and replaced with a single header field whose name is [name] and whose
      value is [value]. This new header field will appear in the transmission
      order where the first occurrence of a header field with a name matching
      [name] was found.

      If no header field with a name equal to [name] is present in [t], then
      the result is simply [t], unchanged. *)

  (** {3 Destructors} *)

  val mem : t -> name -> bool
  (** [mem t name] is true iff [t] includes a header field with a name that is
      equal to [name]. *)

  val get : t -> name -> value option
  (** [get t name] returns the last header from [t] with name [name], or [None]
      if no such header is present. *)

  val get_exn : t -> name -> value
  (** [get t name] returns the last header from [t] with name [name], or raises
      if no such header is present. *)

  val get_multi : t -> name -> value list
  (** [get_multi t name] is the list of header values in [t] whose names are
      equal to [name]. The returned list is in transmission order. *)

* { 3 Iteration }

  val iter : f:(name -> value -> unit) -> t -> unit
  val fold : f:(name -> value -> 'a -> 'a) -> init:'a -> t -> 'a

* { 3 Utilities }

  val to_string : t -> string

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end

* { 2 Message Body }

module Body : sig
  type 'rw t

  val schedule_read
    :  [`read] t
    -> on_eof  : (unit -> unit)
    -> on_read : (Bigstringaf.t -> off:int -> len:int -> unit)
    -> unit
  (** [schedule_read t ~on_eof ~on_read] will setup [on_read] and [on_eof] as
      callbacks for when bytes are available in [t] for the application to
      consume, or when the input channel has been closed and no further bytes
      will be received by the application.

      Once either of these callbacks have been called, they become inactive. 
      The application is responsible for scheduling subsequent reads, either 
      within the [on_read] callback or by some other mechanism. *)

  val write_char : [`write] t -> char -> unit
  (** [write_char w char] copies [char] into an internal buffer. If possible,
      this write will be combined with previous and/or subsequent writes before
      transmission. *)

  val write_string : [`write] t -> ?off:int -> ?len:int -> string -> unit
  (** [write_string w ?off ?len str] copies [str] into an internal buffer. If
      possible, this write will be combined with previous and/or subsequent
      writes before transmission. *)

  val write_bigstring : [`write] t -> ?off:int -> ?len:int -> Bigstringaf.t -> unit
  (** [write_bigstring w ?off ?len bs] copies [bs] into an internal buffer. If
      possible, this write will be combined with previous and/or subsequent
      writes before transmission. *)

  val schedule_bigstring : [`write] t -> ?off:int -> ?len:int -> Bigstringaf.t -> unit
  (** [schedule_bigstring w ?off ?len bs] schedules [bs] to be transmitted at
      the next opportunity without performing a copy. [bs] should not be
      modified until a subsequent call to {!flush} has successfully 
      completed. *)

  val flush : [`write] t -> (unit -> unit) -> unit
  (** [flush t f] makes all bytes in [t] available for writing to the awaiting
      output channel. Once those bytes have reached that output channel, [f]
      will be called.

      The type of the output channel is runtime-dependent, as are guarantees about
      whether those packets have been queued for delivery or have actually been
      received by the intended recipient. *)

  val close_reader : [`read] t -> unit
  (** [close_reader t] closes [t], indicating that any subsequent input
      received should be discarded. *)

  val close_writer : [`write] t -> unit
  (** [close_writer t] closes [t], causing subsequent write calls to raise. If
      [t] is writable, this will cause any pending output to become available
      to the output channel. *)

  val is_closed : _ t -> bool
  (** [is_closed t] is [true] if {!close} has been called on [t] and [false]
      otherwise. A closed [t] may still have pending output. *)

end


* { 2 Message Types }

(** Request

    A client-initiated HTTP message. *)
module Request : sig
  type t =
    { meth    : Method.t
    ; target  : string
    ; version : Version.t
    ; headers : Headers.t }

  val create
* default is HTTP 1.1
    -> ?headers:Headers.t (** default is {!Headers.empty} *)
    -> Method.t
    -> string
    -> t

  val body_length : t -> [
    | `Fixed of Int64.t
    | `Chunked
    | `Error of [`Bad_request]
  ]
* [  t ] is the length of the message body accompanying [ t ] . It is 
       an error to generate a request with a close - delimited message body . 

       See { { : #section-3.3.3 } RFC7230§3.3.3 } 
       for more details .
      an error to generate a request with a close-delimited message body.

      See {{:#section-3.3.3} RFC7230§3.3.3}
      for more details. *)

  val persistent_connection : ?proxy:bool -> t -> bool
* [ persistent_connection ? proxy t ] indicates whether the connection for [ t ] 
       can be reused for multiple requests and responses . If the calling code 
       is acting as a proxy , it should pass [ ~proxy : true ] . 

       See { { : #section-6.3 } RFC7230§6.3 for 
       more details .
      can be reused for multiple requests and responses. If the calling code
      is acting as a proxy, it should pass [~proxy:true].

      See {{:#section-6.3} RFC7230§6.3 for
      more details. *)

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


(** Response

    A server-generated message to a {Request}. *)
module Response : sig
  type t =
    { version : Version.t
    ; status  : Status.t
    ; reason  : string
    ; headers : Headers.t }

  val create
    :  ?reason:string     (** default is determined by {!Status.default_reason_phrase} *)
* default is HTTP 1.1
    -> ?headers:Headers.t (** default is {!Headers.empty} *)
    -> Status.t
    -> t
  (** [create ?reason ?version ?headers status] creates an HTTP response with
      the given parameters. For typical use cases, it's sufficient to provide
      values for [headers] and [status]. *)

  val body_length : ?proxy:bool -> request_method:Method.standard -> t -> [
    | `Fixed of Int64.t
    | `Chunked
    | `Close_delimited
    | `Error of [ `Bad_gateway | `Internal_server_error ]
  ]
* [  ? proxy ~request_method t ] is the length of the message body 
       accompanying [ t ] assuming it is a response to a request whose method was 
       [ request_method ] . If the calling code is acting as a proxy , it should 
       pass [ ~proxy : true ] . This optional parameter only affects error reporting . 

       See { { : #section-3.3.3 } RFC7230§3.3.3 } 
       for more details .
      accompanying [t] assuming it is a response to a request whose method was
      [request_method]. If the calling code is acting as a proxy, it should
      pass [~proxy:true]. This optional parameter only affects error reporting.

      See {{:#section-3.3.3} RFC7230§3.3.3}
      for more details. *)

  val persistent_connection : ?proxy:bool -> t -> bool
* [ persistent_connection ? proxy t ] indicates whether the connection for [ t ] 
       can be reused for multiple requests and responses . If the calling code 
       is acting as a proxy , it should pass [ ~proxy : true ] . 

       See { { : #section-6.3 } RFC7230§6.3 for 
       more details .
      can be reused for multiple requests and responses. If the calling code
      is acting as a proxy, it should pass [~proxy:true].

      See {{:#section-6.3} RFC7230§6.3 for
      more details. *)

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


* 
module IOVec : sig
  type 'a t = 'a Faraday.iovec =
    { buffer : 'a
    ; off : int
    ; len : int }

  val length  : _ t -> int
  val lengthv : _ t list -> int

  val shift  : 'a t -> int -> 'a t
  val shiftv : 'a t list -> int -> 'a t list

  val pp_hum : Format.formatter -> _ t -> unit [@@ocaml.toplevel_printer]
end

* { 2 Request Descriptor }
module Reqd : sig
  type t

  val request : t -> Request.t
  val request_body : t -> [`read] Body.t

  val response : t -> Response.t option
  val response_exn : t -> Response.t

  (** Responding

      The following functions will initiate a response for the corresponding
      request in [t]. Depending on the state of the current connection, and the
      header values of the response, this may cause the connection to close or
      to persist for reuse by the client.

      See {{:#section-6.3} RFC7230§6.3} for
      more details. *)

  val respond_with_string    : t -> Response.t -> string -> unit
  val respond_with_bigstring : t -> Response.t -> Bigstringaf.t -> unit
  val respond_with_streaming : ?flush_headers_immediately:bool -> t -> Response.t -> [`write] Body.t

* { 3 Exception Handling }

  val report_exn : t -> exn -> unit
  val try_with : t -> (unit -> unit) -> (unit, exn) result
end

* { 2 Buffer Size Configuration }
module Config : sig
  type t =
* Default is [ 4096 ]
* Default is [ 4096 ]
* Default is [ 1024 ]
* Default is [ 4096 ]
    }

  val default : t
  (** [default] is a configuration record with all parameters set to their
      default values. *)
end

* { 2 Server Connection }

module Server_connection : sig
  type error =
    [ `Bad_request | `Bad_gateway | `Internal_server_error | `Exn of exn ]

  type request_handler = Reqd.t -> unit

  type error_handler =
    ?request:Request.t -> error -> (Headers.t -> [`write] Body.t) -> unit

  val handle :
    ?config:Config.t ->
    ?error_handler:error_handler ->
    sw:Switch.t ->
    read:(int -> Angstrom.bigstring * int * int * Angstrom.Unbuffered.more) ->
    write:(Faraday.bigstring IOVec.t list -> [< `Closed | `Ok of int ]) ->
    request_handler ->
    unit
* [ handle ~sw ~read request_handler ] handles an incoming HTTP connection . 
       It calls [ read ] as necessary to read from the connection , passing in the number 
       of bytes consumed since the last call . [ read ] should return a tuple 
       [ ( buf , off , len , more ) ] , where the slice of [ buf ] from [ off ] to [ off+len ] 
       contains the previously unconsumed bytes plus at least one newly read byte . 
       [ request_handler ] is invoked to handle each HTTP request , once the headers 
       have been received . Processing of the request stream continues when it returns . 
       On error , [ sw ] is turned off .
      It calls [read] as necessary to read from the connection, passing in the number
      of bytes consumed since the last call. [read] should return a tuple
      [(buf, off, len, more)], where the slice of [buf] from [off] to [off+len]
      contains the previously unconsumed bytes plus at least one newly read byte.
      [request_handler] is invoked to handle each HTTP request, once the headers
      have been received. Processing of the request stream continues when it returns.
      On error, [sw] is turned off. *)
end

* { 2 Client Connection }

module Client_connection : sig

  type t

  type error =
    [ `Malformed_response of string | `Invalid_response_body_length of Response.t | `Exn of exn ]

  type response_handler = Response.t -> [`read] Body.t  -> unit

  type error_handler = error -> unit

  val request
    :  ?config:Config.t
    -> Request.t
    -> error_handler:error_handler
    -> response_handler:response_handler
    -> [`write] Body.t * t

  val next_read_operation : t -> [ `Read | `Close ]
  (** [next_read_operation t] returns a value describing the next operation
      that the caller should conduct on behalf of the connection. *)

  val read : t -> Bigstringaf.t -> off:int -> len:int -> int
* [ read t   ~len ] reads bytes of input from the provided range 
       of [ bigstring ] and returns the number of bytes consumed by the 
       connection .   { ! read } should be called after { ! next_read_operation } 
       returns a [ ` Read ] value and additional input is available for the 
       connection to consume .
      of [bigstring] and returns the number of bytes consumed by the
      connection.  {!read} should be called after {!next_read_operation}
      returns a [`Read] value and additional input is available for the
      connection to consume. *)

  val read_eof : t -> Bigstringaf.t -> off:int -> len:int -> int
* [ read_eof t   ~len ] reads bytes of input from the provided 
       range of [ bigstring ] and returns the number of bytes consumed by the 
       connection .   { !  } should be called after { ! next_read_operation } 
       returns a [ ` Read ] and an EOF has been received from the communication 
       channel . The connection will attempt to consume any buffered input and 
       then shutdown the HTTP parser for the connection .
      range of [bigstring] and returns the number of bytes consumed by the
      connection.  {!read_eof} should be called after {!next_read_operation}
      returns a [`Read] and an EOF has been received from the communication
      channel. The connection will attempt to consume any buffered input and
      then shutdown the HTTP parser for the connection. *)

  val next_write_operation : t -> [
    | `Write of Bigstringaf.t IOVec.t list
    | `Yield
    | `Close of int ]
  (** [next_write_operation t] returns a value describing the next operation
      that the caller should conduct on behalf of the connection. *)

  val report_write_result : t -> [`Ok of int | `Closed] -> unit
  (** [report_write_result t result] reports the result of the latest write
      attempt to the connection. {report_write_result} should be called after a
      call to {next_write_operation} that returns a [`Write buffer] value.

        {ul
        {- [`Ok n] indicates that the caller successfully wrote [n] bytes of
        output from the buffer that the caller was provided by
        {next_write_operation}. }
        {- [`Closed] indicates that the output destination will no longer
        accept bytes from the write processor. }} *)

  val yield_writer : t -> (unit -> unit) -> unit
  (** [yield_writer t continue] registers with the connection to call
      [continue] when writing should resume. {!yield_writer} should be called
      after {next_write_operation} returns a [`Yield] value. *)

  val report_exn : t -> exn -> unit
  (** [report_exn t exn] reports that an error [exn] has been caught and
      that it has been attributed to [t]. Calling this function will switch [t]
      into an error state. Depending on the state [t] is transitioning from, it
      may call its error handler before terminating the connection. *)

  val is_closed : t -> bool

  (**/**)
  val shutdown : t -> unit
  (**/**)
end

(**/**)

module Httpaf_private : sig
  module Parse : sig
    val request : Request.t Angstrom.t
    val response : Response.t Angstrom.t
  end

  module Serialize : sig
    val write_request  : Faraday.t -> Request.t  -> unit
    val write_response : Faraday.t -> Response.t -> unit
  end
end

* Protocol Version

    HTTP uses a "<major>.<minor>" numbering scheme to indicate versions of the
    protocol. The protocol version as a whole indicates the sender's conformance
    with the set of requirements laid out in that version's corresponding
    specification of HTTP.

    See {{:#section-2.6} RFC7230§2.6} for
    more details. 
* The major protocol number. 
* The minor protocol number. 
* Request Method

    The request method token is the primary source of request semantics;
    it indicates the purpose for which the client has made this request
    and what is expected by the client as a successful result.

    See {{:#section-4} RFC7231§4} for more
    details. 
* {{:#section-4.3.4} RFC7231§4.3.4}. Idempotent. 
* {{:#section-4.3.5} RFC7231§4.3.5}. Idempotent. 
* {{:#section-4.3.6} RFC7231§4.3.6}. 
* {{:#section-4.3.7} RFC7231§4.3.7}. Safe.
* {{:#section-4.3.8} RFC7231§4.3.8}. Safe.
* Request methods are considered "safe" if their defined semantics are
      essentially read-only; i.e., the client does not request, and does not
      expect, any state change on the origin server as a result of applying a
      safe method to a target resource.  Likewise, reasonable use of a safe
      method is not expected to cause any harm, loss of property, or unusual
      burden on the origin server.

      See {{:#section-4.2.1} RFC7231§4.2.1}
      for more details. 
* The standard codes along with support for custom codes. 
* [to_code t] is the integer representation of [t]. 
* [unsafe_of_code i] is equivalent to [of_code i], except it accepts any
      positive code, regardless of the number of digits it has. On negative
      codes, it will still raise [Failure]. 
* [is_informational t] is true iff [t] belongs to the Informational class
      of status codes. 
* [is_successful t] is true iff [t] belongs to the Successful class of
      status codes. 
* [is_client_error t] is true iff [t] belongs to the Client Error class of
      status codes. 
* [is_server_error t] is true iff [t] belongs to the Server Error class of
      status codes. 
* [is_error t] is true iff [t] belongs to the Client Error or Server Error
      class of status codes. 
* The type of a case-insensitive header name. 
* The type of a header value. 
* {3 Constructor} 
* [empty] is the empty collection of header fields. 
* [of_list assoc] is a collection of header fields defined by the
      association list [assoc]. [of_list] assumes the order of header fields in
      [assoc] is the intended transmission order. The following equations
      should hold:

        {ul
        {- [to_list (of_list lst) = lst] }
        {- [get (of_list [("k", "v1"); ("k", "v2")]) "k" = Some "v2"]. }} 
* [to_list t] is the association list of header fields contained in [t] in
      transmission order. 
* [to_rev_list t] is the association list of header fields contained in [t]
      in {i reverse} transmission order. 
* [add t name value] is a collection of header fields that is the same as
      [t] except with [(name, value)] added at the end of the trasmission order.
      The following equations should hold:

        {ul
        {- [get (add t name value) name = Some value] }} 
* [add_unless_exists t name value] is a collection of header fields that is
      the same as [t] if [t] already inclues [name], and otherwise is
      equivalent to [add t name value]. 
* [add_list t assoc] is a collection of header fields that is the same as
      [t] except with all the header fields in [assoc] added to the end of the
      transmission order, in reverse order. 
* [remove t name] is a collection of header fields that contains all the
      header fields of [t] except those that have a header-field name that are
      equal to [name]. If [t] contains multiple header fields whose name is
      [name], they will all be removed. 
* {3 Destructors} 
* [mem t name] is true iff [t] includes a header field with a name that is
      equal to [name]. 
* [get t name] returns the last header from [t] with name [name], or [None]
      if no such header is present. 
* [get t name] returns the last header from [t] with name [name], or raises
      if no such header is present. 
* [get_multi t name] is the list of header values in [t] whose names are
      equal to [name]. The returned list is in transmission order. 
* [schedule_read t ~on_eof ~on_read] will setup [on_read] and [on_eof] as
      callbacks for when bytes are available in [t] for the application to
      consume, or when the input channel has been closed and no further bytes
      will be received by the application.

      Once either of these callbacks have been called, they become inactive. 
      The application is responsible for scheduling subsequent reads, either 
      within the [on_read] callback or by some other mechanism. 
* [write_char w char] copies [char] into an internal buffer. If possible,
      this write will be combined with previous and/or subsequent writes before
      transmission. 
* [write_string w ?off ?len str] copies [str] into an internal buffer. If
      possible, this write will be combined with previous and/or subsequent
      writes before transmission. 
* [write_bigstring w ?off ?len bs] copies [bs] into an internal buffer. If
      possible, this write will be combined with previous and/or subsequent
      writes before transmission. 
* [schedule_bigstring w ?off ?len bs] schedules [bs] to be transmitted at
      the next opportunity without performing a copy. [bs] should not be
      modified until a subsequent call to {!flush} has successfully 
      completed. 
* [flush t f] makes all bytes in [t] available for writing to the awaiting
      output channel. Once those bytes have reached that output channel, [f]
      will be called.

      The type of the output channel is runtime-dependent, as are guarantees about
      whether those packets have been queued for delivery or have actually been
      received by the intended recipient. 
* [close_reader t] closes [t], indicating that any subsequent input
      received should be discarded. 
* [close_writer t] closes [t], causing subsequent write calls to raise. If
      [t] is writable, this will cause any pending output to become available
      to the output channel. 
* [is_closed t] is [true] if {!close} has been called on [t] and [false]
      otherwise. A closed [t] may still have pending output. 
* Request

    A client-initiated HTTP message. 
* default is {!Headers.empty} 
* Response

    A server-generated message to a {Request}. 
* default is determined by {!Status.default_reason_phrase} 
* default is {!Headers.empty} 
* [create ?reason ?version ?headers status] creates an HTTP response with
      the given parameters. For typical use cases, it's sufficient to provide
      values for [headers] and [status]. 
* Responding

      The following functions will initiate a response for the corresponding
      request in [t]. Depending on the state of the current connection, and the
      header values of the response, this may cause the connection to close or
      to persist for reuse by the client.

      See {{:#section-6.3} RFC7230§6.3} for
      more details. 
* [default] is a configuration record with all parameters set to their
      default values. 
* [next_read_operation t] returns a value describing the next operation
      that the caller should conduct on behalf of the connection. 
* [next_write_operation t] returns a value describing the next operation
      that the caller should conduct on behalf of the connection. 
* [report_write_result t result] reports the result of the latest write
      attempt to the connection. {report_write_result} should be called after a
      call to {next_write_operation} that returns a [`Write buffer] value.

        {ul
        {- [`Ok n] indicates that the caller successfully wrote [n] bytes of
        output from the buffer that the caller was provided by
        {next_write_operation}. }
        {- [`Closed] indicates that the output destination will no longer
        accept bytes from the write processor. }} 
* [yield_writer t continue] registers with the connection to call
      [continue] when writing should resume. {!yield_writer} should be called
      after {next_write_operation} returns a [`Yield] value. 
* [report_exn t exn] reports that an error [exn] has been caught and
      that it has been attributed to [t]. Calling this function will switch [t]
      into an error state. Depending on the state [t] is transitioning from, it
      may call its error handler before terminating the connection. 
*/*
*/*
*/*
---------------------------------------------------------------------------- 
     Copyright ( c ) 2017 Inhabited Type LLC . 

     All rights reserved . 

     Redistribution and use in source and binary forms , with or without 
     modification , are permitted provided that the following conditions 
     are met : 

     1 . Redistributions of source code must retain the above copyright 
        notice , this list of conditions and the following disclaimer . 

     2 . Redistributions in binary form must reproduce the above copyright 
        notice , this list of conditions and the following disclaimer in the 
        documentation and/or other materials provided with the distribution . 

     3 . Neither the name of the author nor the names of his contributors 
        may be used to endorse or promote products derived from this software 
        without specific prior written permission . 

     THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ` ` AS IS '' AND ANY EXPRESS 
     OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED 
     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
     DISCLAIMED .   IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 
     ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL 
     DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS 
     OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) 
     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , 
     STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN 
     ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE 
     POSSIBILITY OF SUCH DAMAGE . 
   ----------------------------------------------------------------------------
    Copyright (c) 2017 Inhabited Type LLC.

    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

    3. Neither the name of the author nor the names of his contributors
       may be used to endorse or promote products derived from this software
       without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
  ----------------------------------------------------------------------------*)

* Http / af is a high - performance , memory - efficient , and scalable web server 
     for OCaml . It implements the HTTP 1.1 specification with respect to 
     parsing , serialization , and connection pipelining . For compatibility , 
     http / af respects the imperatives of the [ Server_connection ] header when handling 
     HTTP 1.0 connections . 

     To use this library effectively , the user must be familiar with the HTTP 
     1.1 specification , and the basic principles of memory management and 
     vectorized IO .
    for OCaml. It implements the HTTP 1.1 specification with respect to
    parsing, serialization, and connection pipelining. For compatibility,
    http/af respects the imperatives of the [Server_connection] header when handling
    HTTP 1.0 connections.

    To use this library effectively, the user must be familiar with the HTTP
    1.1 specification, and the basic principles of memory management and
    vectorized IO. *)


open Result
open Eio.Std

* { 2 Basic HTTP Types }


module Version : sig
  type t =
    }

  val compare : t -> t -> int

  val to_string : t -> string
  val of_string : string -> t

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


module Method : sig
  type standard = [
    | `GET
* { { : #section-4.3.1 } RFC7231§4.3.1 } . Safe , Cacheable .
    | `HEAD
* { { : #section-4.3.2 } RFC7231§4.3.2 } . Safe , Cacheable .
    | `POST
* { { : #section-4.3.3 } RFC7231§4.3.3 } . Cacheable .
    | `PUT
    | `DELETE
    | `CONNECT
    | `OPTIONS
    | `TRACE
    ]

  type t = [
    | standard
    | `Other of string
* Methods defined outside of RFC7231 , or custom methods .
    ]

  val is_safe : standard -> bool

  val is_cacheable  : standard -> bool
*   Request methods can be defined as " cacheable " to indicate that responses 
        to them are allowed to be stored for future reuse . 

        See { { :  }  } for more details .
       to them are allowed to be stored for future reuse.

       See {{:} RFC7234} for more details. *)

  val is_idempotent : standard -> bool
* A request method is considered " idempotent " if the intended effect on 
       the server of multiple identical requests with that method is the same as 
       the effect for a single such request .   Of the request methods defined by 
       this specification , PUT , DELETE , and safe request methods are idempotent . 

       See { { : #section-4.2.2 } RFC7231§4.2.2 } 
       for more details .
      the server of multiple identical requests with that method is the same as
      the effect for a single such request.  Of the request methods defined by
      this specification, PUT, DELETE, and safe request methods are idempotent.

      See {{:#section-4.2.2} RFC7231§4.2.2}
      for more details. *)

  val to_string : t -> string
  val of_string : string -> t

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


* Response Status Codes 

    The status - code element is a three - digit integer code giving the result of 
    the attempt to understand and satisfy the request . 

    See { { : #section-6 } RFC7231§6 } for more 
    details .

   The status-code element is a three-digit integer code giving the result of
   the attempt to understand and satisfy the request.

   See {{:#section-6} RFC7231§6} for more
   details. *)
module Status : sig
  type informational = [
    | `Continue
    | `Switching_protocols
    ]
* The 1xx ( Informational ) class of status code indicates an interim 
       response for communicating connection status or request progress 
       prior to completing the requested action and sending a final 
       response . 

       See { { : #section-6.2 } RFC7231§6.2 } 
       for more details .
      response for communicating connection status or request progress
      prior to completing the requested action and sending a final
      response.

      See {{:#section-6.2} RFC7231§6.2}
      for more details. *)

  type successful = [
    | `OK
    | `Created
    | `Accepted
    | `Non_authoritative_information
    | `No_content
    | `Reset_content
    | `Partial_content
    ]
* The 2xx ( Successful ) class of status code indicates that the client 's 
       request was successfully received , understood , and accepted . 

       See { { : #section-6.3 } RFC7231§6.3 } 
       for more details .
      request was successfully received, understood, and accepted.

      See {{:#section-6.3} RFC7231§6.3}
      for more details. *)

  type redirection = [
    | `Multiple_choices
    | `Moved_permanently
    | `Found
    | `See_other
    | `Not_modified
    | `Use_proxy
    | `Temporary_redirect
    ]
* The  ( Redirection ) class of status code indicates that further 
       action needs to be taken by the user agent in order to fulfill the 
       request . 

       See { { : #section-6.4 } RFC7231§6.4 } for 
       more details .
      action needs to be taken by the user agent in order to fulfill the
      request.

      See {{:#section-6.4} RFC7231§6.4} for
      more details. *)

  type client_error = [
    | `Bad_request
    | `Unauthorized
    | `Payment_required
    | `Forbidden
    | `Not_found
    | `Method_not_allowed
    | `Not_acceptable
    | `Proxy_authentication_required
    | `Request_timeout
    | `Conflict
    | `Gone
    | `Length_required
    | `Precondition_failed
    | `Payload_too_large
    | `Uri_too_long
    | `Unsupported_media_type
    | `Range_not_satisfiable
    | `Expectation_failed
    | `Upgrade_required
    | `I_m_a_teapot
    | `Enhance_your_calm
    ]
* The 4xx ( Client Error ) class of status code indicates that the client 
       seems to have erred . 

       See { { :  } RFC7231§6.5 } for 
       more details .
      seems to have erred.

      See {{:#section-6.5} RFC7231§6.5} for
      more details. *)

  type server_error = [
    | `Internal_server_error
    | `Not_implemented
    | `Bad_gateway
    | `Service_unavailable
    | `Gateway_timeout
    | `Http_version_not_supported
    ]
* The 5xx ( Server Error ) class of status code indicates that the server is 
       aware that it has erred or is incapable of performing the requested 
       method . 

       See { { : #section-6.6 } RFC7231§6.6 } for 
       more details .
      aware that it has erred or is incapable of performing the requested
      method.

      See {{:#section-6.6} RFC7231§6.6} for
      more details. *)

  type standard = [
    | informational
    | successful
    | redirection
    | client_error
    | server_error
    ]
* The status codes defined in the HTTP 1.1 RFCs

  type t = [
    | standard
    | `Code of int ]

  val default_reason_phrase : standard -> string
* [ default_reason_phrase standard ] is the example reason phrase provided 
       by  for the [ standard ] status code . The RFC allows servers to use 
       reason phrases besides these in responses .
      by RFC7231 for the [standard] status code. The RFC allows servers to use
      reason phrases besides these in responses. *)

  val to_code : t -> int

  val of_code : int -> t
* [ of_code i ] is the [ t ] representation of [ i ] . [ of_code ] raises [ Failure ] 
       if [ i ] is not a positive three - digit number .
      if [i] is not a positive three-digit number. *)

  val unsafe_of_code : int -> t

  val is_informational : t -> bool

  val is_successful : t -> bool

  val is_redirection : t -> bool
* [ is_redirection t ] is true iff [ t ] belongs to the Redirection class of 
       status codes .
      status codes. *)

  val is_client_error : t -> bool

  val is_server_error : t -> bool

  val is_error : t -> bool

  val to_string : t -> string
  val of_string : string -> t

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


* Header  

     Each header field consists of a case - insensitive { b field name } and a { b 
     field value } . The order in which header fields { i with differing field 
     names } are received is not significant . However , it is good practice to 
     send header fields that contain control data first so that implementations 
     can decide when not to handle a message as early as possible . 

     A sender MUST NOT generate multiple header fields with the same field name 
     in a message unless either the entire field value for that header field is 
     defined as a comma - separated list or the header field is a well - known 
     exception , e.g. , [ Set - Cookie ] . 

     A recipient  combine multiple header fields with the same field name 
     into one " field - name : field - value " pair , without changing the semantics of 
     the message , by appending each subsequent field value to the combined field 
     value in order , separated by a comma . { i The order in which header fields 
     with the same field name are received is therefore significant to the 
     interpretation of the combined field value } ; a proxy MUST NOT change the 
     order of these field values when forwarding a message . 

     { i Note . } Unless otherwise specified , all operations preserve header field 
     order and all reference to equality on names is assumed to be 
     case - insensitive . 

     See { { : #section-3.2 } RFC7230§3.2 } for 
     more details .

    Each header field consists of a case-insensitive {b field name} and a {b
    field value}. The order in which header fields {i with differing field
    names} are received is not significant. However, it is good practice to
    send header fields that contain control data first so that implementations
    can decide when not to handle a message as early as possible.

    A sender MUST NOT generate multiple header fields with the same field name
    in a message unless either the entire field value for that header field is
    defined as a comma-separated list or the header field is a well-known
    exception, e.g., [Set-Cookie].

    A recipient MAY combine multiple header fields with the same field name
    into one "field-name: field-value" pair, without changing the semantics of
    the message, by appending each subsequent field value to the combined field
    value in order, separated by a comma. {i The order in which header fields
    with the same field name are received is therefore significant to the
    interpretation of the combined field value}; a proxy MUST NOT change the
    order of these field values when forwarding a message.

    {i Note.} Unless otherwise specified, all operations preserve header field
    order and all reference to equality on names is assumed to be
    case-insensitive.

    See {{:#section-3.2} RFC7230§3.2} for
    more details. *)
module Headers : sig
  type t

  type name = string

  type value = string


  val empty : t

  val of_list : (name * value) list -> t

  val of_rev_list : (name * value) list -> t
* [ of_list assoc ] is a collection of header fields defined by the 
       association list [ assoc ] . [ of_list ] assumes the order of header fields in 
       [ assoc ] is the { i reverse } of the intended trasmission order . The 
       following equations should hold : 

         { ul 
         { - [ to_list ( of_rev_list lst ) = List.rev lst ] } 
         { - [ get ( of_rev_list [ ( " k " , " v1 " ) ; ( " k " , " v2 " ) ] ) " k " = Some " v1 " ] . } }
      association list [assoc]. [of_list] assumes the order of header fields in
      [assoc] is the {i reverse} of the intended trasmission order. The
      following equations should hold:

        {ul
        {- [to_list (of_rev_list lst) = List.rev lst] }
        {- [get (of_rev_list [("k", "v1"); ("k", "v2")]) "k" = Some "v1"]. }} *)

  val to_list : t -> (name * value) list

  val to_rev_list : t -> (name * value) list

  val add : t -> name -> value -> t

  val add_unless_exists : t -> name -> value -> t

  val add_list : t -> (name * value) list -> t

  val add_multi : t -> (name * value list) list -> t
* [ add_multi t assoc ] is the same as 

       { [ 
         add_list t ( List.concat_map assoc ~f:(fun ( name , values ) - > 
           List.map values ~f:(fun value - > ( name , value ) ) ) ) 
       ] } 

       but is implemented more efficiently . For example , 

       { [ 
         add_multi t [ " name1 " , [ " x " , " y " ] ; "  " , [ " p " , " q " ] ] 
           = add_list [ " name1 " , " x " ; " name1 " , " y " ; "  " , " p " ; "  " , " q " ] 
       ] }

      {[
        add_list t (List.concat_map assoc ~f:(fun (name, values) ->
          List.map values ~f:(fun value -> (name, value))))
      ]}

      but is implemented more efficiently. For example,

      {[
        add_multi t ["name1", ["x", "y"]; "name2", ["p", "q"]]
          = add_list ["name1", "x"; "name1", "y"; "name2", "p"; "name2", "q"]
      ]} *)

  val remove : t -> name -> t

  val replace : t -> name -> value -> t
* [ replace t name value ] is a collection of header fields that is the same 
       as [ t ] except with all header fields with a name equal to [ name ] removed 
       and replaced with a single header field whose name is [ name ] and whose 
       value is [ value ] . This new header field will appear in the transmission 
       order where the first occurrence of a header field with a name matching 
       [ name ] was found . 

       If no header field with a name equal to [ name ] is present in [ t ] , then 
       the result is simply [ t ] , unchanged .
      as [t] except with all header fields with a name equal to [name] removed
      and replaced with a single header field whose name is [name] and whose
      value is [value]. This new header field will appear in the transmission
      order where the first occurrence of a header field with a name matching
      [name] was found.

      If no header field with a name equal to [name] is present in [t], then
      the result is simply [t], unchanged. *)


  val mem : t -> name -> bool

  val get : t -> name -> value option

  val get_exn : t -> name -> value

  val get_multi : t -> name -> value list

* { 3 Iteration }

  val iter : f:(name -> value -> unit) -> t -> unit
  val fold : f:(name -> value -> 'a -> 'a) -> init:'a -> t -> 'a

* { 3 Utilities }

  val to_string : t -> string

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end

* { 2 Message Body }

module Body : sig
  type 'rw t

  val schedule_read
    :  [`read] t
    -> on_eof  : (unit -> unit)
    -> on_read : (Bigstringaf.t -> off:int -> len:int -> unit)
    -> unit

  val write_char : [`write] t -> char -> unit

  val write_string : [`write] t -> ?off:int -> ?len:int -> string -> unit

  val write_bigstring : [`write] t -> ?off:int -> ?len:int -> Bigstringaf.t -> unit

  val schedule_bigstring : [`write] t -> ?off:int -> ?len:int -> Bigstringaf.t -> unit

  val flush : [`write] t -> (unit -> unit) -> unit

  val close_reader : [`read] t -> unit

  val close_writer : [`write] t -> unit

  val is_closed : _ t -> bool

end


* { 2 Message Types }

module Request : sig
  type t =
    { meth    : Method.t
    ; target  : string
    ; version : Version.t
    ; headers : Headers.t }

  val create
* default is HTTP 1.1
    -> Method.t
    -> string
    -> t

  val body_length : t -> [
    | `Fixed of Int64.t
    | `Chunked
    | `Error of [`Bad_request]
  ]
* [  t ] is the length of the message body accompanying [ t ] . It is 
       an error to generate a request with a close - delimited message body . 

       See { { : #section-3.3.3 } RFC7230§3.3.3 } 
       for more details .
      an error to generate a request with a close-delimited message body.

      See {{:#section-3.3.3} RFC7230§3.3.3}
      for more details. *)

  val persistent_connection : ?proxy:bool -> t -> bool
* [ persistent_connection ? proxy t ] indicates whether the connection for [ t ] 
       can be reused for multiple requests and responses . If the calling code 
       is acting as a proxy , it should pass [ ~proxy : true ] . 

       See { { : #section-6.3 } RFC7230§6.3 for 
       more details .
      can be reused for multiple requests and responses. If the calling code
      is acting as a proxy, it should pass [~proxy:true].

      See {{:#section-6.3} RFC7230§6.3 for
      more details. *)

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


module Response : sig
  type t =
    { version : Version.t
    ; status  : Status.t
    ; reason  : string
    ; headers : Headers.t }

  val create
* default is HTTP 1.1
    -> Status.t
    -> t

  val body_length : ?proxy:bool -> request_method:Method.standard -> t -> [
    | `Fixed of Int64.t
    | `Chunked
    | `Close_delimited
    | `Error of [ `Bad_gateway | `Internal_server_error ]
  ]
* [  ? proxy ~request_method t ] is the length of the message body 
       accompanying [ t ] assuming it is a response to a request whose method was 
       [ request_method ] . If the calling code is acting as a proxy , it should 
       pass [ ~proxy : true ] . This optional parameter only affects error reporting . 

       See { { : #section-3.3.3 } RFC7230§3.3.3 } 
       for more details .
      accompanying [t] assuming it is a response to a request whose method was
      [request_method]. If the calling code is acting as a proxy, it should
      pass [~proxy:true]. This optional parameter only affects error reporting.

      See {{:#section-3.3.3} RFC7230§3.3.3}
      for more details. *)

  val persistent_connection : ?proxy:bool -> t -> bool
* [ persistent_connection ? proxy t ] indicates whether the connection for [ t ] 
       can be reused for multiple requests and responses . If the calling code 
       is acting as a proxy , it should pass [ ~proxy : true ] . 

       See { { : #section-6.3 } RFC7230§6.3 for 
       more details .
      can be reused for multiple requests and responses. If the calling code
      is acting as a proxy, it should pass [~proxy:true].

      See {{:#section-6.3} RFC7230§6.3 for
      more details. *)

  val pp_hum : Format.formatter -> t -> unit [@@ocaml.toplevel_printer]
end


* 
module IOVec : sig
  type 'a t = 'a Faraday.iovec =
    { buffer : 'a
    ; off : int
    ; len : int }

  val length  : _ t -> int
  val lengthv : _ t list -> int

  val shift  : 'a t -> int -> 'a t
  val shiftv : 'a t list -> int -> 'a t list

  val pp_hum : Format.formatter -> _ t -> unit [@@ocaml.toplevel_printer]
end

* { 2 Request Descriptor }
module Reqd : sig
  type t

  val request : t -> Request.t
  val request_body : t -> [`read] Body.t

  val response : t -> Response.t option
  val response_exn : t -> Response.t


  val respond_with_string    : t -> Response.t -> string -> unit
  val respond_with_bigstring : t -> Response.t -> Bigstringaf.t -> unit
  val respond_with_streaming : ?flush_headers_immediately:bool -> t -> Response.t -> [`write] Body.t

* { 3 Exception Handling }

  val report_exn : t -> exn -> unit
  val try_with : t -> (unit -> unit) -> (unit, exn) result
end

* { 2 Buffer Size Configuration }
module Config : sig
  type t =
* Default is [ 4096 ]
* Default is [ 4096 ]
* Default is [ 1024 ]
* Default is [ 4096 ]
    }

  val default : t
end

* { 2 Server Connection }

module Server_connection : sig
  type error =
    [ `Bad_request | `Bad_gateway | `Internal_server_error | `Exn of exn ]

  type request_handler = Reqd.t -> unit

  type error_handler =
    ?request:Request.t -> error -> (Headers.t -> [`write] Body.t) -> unit

  val handle :
    ?config:Config.t ->
    ?error_handler:error_handler ->
    sw:Switch.t ->
    read:(int -> Angstrom.bigstring * int * int * Angstrom.Unbuffered.more) ->
    write:(Faraday.bigstring IOVec.t list -> [< `Closed | `Ok of int ]) ->
    request_handler ->
    unit
* [ handle ~sw ~read request_handler ] handles an incoming HTTP connection . 
       It calls [ read ] as necessary to read from the connection , passing in the number 
       of bytes consumed since the last call . [ read ] should return a tuple 
       [ ( buf , off , len , more ) ] , where the slice of [ buf ] from [ off ] to [ off+len ] 
       contains the previously unconsumed bytes plus at least one newly read byte . 
       [ request_handler ] is invoked to handle each HTTP request , once the headers 
       have been received . Processing of the request stream continues when it returns . 
       On error , [ sw ] is turned off .
      It calls [read] as necessary to read from the connection, passing in the number
      of bytes consumed since the last call. [read] should return a tuple
      [(buf, off, len, more)], where the slice of [buf] from [off] to [off+len]
      contains the previously unconsumed bytes plus at least one newly read byte.
      [request_handler] is invoked to handle each HTTP request, once the headers
      have been received. Processing of the request stream continues when it returns.
      On error, [sw] is turned off. *)
end

* { 2 Client Connection }

module Client_connection : sig

  type t

  type error =
    [ `Malformed_response of string | `Invalid_response_body_length of Response.t | `Exn of exn ]

  type response_handler = Response.t -> [`read] Body.t  -> unit

  type error_handler = error -> unit

  val request
    :  ?config:Config.t
    -> Request.t
    -> error_handler:error_handler
    -> response_handler:response_handler
    -> [`write] Body.t * t

  val next_read_operation : t -> [ `Read | `Close ]

  val read : t -> Bigstringaf.t -> off:int -> len:int -> int
* [ read t   ~len ] reads bytes of input from the provided range 
       of [ bigstring ] and returns the number of bytes consumed by the 
       connection .   { ! read } should be called after { ! next_read_operation } 
       returns a [ ` Read ] value and additional input is available for the 
       connection to consume .
      of [bigstring] and returns the number of bytes consumed by the
      connection.  {!read} should be called after {!next_read_operation}
      returns a [`Read] value and additional input is available for the
      connection to consume. *)

  val read_eof : t -> Bigstringaf.t -> off:int -> len:int -> int
* [ read_eof t   ~len ] reads bytes of input from the provided 
       range of [ bigstring ] and returns the number of bytes consumed by the 
       connection .   { !  } should be called after { ! next_read_operation } 
       returns a [ ` Read ] and an EOF has been received from the communication 
       channel . The connection will attempt to consume any buffered input and 
       then shutdown the HTTP parser for the connection .
      range of [bigstring] and returns the number of bytes consumed by the
      connection.  {!read_eof} should be called after {!next_read_operation}
      returns a [`Read] and an EOF has been received from the communication
      channel. The connection will attempt to consume any buffered input and
      then shutdown the HTTP parser for the connection. *)

  val next_write_operation : t -> [
    | `Write of Bigstringaf.t IOVec.t list
    | `Yield
    | `Close of int ]

  val report_write_result : t -> [`Ok of int | `Closed] -> unit

  val yield_writer : t -> (unit -> unit) -> unit

  val report_exn : t -> exn -> unit

  val is_closed : t -> bool

  val shutdown : t -> unit
end


module Httpaf_private : sig
  module Parse : sig
    val request : Request.t Angstrom.t
    val response : Response.t Angstrom.t
  end

  module Serialize : sig
    val write_request  : Faraday.t -> Request.t  -> unit
    val write_response : Faraday.t -> Response.t -> unit
  end
end
