My aggregated monorepo of OCaml code, automaintained

Merge commit '368d4db8cded0c84777395279154223c2c0e5015'

+139 -204
+11 -5
ocaml-requests/lib/uri.ml
··· 518 518 end 519 519 520 520 let query_of_encoded = Query.query_of_encoded 521 - let encoded_of_query ?scheme = Query.encoded_of_query ?scheme 521 + let encoded_of_query ?scheme l = Query.encoded_of_query ?scheme l 522 522 523 523 (** {1 URI Type} *) 524 524 ··· 599 599 600 600 (** {1 URI to String Conversion} *) 601 601 602 - let to_string ?(pct_encoder=pct_encoder ()) uri = 602 + let to_string_internal ?(pct_encoder=pct_encoder ()) uri = 603 603 let scheme = match uri.scheme with 604 604 | Some s -> Some (Pct.uncast_decoded s) 605 605 | None -> None in ··· 669 669 ); 670 670 Buffer.contents buf 671 671 672 + let to_string uri = to_string_internal uri 673 + 672 674 (** {1 Accessor Functions} *) 673 675 674 676 let get_decoded_opt = function None -> None |Some x -> Some (Pct.uncast_decoded x) ··· 690 692 |None -> default 691 693 |Some h -> h 692 694 693 - let userinfo ?(pct_encoder=pct_encoder ()) uri = match uri.userinfo with 695 + let userinfo_internal ?(pct_encoder=pct_encoder ()) uri = match uri.userinfo with 694 696 | None -> None 695 697 | Some userinfo -> Some (Pct.uncast_encoded (match uri.scheme with 696 698 | None -> encoded_of_userinfo ~component:pct_encoder.userinfo userinfo 697 699 | Some s -> encoded_of_userinfo ~scheme:(Pct.uncast_decoded s) ~component:pct_encoder.userinfo userinfo)) 700 + 701 + let userinfo uri = userinfo_internal uri 698 702 699 703 let with_userinfo uri userinfo = 700 704 let userinfo = match userinfo with ··· 734 738 | Some _ -> { uri with host=Some (`Host (Pct.cast_decoded "")); port=port } 735 739 end 736 740 737 - let path ?(pct_encoder=pct_encoder ()) uri = Pct.uncast_encoded (match uri.scheme with 741 + let path_internal ?(pct_encoder=pct_encoder ()) uri = Pct.uncast_encoded (match uri.scheme with 738 742 | None -> encoded_of_path ~component:pct_encoder.path uri.path 739 743 | Some s -> encoded_of_path ~scheme:(Pct.uncast_decoded s) ~component:pct_encoder.path uri.path) 744 + 745 + let path uri = path_internal uri 740 746 741 747 let with_path uri path = 742 748 let path = path_of_encoded path in ··· 1394 1400 | Ok t -> t 1395 1401 | Error (`Msg error) -> failwith error 1396 1402 1397 - let to_string ?pct_encoder t = to_uri t |> to_string ?pct_encoder 1403 + let to_string t = to_uri t |> to_string 1398 1404 1399 1405 let normalize t = 1400 1406 { t with
+128 -199
ocaml-requests/lib/uri.mli
··· 18 18 (** Uniform Resource Identifier handling that is RFC3986-compliant. 19 19 20 20 This module provides URI parsing, construction, and manipulation 21 - using Eio.Buf_read combinators for parsing. 21 + for HTTP clients and servers. 22 22 23 23 {2 RFC 3986 Compliance} 24 24 25 25 This implementation follows {{:https://tools.ietf.org/html/rfc3986}RFC 3986} 26 - for URI syntax, reference resolution, and normalization. *) 26 + for URI syntax. *) 27 + 28 + (** {1 Types} *) 27 29 28 - (** A single URI that is a compact sequence of characters that identifies 29 - an abstract or physical resource. *) 30 30 type t 31 + (** A URI: a compact sequence of characters that identifies an abstract 32 + or physical resource. *) 31 33 32 34 (** URI component types for percent-encoding customization. *) 33 - type component = [ 34 - | `Scheme 35 + type component = 36 + [ `Scheme 35 37 | `Authority 36 - | `Userinfo (** subcomponent of authority in some schemes *) 37 - | `Host (** subcomponent of authority in some schemes *) 38 + | `Userinfo 39 + | `Host 38 40 | `Path 39 41 | `Query 40 42 | `Query_key 41 43 | `Query_value 42 44 | `Fragment 43 45 | `Generic 44 - | `Custom of (component * string * string) (** (component * safe chars * unsafe chars) *) 45 - ] 46 + | `Custom of component * string * string ] 46 47 47 - (** For pct encoding customization when converting a URI to a string. *) 48 - type pct_encoder 49 - 50 - (** {2 Core functionality } *) 48 + (** {1 Construction and Conversion} *) 51 49 52 50 val empty : t 53 - (** The empty (zero length) URI reference. Useful for constructing 54 - URIs piece-by-piece. *) 55 - 56 - val compare : t -> t -> int 57 - (** Comparator ordering by host, scheme, port, userinfo, path, query, 58 - and finally fragment. Designed to produce a reasonable sort order. *) 59 - 60 - val equal : t -> t -> bool 61 - (** [equal a b] is [compare a b = 0]. *) 62 - 63 - val pct_encode : ?scheme:string -> ?component:component -> string -> string 64 - (** Percent-encode a string. The [component] argument defaults to `Path *) 51 + (** The empty URI reference. Useful for constructing URIs piece-by-piece. *) 65 52 66 - val pct_encoder : 67 - ?scheme:component -> 68 - ?userinfo:component -> 69 - ?host:component -> 70 - ?path:component -> 71 - ?query_key:component -> 72 - ?query_value:component -> 73 - ?fragment:component -> 53 + val make : 54 + ?scheme:string -> 55 + ?userinfo:string -> 56 + ?host:string -> 57 + ?port:int -> 58 + ?path:string -> 59 + ?query:(string * string list) list -> 60 + ?fragment:string -> 74 61 unit -> 75 - pct_encoder 76 - (** Construct a pct_encoder. *) 77 - 78 - val pct_decode : string -> string 79 - (** Percent-decode a percent-encoded string *) 62 + t 63 + (** Construct a URI from components. If userinfo or port are supplied without 64 + host, an empty host is added. If path is supplied and authority components 65 + are also supplied, path is made absolute. *) 80 66 81 67 val of_string : string -> t 82 - (** Parse a URI string literal into a URI structure. A bare string will be 83 - interpreted as a path; a string prefixed with `//` will be interpreted as a 84 - host. *) 68 + (** Parse a URI string into a URI structure. A bare string is interpreted as 69 + a path; a string prefixed with [//] is interpreted as a host. *) 85 70 86 - val to_string : ?pct_encoder:pct_encoder -> t -> string 87 - (** Convert a URI structure into a percent-encoded URI string *) 71 + val to_string : t -> string 72 + (** Convert a URI to a percent-encoded string. *) 88 73 89 - val resolve : string -> t -> t -> t 90 - (** [resolve scheme base uri] resolves [uri] against [base] URI using [scheme] 91 - as the default scheme. Per RFC 3986 Section 5. *) 74 + (** {1 Comparison} *) 92 75 93 - val canonicalize : t -> t 94 - (** Canonicalize a URI according to Sec 6.2.3 "Scheme-Based 95 - Normalization". This transform is more aggressive than the 96 - standard URI-generic normalization automatically done. In 97 - particular, HTTP(S) URIs with empty path components will have 98 - their path components set to "/". Some applications like web 99 - servers may rely on the distinction between a path-less and a 100 - root-path URI to distinguish request URIs (e.g. OPTIONS * vs 101 - OPTIONS /). 76 + val compare : t -> t -> int 77 + (** Compare two URIs. Orders by host, scheme, port, userinfo, path, query, 78 + then fragment. *) 102 79 103 - @see <https://tools.ietf.org/html/rfc3986#section-6.2.3> RFC 3986.6.2.3 104 - *) 80 + val equal : t -> t -> bool 81 + (** [equal a b] is [compare a b = 0]. *) 105 82 106 - val make : ?scheme:string -> ?userinfo:string -> ?host:string -> 107 - ?port:int -> ?path:string -> ?query:(string * string list) list -> 108 - ?fragment:string -> unit -> t 109 - (** Make a URI from supplied components. If userinfo or port are 110 - supplied without host, an empty host is added. If path is supplied 111 - and userinfo, host, or port is also supplied, path is made 112 - absolute but not resolved. *) 83 + (** {1 Percent Encoding} *) 113 84 114 - val with_uri : ?scheme:string option -> ?userinfo:string option -> 115 - ?host:string option -> ?port:int option -> ?path:string option -> 116 - ?query:(string * string list) list option -> ?fragment:string option -> t -> t 117 - (** Functional update for a URI using the supplied components. If a component 118 - is unspecified then it will be unchanged. If a component is supplied as 119 - [None] then the component will be removed in the returned URI. If a 120 - component is supplied as [Some x] then [x] will be added if it does not 121 - exist in the source URI or replaced if it does exist. *) 85 + val pct_encode : ?scheme:string -> ?component:component -> string -> string 86 + (** Percent-encode a string. The [component] argument controls which characters 87 + are considered safe; defaults to [`Path]. *) 122 88 123 - (** {2 Query functions } 89 + val pct_decode : string -> string 90 + (** Decode a percent-encoded string. *) 124 91 125 - The query string API attempts to accommodate conventional query 126 - string representations (i.e. [?key0=value0&key1=value1]) while 127 - maximally exposing any meaning in those representations. For 128 - example, it is not necessarily the case that [/] and [/?] are 129 - equivalent to a web server. In the former case, we observe a zero 130 - query string whereas in the latter case, we observe a query string 131 - with a single key, [""] and a zero value. Compare this with [/?=] 132 - which has a single key and a single empty value, 133 - [""]. Additionally, some query functions return lists of values 134 - for a key. These list values are extracted from a {b single} key 135 - with a comma-separated value list. If a query string has multiple 136 - identical keys, you must use {! query} to retrieve the entirety of 137 - the structured query string. 138 - *) 92 + (** {1 Component Access} *) 139 93 140 - val query : t -> (string * string list) list 141 - (** Get a query string from a URI *) 94 + val scheme : t -> string option 95 + (** Get the scheme component (e.g., ["http"], ["https"]). *) 142 96 143 - val verbatim_query : ?pct_encoder:pct_encoder -> t -> string option 144 - (** Get a verbatim query string from a URI. If the provenance of the 145 - URI is a string and its query component has not been updated, this 146 - is the literal query string as parsed. Otherwise, this is the 147 - composition of {!query} and {!encoded_of_query} *) 97 + val userinfo : t -> string option 98 + (** Get the userinfo component (e.g., ["user:password"]). *) 148 99 149 - val encoded_of_query : 150 - ?scheme:string -> 151 - ?pct_encoder:pct_encoder -> 152 - (string * string list) list -> 153 - string 154 - (** Make a percent-encoded query string from percent-decoded query tuple *) 100 + val host : t -> string option 101 + (** Get the host component. *) 155 102 156 - val query_of_encoded : string -> (string * string list) list 157 - (** Parse a percent-encoded query string into a percent-decoded query tuple *) 103 + val port : t -> int option 104 + (** Get the port component. *) 158 105 159 - val with_query : t -> (string * string list) list -> t 160 - (** Replace the query URI with the supplied list. 161 - Input URI is not modified *) 106 + val path : t -> string 107 + (** Get the path component. *) 162 108 163 - val with_query' : t -> (string * string) list -> t 164 - (** Replace the query URI with the supplied singleton query list. 165 - Input URI is not modified *) 109 + val fragment : t -> string option 110 + (** Get the fragment component. *) 166 111 167 - val get_query_param' : t -> string -> string list option 168 - (** [get_query_param' q key] returns the list of values for the 169 - [key] parameter in query [q]. Note that an empty list is not the 170 - same as a [None] return value. *) 112 + val path_and_query : t -> string 113 + (** Get the combined path and query string, suitable for HTTP request lines. *) 171 114 172 - val get_query_param: t -> string -> string option 173 - (** [get_query_param q key] returns the value found for a [key] in 174 - query [q]. If there are multiple values for the key, then the 175 - first one is returned. *) 115 + (** {1 Component Modification} *) 176 116 177 - val add_query_param : t -> (string * string list) -> t 178 - (** Add a query parameter to the input query URI. 179 - Input URI is not modified *) 117 + val with_scheme : t -> string option -> t 118 + (** Return a new URI with the scheme replaced. *) 180 119 181 - val add_query_param' : t -> (string * string) -> t 182 - (** Add a query parameter to the input singleton query URI. 183 - Input URI is not modified *) 120 + val with_userinfo : t -> string option -> t 121 + (** Return a new URI with the userinfo replaced. Adds an empty host if none 122 + is present. *) 184 123 185 - val add_query_params : t -> (string * string list) list -> t 186 - (** Add a query parameter list to the input query URI. 187 - Input URI is not modified *) 188 - 189 - val add_query_params' : t -> (string * string) list -> t 190 - (** Add a query singleton parameter list to the input query URI. 191 - Input URI is not modified *) 192 - 193 - val remove_query_param : t -> string -> t 194 - (** Remove a query key from the input query URI. 195 - Input URI is not modified, and no error is generated if the 196 - key does not already exist in the URI. *) 197 - 198 - (** {2 Component getters and setters } *) 199 - 200 - val path : ?pct_encoder:pct_encoder -> t -> string 201 - (** Get the encoded path component of a URI *) 124 + val with_host : t -> string option -> t 125 + (** Return a new URI with the host replaced. *) 202 126 203 - val path_and_query : t -> string 204 - (** Get the encoded path and query components of a URI *) 127 + val with_port : t -> int option -> t 128 + (** Return a new URI with the port replaced. Adds an empty host if none 129 + is present. *) 205 130 206 131 val with_path : t -> string -> t 207 - (** Replace the path URI with the supplied encoded path. 208 - If a host is present in the supplied URI, the path is made absolute but not 209 - resolved. If the path is empty, the path component is removed. 210 - Input URI is not modified *) 132 + (** Return a new URI with the path replaced. If a host is present, the path 133 + is made absolute. An empty path removes the path component. *) 211 134 212 - val scheme : t -> string option 213 - (** Get the scheme component of a URI *) 135 + val with_fragment : t -> string option -> t 136 + (** Return a new URI with the fragment replaced. *) 214 137 215 - val with_scheme : t -> string option -> t 216 - (** Replace the scheme portion of the URI with the supplied [scheme]. 217 - Input URI is not modified *) 138 + (** {1 Query String} *) 218 139 219 - val userinfo : ?pct_encoder:pct_encoder -> t -> string option 220 - (** Get the userinfo component of a URI *) 140 + val query : t -> (string * string list) list 141 + (** Get the query parameters as a list of key-value pairs. Each key may have 142 + multiple values. *) 221 143 222 - val with_userinfo : t -> string option -> t 223 - (** Replace the userinfo portion of the URI with the supplied [string option]. 224 - If no host is present in the supplied URI, an empty host is added. 225 - Input URI is not modified. *) 144 + val encoded_of_query : ?scheme:string -> (string * string list) list -> string 145 + (** Encode query parameters to a percent-encoded query string. *) 226 146 227 - val user : t -> string option 228 - (** Get the username component of a URI *) 147 + val with_query : t -> (string * string list) list -> t 148 + (** Return a new URI with the query parameters replaced. *) 229 149 230 - val password : t -> string option 231 - (** Get the password component of a URI *) 150 + val get_query_param : t -> string -> string option 151 + (** [get_query_param uri key] returns the first value for [key], or [None]. *) 232 152 233 - val with_password : t -> string option -> t 234 - (** Replace the password portion of the URI with the supplied [string option]. 235 - If no host is present in the supplied URI, an empty host is added. 236 - Input URI is not modified. *) 153 + val add_query_param : t -> string * string list -> t 154 + (** Add a query parameter (key with potentially multiple values). *) 237 155 238 - val host : t -> string option 239 - (** Get the host component of a URI *) 156 + val add_query_param' : t -> string * string -> t 157 + (** Add a single-valued query parameter. *) 240 158 241 - val with_host: t -> string option -> t 242 - (** Replace the host component of the URI. 243 - Input URI is not modified. *) 159 + val add_query_params : t -> (string * string list) list -> t 160 + (** Add multiple query parameters. *) 244 161 245 - val host_with_default: ?default:string -> t -> string 246 - (** Get the host component of a URI, with a default supplied if one is 247 - not present *) 162 + val remove_query_param : t -> string -> t 163 + (** Remove all values for a query key. *) 248 164 249 - val port : t -> int option 250 - (** Get the port component of a URI *) 165 + (** {1 Reference Resolution} *) 251 166 252 - val with_port : t -> int option -> t 253 - (** Replace the port component of the URI with the supplied port. 254 - If no host is present in the supplied URI, an empty host is added. 255 - Input URI is not modified. *) 256 - 257 - val fragment : t -> string option 258 - (** Get the fragment component of a URI *) 259 - 260 - val with_fragment : t -> string option -> t 261 - (** Replace the fragment component of a URI with the supplied fragment. 262 - Input URI is not modified *) 167 + val resolve : string -> t -> t -> t 168 + (** [resolve scheme base uri] resolves [uri] against [base] using [scheme] 169 + as the default scheme. Per RFC 3986 Section 5. Used for handling relative 170 + redirect URLs. *) 263 171 264 - (** {2 Formatters } *) 172 + (** {1 Formatting} *) 265 173 266 174 val pp : Format.formatter -> t -> unit 267 - (** [pp ppf t] will output a human readable version of the Uri [t] 268 - to the formatter [ppf] *) 175 + (** Pretty-print a URI. *) 269 176 270 - val pp_hum : Format.formatter -> t -> unit 271 - (** [pp_hum] is now an alias for the {!pp} function. *) 177 + (** {1 Parsing} 272 178 273 - (** {2 Buf_read Parsers} 179 + Buf_read parsers for streaming URI parsing. *) 274 180 275 - These parsers use Eio.Buf_read for efficient streaming parsing. *) 276 181 module Parser : sig 277 182 val ipv6 : Eio.Buf_read.t -> string 278 183 (** Parse an IPv6 address (without brackets). *) ··· 281 186 (** Parse a complete URI reference. *) 282 187 end 283 188 284 - (** Specializations for HTTP and HTTPS schemes as per RFC9110 *) 189 + (** {1 HTTP URIs} 190 + 191 + Specializations for HTTP and HTTPS schemes as per RFC 9110. These ensure 192 + the URI has a valid scheme and host for HTTP requests. *) 193 + 285 194 module Absolute_http : sig 286 195 type uri := t 196 + 287 197 type t 198 + (** An absolute HTTP or HTTPS URI with a required host. *) 288 199 289 200 val of_uri : uri -> (t, [ `Msg of string ]) result 201 + (** Convert a generic URI to an HTTP URI. Fails if scheme is not http/https 202 + or if host is missing. *) 203 + 290 204 val to_uri : t -> uri 205 + (** Convert back to a generic URI. *) 291 206 292 207 val of_string : string -> t 293 - val to_string : ?pct_encoder:pct_encoder -> t -> string 208 + (** Parse a string as an HTTP URI. Raises on invalid input. *) 294 209 295 - val make : scheme:[ `Http | `Https ]-> host:string -> 296 - ?userinfo:string -> ?port:int -> ?path:string -> 297 - ?query:(string * string list) list -> ?fragment:string -> unit -> t 210 + val to_string : t -> string 211 + (** Convert to a percent-encoded string. *) 212 + 213 + val make : 214 + scheme:[ `Http | `Https ] -> 215 + host:string -> 216 + ?userinfo:string -> 217 + ?port:int -> 218 + ?path:string -> 219 + ?query:(string * string list) list -> 220 + ?fragment:string -> 221 + unit -> 222 + t 223 + (** Construct an HTTP URI. *) 224 + 225 + val scheme : t -> [ `Http | `Https ] 226 + (** Get the scheme. *) 298 227 299 228 val host : t -> string 300 - val scheme : t -> [`Http | `Https] 229 + (** Get the host (always present for HTTP URIs). *) 301 230 end