A batteries included HTTP/1.1 client in OCaml
at main 81 lines 2.8 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** Tests for Proxy_tunnel module *) 7 8module Proxy = Requests.Proxy 9module Proxy_tunnel = Requests.Proxy_tunnel 10 11(** Helper to capture Buf_write output into a string *) 12let buf_write_to_string f = 13 let buf = Buffer.create 256 in 14 Eio.Buf_write.with_flow (Eio.Flow.buffer_sink buf) (fun w -> f w); 15 Buffer.contents buf 16 17(** {1 write_connect_request Tests} *) 18 19let test_write_connect_request_basic () = 20 Eio_main.run @@ fun _env -> 21 let proxy = Proxy.http "proxy.example.com" in 22 let output = 23 buf_write_to_string (fun w -> 24 Proxy_tunnel.write_connect_request w ~proxy 25 ~target_host:"api.example.com" ~target_port:443) 26 in 27 (* Check request line *) 28 Alcotest.(check bool) 29 "contains CONNECT" true 30 (String.length output > 0 && String.sub output 0 7 = "CONNECT"); 31 Alcotest.(check bool) 32 "contains target" true 33 (let pat = "CONNECT api.example.com:443 HTTP/1.1\r\n" in 34 String.length output >= String.length pat 35 && String.sub output 0 (String.length pat) = pat); 36 (* Check Host header *) 37 let has_host = 38 let pat = "Host: api.example.com:443\r\n" in 39 let rec find i = 40 if i + String.length pat > String.length output then false 41 else if String.sub output i (String.length pat) = pat then true 42 else find (i + 1) 43 in 44 find 0 45 in 46 Alcotest.(check bool) "contains Host header" true has_host; 47 (* Check ends with \r\n\r\n *) 48 let len = String.length output in 49 Alcotest.(check bool) 50 "ends with CRLFCRLF" true 51 (len >= 4 && String.sub output (len - 4) 4 = "\r\n\r\n") 52 53let test_write_connect_with_auth () = 54 Eio_main.run @@ fun _env -> 55 let auth = Requests.Auth.basic ~username:"user" ~password:"pass" in 56 let proxy = Proxy.http ~auth "proxy.example.com" in 57 let output = 58 buf_write_to_string (fun w -> 59 Proxy_tunnel.write_connect_request w ~proxy ~target_host:"target.com" 60 ~target_port:443) 61 in 62 (* Check that Proxy-Authorization header is present *) 63 let has_proxy_auth = 64 let pat = "Proxy-Authorization: " in 65 let rec find i = 66 if i + String.length pat > String.length output then false 67 else if String.sub output i (String.length pat) = pat then true 68 else find (i + 1) 69 in 70 find 0 71 in 72 Alcotest.(check bool) "contains Proxy-Authorization" true has_proxy_auth 73 74(** {1 Test Suite} *) 75 76let suite = 77 ( "proxy_tunnel", 78 [ 79 Alcotest.test_case "basic CONNECT" `Quick test_write_connect_request_basic; 80 Alcotest.test_case "with proxy auth" `Quick test_write_connect_with_auth; 81 ] )