A batteries included HTTP/1.1 client in OCaml
at main 136 lines 4.5 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** HTTP Proxy Configuration 7 8 Per RFC 9110 Section 3.7 and Section 7.3.2: A proxy is a message-forwarding 9 agent chosen by the client, usually configured via local rules. 10 11 {2 Usage} 12 13 Create a proxy configuration: 14 {[ 15 let proxy = Proxy.http ~port:8080 "proxy.example.com" 16 17 (* With authentication *) 18 let proxy = 19 Proxy.http ~port:8080 20 ~auth:(Auth.basic ~username:"user" ~password:"pass") 21 "proxy.example.com" 22 23 (* With bypass list *) 24 let proxy = 25 Proxy.http 26 ~no_proxy:[ "localhost"; "*.internal.example.com" ] 27 "proxy.example.com" 28 ]} 29 30 Read from environment variables: 31 {[ 32 match Proxy.from_env () with 33 | Some proxy -> (* use proxy *) 34 | None -> (* no proxy configured *) 35 ]} *) 36 37val src : Logs.Src.t 38(** Log source for proxy operations. *) 39 40(** {1 Proxy Types} *) 41 42(** Proxy protocol type *) 43type kind = 44 | HTTP (** HTTP proxy (CONNECT for HTTPS, absolute-URI for HTTP) *) 45 | SOCKS5 (** SOCKS5 proxy (RFC 1928) - future extension *) 46 47type config = { 48 host : string; (** Proxy server hostname *) 49 port : int; (** Proxy server port (default: 8080) *) 50 kind : kind; 51 auth : Auth.t option; (** Proxy authentication (Proxy-Authorization) *) 52 no_proxy : string list; (** Hosts/patterns to bypass proxy *) 53} 54(** Proxy configuration *) 55 56(** {1 Configuration Constructors} *) 57 58val http : 59 ?port:int -> ?auth:Auth.t -> ?no_proxy:string list -> string -> config 60(** [http ?port ?auth ?no_proxy host] creates an HTTP proxy configuration. 61 62 @param port Proxy port (default: 8080) 63 @param auth Proxy authentication credentials 64 @param no_proxy 65 List of hosts/patterns to bypass the proxy. Supports wildcards like 66 [*.example.com] to match [foo.example.com]. 67 @param host Proxy server hostname. *) 68 69val socks5 : 70 ?port:int -> ?auth:Auth.t -> ?no_proxy:string list -> string -> config 71(** [socks5 ?port ?auth ?no_proxy host] creates a SOCKS5 proxy configuration. 72 73 {b Note:} SOCKS5 support is not yet implemented. This function creates the 74 configuration type for future use. 75 76 @param port Proxy port (default: 1080) 77 @param auth Proxy authentication credentials 78 @param no_proxy List of hosts/patterns to bypass the proxy 79 @param host Proxy server hostname. *) 80 81(** {1 Configuration Utilities} *) 82 83val should_bypass : config -> string -> bool 84(** [should_bypass config url] returns [true] if [url] should bypass the proxy 85 based on the [no_proxy] list. 86 87 Matching rules: 88 - Exact hostname match (case-insensitive) 89 - Wildcard prefix match: [*.example.com] matches [foo.example.com] 90 - [localhost] and [127.0.0.1] match by default if in no_proxy list. *) 91 92val host_port : config -> string * int 93(** [host_port config] returns the proxy host and port as a tuple. *) 94 95val validate_supported : config -> unit 96(** [validate_supported config] checks that the proxy type is currently 97 supported. 98 @raise Error.Proxy_error if SOCKS5 is requested (not yet implemented). *) 99 100(** {1 Environment Variable Support} *) 101 102val from_env : unit -> config option 103(** [from_env ()] reads proxy configuration from environment variables. 104 105 Checks the following variables (in order of preference): 106 - [HTTP_PROXY] / [http_proxy] 107 - [HTTPS_PROXY] / [https_proxy] 108 - [ALL_PROXY] / [all_proxy] 109 - [NO_PROXY] / [no_proxy] (comma-separated list of bypass patterns) 110 111 Returns [None] if no proxy is configured. 112 113 URL format: [http://[user:pass@]host[:port]] 114 115 Example environment: 116 {[ 117 HTTP_PROXY=http://user:pass@proxy.example.com:8080 118 NO_PROXY=localhost,*.internal.example.com,.example.org 119 ]}. *) 120 121val from_env_for_url : string -> config option 122(** [from_env_for_url url] reads proxy configuration appropriate for [url]. 123 124 - Uses [HTTPS_PROXY] for HTTPS URLs 125 - Uses [HTTP_PROXY] for HTTP URLs 126 - Falls back to [ALL_PROXY] 127 - Returns [None] if the URL matches [NO_PROXY] patterns. *) 128 129(** {1 Pretty Printing} *) 130 131val pp_kind : Format.formatter -> kind -> unit 132(** Pretty printer for proxy type. *) 133 134val pp_config : Format.formatter -> config -> unit 135(** Pretty printer for proxy configuration. Note: Authentication credentials are 136 redacted. *)