forked from
anil.recoil.org/ocaml-requests
A batteries included HTTP/1.1 client in OCaml
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 ] )