tangled
alpha
login
or
join now
anil.recoil.org
/
ocaml-requests
1
fork
atom
A batteries included HTTP/1.1 client in OCaml
1
fork
atom
overview
issues
pulls
pipelines
more
anil.recoil.org
2 months ago
bb08e520
08bff2d3
-654
1 changed file
expand all
collapse all
unified
split
RECOMMENDATIONS.md
-654
RECOMMENDATIONS.md
···
1
1
-
# OCaml HTTP Client Library - Priority Feature Recommendations
2
2
-
3
3
-
> Auto-generated summary of recommendations from analyzing HTTP client libraries across multiple languages.
4
4
-
5
5
-
## Implementation Status Summary
6
6
-
7
7
-
| Status | Count | Description |
8
8
-
|--------|-------|-------------|
9
9
-
| ✅ Implemented | 15 | Fully implemented and tested |
10
10
-
| 🔧 Partial | 1 | Partially implemented |
11
11
-
| ❌ Not Started | 14 | Not yet implemented |
12
12
-
13
13
-
### Implemented Features
14
14
-
15
15
-
| # | Feature | Location |
16
16
-
|---|---------|----------|
17
17
-
| 1 | Strip sensitive headers on cross-origin redirects | `lib/requests.ml`, `lib/one.ml` |
18
18
-
| 3 | Enforce HTTPS for sensitive authentication | `lib/auth.ml` (`apply_secure`, `Insecure_auth` error) |
19
19
-
| 4 | Content-Length vs Transfer-Encoding precedence | `lib/http_read.ml` (RFC 9112 warning) |
20
20
-
| 5 | Cap maximum Retry-After delay | `lib/retry.ml` (`backoff_max` parameter) |
21
21
-
| 11 | Base URL support with relative path resolution | `lib/requests.ml` (`base_url`, `resolve_url`) |
22
22
-
| 12 | Detailed timing metrics | `lib/timing.ml` (new module) |
23
23
-
| 13 | Stale connection detection | `ocaml-conpool/lib/conpool.ml` (`is_healthy`) |
24
24
-
| 14 | Custom retry condition predicates | `lib/retry.ml` (`response_predicate`, `exception_predicate`) |
25
25
-
| 19 | Link header parsing for pagination | `lib/link.ml` (new module) |
26
26
-
| 21 | Result-based error_for_status variant | `lib/response.ml` (`check_status`) |
27
27
-
| 24 | XSRF/CSRF token handling | `lib/requests.ml` (`apply_xsrf_token`) |
28
28
-
| 25 | Decompression bomb protection | `lib/http_client.ml` (`check_decompression_limits`) |
29
29
-
| 26 | HTTP version in response metadata | `lib/http_read.ml` (`http_version` type) |
30
30
-
| 28 | Restrict URL protocols to HTTP/HTTPS | `lib/requests.ml`, `lib/one.ml` (`validate_redirect_url`) |
31
31
-
| 29 | Path parameter templating | `lib/requests.ml` (`substitute_path_params`) |
32
32
-
| 30 | Default User-Agent header | `lib/version.ml`, applied in `lib/requests.ml` |
33
33
-
34
34
-
### Not Yet Implemented
35
35
-
36
36
-
| # | Feature | Priority |
37
37
-
|---|---------|----------|
38
38
-
| 2 | Certificate/public key pinning | High |
39
39
-
| 6 | HTTP proxy support | High |
40
40
-
| 7 | Request/response middleware system | Medium |
41
41
-
| 8 | Progress callbacks | Medium |
42
42
-
| 9 | Request cancellation | Medium |
43
43
-
| 10 | Concurrent request batching | Low |
44
44
-
| 15 | Charset/encoding detection | Low |
45
45
-
| 16 | Redirect policy customization | Low |
46
46
-
| 17 | TCP keep-alive configuration | Low |
47
47
-
| 18 | URL sanitization for error messages | Low |
48
48
-
| 20 | Mock handler for testing | Medium |
49
49
-
| 22 | Request body rewind for retries | Medium |
50
50
-
| 23 | Event listener/hooks | Low |
51
51
-
| 27 | Unix domain socket support | Low |
52
52
-
53
53
-
---
54
54
-
55
55
-
## Executive Summary
56
56
-
57
57
-
This comprehensive analysis synthesizes recommendations from 45+ HTTP client libraries across 10 programming languages (Python, JavaScript, Go, Rust, Haskell, PHP, Java, Swift, C++, Bash). The most consistent themes are: (1) Security features like certificate pinning, cross-origin header stripping, and HTTPS enforcement for sensitive auth; (2) Middleware/interceptor systems for extensibility; (3) HTTP proxy support; (4) Progress callbacks for uploads/downloads; (5) Request cancellation capabilities; (6) Detailed timing metrics; (7) Retry logic improvements including Retry-After capping and custom predicates. The prioritization emphasizes security fixes that could lead to credential leakage, followed by missing features that block enterprise adoption (proxy support), then enhancements that improve developer experience.
58
58
-
59
59
-
60
60
-
---
61
61
-
62
62
-
## Security & Spec Compliance
63
63
-
64
64
-
### 1. ✅ Strip sensitive headers on cross-origin redirects
65
65
-
66
66
-
**Status: IMPLEMENTED** in `lib/requests.ml` and `lib/one.ml`
67
67
-
68
68
-
When redirecting to a different origin (host/port/scheme), automatically strip Authorization, Cookie, Proxy-Authorization, and WWW-Authenticate headers to prevent credential leakage to unintended domains. Also strip headers on HTTPS→HTTP protocol downgrade.
69
69
-
70
70
-
**RFC References:**
71
71
-
- RFC 9110 Section 15.4 (Redirection)
72
72
-
73
73
-
**Cross-Language Consensus:** 8 libraries
74
74
-
**Source Libraries:** reqwest, got, node-fetch, okhttp, axios, superagent, http-client, needle
75
75
-
76
76
-
**Implementation:**
77
77
-
- `same_origin` function compares scheme and host
78
78
-
- `strip_sensitive_headers` removes Authorization, Cookie, Proxy-Authorization, WWW-Authenticate
79
79
-
- Applied during redirect handling in `make_with_redirects`
80
80
-
81
81
-
### 2. ❌ Add certificate/public key pinning support
82
82
-
83
83
-
**Status: NOT IMPLEMENTED** - High priority for enterprise security
84
84
-
85
85
-
Allow pinning certificates or public keys (SPKI hashes) to protect against compromised certificate authorities. Support per-host pinning configuration with wildcard patterns.
86
86
-
87
87
-
**RFC References:**
88
88
-
- RFC 7469 (Public Key Pinning for HTTP)
89
89
-
90
90
-
**Cross-Language Consensus:** 4 libraries
91
91
-
**Source Libraries:** okhttp, swifthttp, urllib3, alamofire
92
92
-
93
93
-
**Affected Files:**
94
94
-
- `lib/requests.ml`
95
95
-
- `lib/requests.mli`
96
96
-
97
97
-
**Implementation Notes:**
98
98
-
Add certificate_pins parameter to create() accepting (hostname * sha256_hash list) list. Verify pins during TLS handshake by extracting SPKI from certificate chain. Provide helpful error messages showing expected vs actual hashes.
99
99
-
100
100
-
### 3. ✅ Enforce HTTPS for sensitive authentication methods
101
101
-
102
102
-
**Status: IMPLEMENTED** in `lib/auth.ml`
103
103
-
104
104
-
Reject Basic, Bearer, and Digest authentication over unencrypted HTTP connections by default. Provide explicit opt-out flag (allow_insecure_auth) for testing environments.
105
105
-
106
106
-
**RFC References:**
107
107
-
- RFC 7617 Section 4 (Basic Authentication Security)
108
108
-
- RFC 6750 Section 5.1 (Bearer Token Security)
109
109
-
110
110
-
**Cross-Language Consensus:** 2 libraries
111
111
-
**Source Libraries:** req (Haskell), urllib3
112
112
-
113
113
-
**Implementation:**
114
114
-
- `Auth.apply_secure` validates transport security before applying auth
115
115
-
- `Auth.validate_secure_transport` checks if HTTPS is required
116
116
-
- `Error.Insecure_auth` error type for clear error messages
117
117
-
- `allow_insecure_auth` parameter in request functions for testing
118
118
-
119
119
-
### 4. ✅ Validate Content-Length vs Transfer-Encoding precedence
120
120
-
121
121
-
**Status: IMPLEMENTED** in `lib/http_read.ml`
122
122
-
123
123
-
Per RFC 9112, when both Content-Length and Transfer-Encoding headers are present, ignore Content-Length. This prevents HTTP request smuggling attacks.
124
124
-
125
125
-
**RFC References:**
126
126
-
- RFC 9112 Section 6.3 (Message Body Length)
127
127
-
128
128
-
**Cross-Language Consensus:** 2 libraries
129
129
-
**Source Libraries:** hyper, http-streams
130
130
-
131
131
-
**Implementation:**
132
132
-
- Transfer-Encoding: chunked takes precedence over Content-Length
133
133
-
- Warning logged when both headers present (potential attack indicator)
134
134
-
- Per RFC 9112 Section 6.3 compliance
135
135
-
136
136
-
### 5. ✅ Cap maximum Retry-After delay to prevent DoS
137
137
-
138
138
-
**Status: IMPLEMENTED** in `lib/retry.ml`
139
139
-
140
140
-
Implement a configurable maximum backoff time (default 120s) that caps server-specified Retry-After values, preventing malicious servers from causing indefinite client blocking.
141
141
-
142
142
-
**RFC References:**
143
143
-
- RFC 9110 Section 10.2.3 (Retry-After)
144
144
-
145
145
-
**Cross-Language Consensus:** 2 libraries
146
146
-
**Source Libraries:** req (Go), got
147
147
-
148
148
-
**Implementation:**
149
149
-
- `backoff_max` field in `Retry.config` (default: 120.0 seconds)
150
150
-
- `parse_retry_after` function accepts `?backoff_max` parameter
151
151
-
- Delays exceeding cap are logged as warnings and capped
152
152
-
153
153
-
154
154
-
---
155
155
-
156
156
-
## Feature Enhancements
157
157
-
158
158
-
### 6. ❌ Add HTTP proxy support with environment variable detection
159
159
-
160
160
-
**Status: NOT IMPLEMENTED** - High priority, see `spec/PROXY_IMPLEMENTATION_PLAN.md`
161
161
-
162
162
-
Implement HTTP/HTTPS proxy support including: proxy URL configuration, authentication (Basic), CONNECT method for HTTPS tunneling, and automatic detection from HTTP_PROXY, HTTPS_PROXY, NO_PROXY environment variables.
163
163
-
164
164
-
**RFC References:**
165
165
-
- RFC 9110 Section 9.3.6 (CONNECT)
166
166
-
- RFC 7235 (HTTP Authentication)
167
167
-
168
168
-
**Cross-Language Consensus:** 7 libraries
169
169
-
**Source Libraries:** reqwest, axios, guzzle, http-client, requests (Go), resty, isahc
170
170
-
171
171
-
**Affected Files:**
172
172
-
- `lib/requests.ml`
173
173
-
- `lib/requests.mli`
174
174
-
- `lib/http_client.ml`
175
175
-
- `lib/one.ml`
176
176
-
177
177
-
**Implementation Notes:**
178
178
-
A comprehensive implementation plan exists in `spec/PROXY_IMPLEMENTATION_PLAN.md` with 8 phases covering proxy configuration, HTTP CONNECT tunneling, environment variable detection, NO_PROXY pattern matching, and proxy authentication.
179
179
-
180
180
-
### 7. ❌ Implement request/response middleware system
181
181
-
182
182
-
**Status: NOT IMPLEMENTED** - Medium priority
183
183
-
184
184
-
Add a composable middleware chain that allows intercepting and transforming requests before sending and responses after receiving. Enable cross-cutting concerns like logging, metrics, request signing, and custom caching.
185
185
-
186
186
-
**Cross-Language Consensus:** 9 libraries
187
187
-
**Source Libraries:** surf, got, axios, guzzle, okhttp, resty, buzz, moya, req (Go)
188
188
-
189
189
-
**Affected Files:**
190
190
-
- `lib/requests.ml`
191
191
-
- `lib/requests.mli`
192
192
-
193
193
-
**Implementation Notes:**
194
194
-
Define type middleware = Request.t -> (Request.t -> Response.t) -> Response.t. Store middleware list in session. Execute chain: apply each middleware wrapping the next. Provide default middleware for retry and redirect as replaceable components.
195
195
-
196
196
-
### 8. ❌ Add progress callbacks for uploads and downloads
197
197
-
198
198
-
**Status: NOT IMPLEMENTED** - Medium priority
199
199
-
200
200
-
Implement optional progress callbacks that report bytes transferred, total size (if known), and percent complete. Rate-limit callbacks to prevent performance degradation.
201
201
-
202
202
-
**Cross-Language Consensus:** 9 libraries
203
203
-
**Source Libraries:** curl-rust, got, axios, guzzle, resty, req (Go), kingfisher, net (Swift), http-request (Java)
204
204
-
205
205
-
**Affected Files:**
206
206
-
- `lib/requests.ml`
207
207
-
- `lib/body.ml`
208
208
-
- `lib/http_client.ml`
209
209
-
- `lib/one.ml`
210
210
-
211
211
-
**Implementation Notes:**
212
212
-
Add optional progress:(transferred:int64 -> total:int64 option -> unit) parameter. Track bytes during streaming read/write. Throttle callbacks (e.g., max 3/second or every 64KB). Support both upload and download progress.
213
213
-
214
214
-
### 9. ❌ Add request cancellation support
215
215
-
216
216
-
**Status: NOT IMPLEMENTED** - Medium priority (Eio provides natural cancellation via switches)
217
217
-
218
218
-
Allow programmatic cancellation of in-flight requests. Integrate with Eio's cancellation system while providing explicit cancel() function or cancel token pattern.
219
219
-
220
220
-
**Cross-Language Consensus:** 6 libraries
221
221
-
**Source Libraries:** got, axios, okhttp, needle, just, hyper
222
222
-
223
223
-
**Affected Files:**
224
224
-
- `lib/requests.ml`
225
225
-
- `lib/requests.mli`
226
226
-
- `lib/one.ml`
227
227
-
228
228
-
**Implementation Notes:**
229
229
-
Return (Response.t * cancel_token) from request functions where cancel_token allows aborting the request. Internally use Eio.Cancel or Switch.fail to terminate the fiber. Raise Cancelled error on cancellation.
230
230
-
231
231
-
### 10. ❌ Add concurrent request batching API (map/imap)
232
232
-
233
233
-
**Status: NOT IMPLEMENTED** - Low priority (Eio.Fiber.all/both provides this)
234
234
-
235
235
-
Provide map() for executing multiple requests concurrently and returning results in order, and imap() for yielding responses as they complete. Include configurable concurrency limits and batch timeout.
236
236
-
237
237
-
**Cross-Language Consensus:** 2 libraries
238
238
-
**Source Libraries:** grequests, aiohttp
239
239
-
240
240
-
**Affected Files:**
241
241
-
- `lib/requests.ml`
242
242
-
- `lib/requests.mli`
243
243
-
244
244
-
**Implementation Notes:**
245
245
-
Implement using Eio.Fiber.all for map, Eio.Stream for imap. Add max_concurrent parameter using Eio.Semaphore. Provide exception_handler callback for partial failure handling. Add batch_timeout for overall operation limit.
246
246
-
247
247
-
### 11. ✅ Add base URL support with relative path resolution
248
248
-
249
249
-
**Status: IMPLEMENTED** in `lib/requests.ml`
250
250
-
251
251
-
Allow configuring a base URL on the session that is prepended to relative request URLs. Use proper RFC 3986 URI resolution for correct path joining.
252
252
-
253
253
-
**RFC References:**
254
254
-
- RFC 3986 Section 5 (Reference Resolution)
255
255
-
256
256
-
**Cross-Language Consensus:** 5 libraries
257
257
-
**Source Libraries:** surf, axios, got, sling, req (Go)
258
258
-
259
259
-
**Implementation:**
260
260
-
- `base_url` parameter in `create` function
261
261
-
- `is_relative_url` checks if URL has scheme
262
262
-
- `resolve_url` uses `Uri.resolve` for RFC 3986 compliant resolution
263
263
-
- Trailing slashes automatically normalized
264
264
-
265
265
-
266
266
-
---
267
267
-
268
268
-
## Architectural Improvements
269
269
-
270
270
-
### 12. ✅ Add detailed timing metrics to responses
271
271
-
272
272
-
**Status: IMPLEMENTED** in new `lib/timing.ml` module
273
273
-
274
274
-
Expose granular timing breakdown: DNS lookup time, TCP connection time, TLS handshake time, time to first byte (TTFB), download time, and total time. Include connection reuse tracking.
275
275
-
276
276
-
**Cross-Language Consensus:** 7 libraries
277
277
-
**Source Libraries:** curl-rust, got, resty, req (Go), guzzle, okhttp, isahc
278
278
-
279
279
-
**Implementation:**
280
280
-
- New `Timing` module with detailed metrics type
281
281
-
- Phases: `dns_lookup`, `tcp_connect`, `tls_handshake`, `request_sent`, `time_to_first_byte`, `content_transfer`, `total`
282
282
-
- `timer` type for incremental collection during requests
283
283
-
- `connection_time` and `server_time` computed metrics
284
284
-
- Pretty-printing with `pp` and `to_string`
285
285
-
286
286
-
### 13. ✅ Add automatic retry on stale connection detection
287
287
-
288
288
-
**Status: IMPLEMENTED** in `ocaml-conpool` library
289
289
-
290
290
-
Detect when a pooled connection was closed by the server between requests (NoResponseDataReceived) and automatically retry with a fresh connection. Mark this error as always retryable.
291
291
-
292
292
-
**Cross-Language Consensus:** 2 libraries
293
293
-
**Source Libraries:** http-client (Haskell), okhttp
294
294
-
295
295
-
**Implementation:**
296
296
-
The `ocaml-conpool` library provides comprehensive stale connection detection via:
297
297
-
- `is_healthy` function checking age, idle time, and use count
298
298
-
- `max_idle_time` configuration (default: 60s)
299
299
-
- `max_connection_lifetime` configuration (default: 300s)
300
300
-
- `max_connection_uses` configuration (optional)
301
301
-
- Custom `health_check` callback support
302
302
-
- Pool `validate` function runs health checks before connection reuse
303
303
-
304
304
-
### 14. ✅ Add custom retry condition predicates
305
305
-
306
306
-
**Status: IMPLEMENTED** in `lib/retry.ml`
307
307
-
308
308
-
Allow users to provide custom retry decision functions beyond status codes and error types. Separate predicates for response-based retry (status/headers) and exception-based retry.
309
309
-
310
310
-
**Cross-Language Consensus:** 4 libraries
311
311
-
**Source Libraries:** resty, got, req (Go), req (Haskell)
312
312
-
313
313
-
**Implementation:**
314
314
-
- `response_predicate` type: `Method.t -> int -> Headers.t -> bool`
315
315
-
- `exception_predicate` type: `exn -> bool`
316
316
-
- `retry_response` and `retry_exception` fields in `Retry.config`
317
317
-
- `should_retry_response` checks both built-in rules and custom predicates
318
318
-
- `should_retry_exn` for exception-based retry decisions
319
319
-
- Examples in module documentation
320
320
-
321
321
-
322
322
-
---
323
323
-
324
324
-
## Feature Enhancements
325
325
-
326
326
-
### 15. ❌ Add response charset/encoding detection and conversion
327
327
-
328
328
-
**Status: NOT IMPLEMENTED** - Low priority
329
329
-
330
330
-
Automatically detect character encoding from Content-Type charset parameter and convert response text to UTF-8. Provide BOM sniffing fallback for encoding detection.
331
331
-
332
332
-
**RFC References:**
333
333
-
- RFC 9110 Section 8.3.1 (Content-Type)
334
334
-
335
335
-
**Cross-Language Consensus:** 6 libraries
336
336
-
**Source Libraries:** reqwest, surf, isahc, needle, got, http-request (Java)
337
337
-
338
338
-
**Affected Files:**
339
339
-
- `lib/response.ml`
340
340
-
- `lib/response.mli`
341
341
-
- `lib/http_read.ml`
342
342
-
343
343
-
**Implementation Notes:**
344
344
-
Parse charset from Content-Type in Mime module. Add Response.text_utf8 that detects and converts encoding. Use uutf library for encoding conversion. Return raw bytes on conversion failure with access to detected charset.
345
345
-
346
346
-
### 16. ❌ Add redirect policy customization
347
347
-
348
348
-
**Status: NOT IMPLEMENTED** - Low priority
349
349
-
350
350
-
Allow custom redirect policies with access to attempt status, URL, and previous URLs. Enable controlling method preservation (307/308 vs 301/302), header stripping, and cross-protocol redirect behavior.
351
351
-
352
352
-
**RFC References:**
353
353
-
- RFC 9110 Section 15.4 (Redirection 3xx)
354
354
-
355
355
-
**Cross-Language Consensus:** 5 libraries
356
356
-
**Source Libraries:** reqwest, needle, node-fetch, guzzle, http-client (Haskell)
357
357
-
358
358
-
**Affected Files:**
359
359
-
- `lib/requests.ml`
360
360
-
- `lib/requests.mli`
361
361
-
362
362
-
**Implementation Notes:**
363
363
-
Add redirect_policy type with hooks: before_redirect:(request -> response -> uri -> bool), strip_headers:(origin_changed -> header_name -> bool). Implement RFC-correct 301/302 POST→GET conversion. Provide presets: follow_all, same_host_only, same_protocol_only.
364
364
-
365
365
-
366
366
-
---
367
367
-
368
368
-
## Architectural Improvements
369
369
-
370
370
-
### 17. ❌ Add TCP keep-alive configuration
371
371
-
372
372
-
**Status: NOT IMPLEMENTED** - Low priority
373
373
-
374
374
-
Expose TCP keep-alive settings including enable/disable, interval, and retry count. This helps detect broken connections and maintain long-lived connections through firewalls/NAT.
375
375
-
376
376
-
**Cross-Language Consensus:** 3 libraries
377
377
-
**Source Libraries:** reqwest, isahc, curl-rust
378
378
-
379
379
-
**Affected Files:**
380
380
-
- `lib/requests.mli`
381
381
-
- `lib/http_client.ml`
382
382
-
383
383
-
**Implementation Notes:**
384
384
-
Add tcp_keepalive_interval and tcp_keepalive option to session config. Configure socket options via Eio.Net during connection establishment. Default to reasonable values (e.g., 60s interval).
385
385
-
386
386
-
387
387
-
---
388
388
-
389
389
-
## Feature Enhancements
390
390
-
391
391
-
### 18. ❌ Add URL sanitization for error messages
392
392
-
393
393
-
**Status: NOT IMPLEMENTED** - Low priority
394
394
-
395
395
-
Automatically sanitize URLs in error messages to prevent leakage of credentials embedded in query parameters (API keys, tokens). Provide without_url() method to strip URLs entirely.
396
396
-
397
397
-
**Cross-Language Consensus:** 1 libraries
398
398
-
**Source Libraries:** reqwest
399
399
-
400
400
-
**Affected Files:**
401
401
-
- `lib/error.ml`
402
402
-
- `lib/error.mli`
403
403
-
404
404
-
**Implementation Notes:**
405
405
-
Extend existing sanitize_url function to handle query parameter credentials. Add Error.without_url to remove URL entirely from error. Apply sanitization automatically in Error.to_string and pp functions.
406
406
-
407
407
-
### 19. ✅ Add Link header parsing for pagination
408
408
-
409
409
-
**Status: IMPLEMENTED** in new `lib/link.ml` module
410
410
-
411
411
-
Parse RFC 8288 Link headers to extract relation types (next, prev, first, last) for API pagination. Provide helpers like Response.next_url for common patterns.
412
412
-
413
413
-
**RFC References:**
414
414
-
- RFC 8288 (Web Linking)
415
415
-
416
416
-
**Cross-Language Consensus:** 3 libraries
417
417
-
**Source Libraries:** got, superagent, just
418
418
-
419
419
-
**Implementation:**
420
420
-
- New `Link` module with RFC 8288 compliant parsing
421
421
-
- `Link.t` type with `uri`, `rel`, `title`, `media_type`, `hreflang`, `params`
422
422
-
- `parse` function handles comma-separated links with quoted values
423
423
-
- `from_headers` extracts Link header from response headers
424
424
-
- `pagination` returns `(first, prev, next, last)` tuple
425
425
-
- `next_url`, `prev_url`, `has_next` convenience functions
426
426
-
- Pretty-printing with `pp` and `to_string`
427
427
-
428
428
-
429
429
-
---
430
430
-
431
431
-
## Architectural Improvements
432
432
-
433
433
-
### 20. ❌ Add mock handler for testing
434
434
-
435
435
-
**Status: NOT IMPLEMENTED** - Medium priority
436
436
-
437
437
-
Provide a mock handler that queues pre-defined responses and exceptions for testing HTTP client code without network calls. Support request inspection and assertion.
438
438
-
439
439
-
**Cross-Language Consensus:** 3 libraries
440
440
-
**Source Libraries:** guzzle, okhttp, resty
441
441
-
442
442
-
**Affected Files:**
443
443
-
- `lib/http_client.ml`
444
444
-
- `test/`
445
445
-
446
446
-
**Implementation Notes:**
447
447
-
Create Mock module with queue of responses/exceptions. Replace actual HTTP client in test mode. Track all requests made for assertions. Allow configuring delays for timeout testing.
448
448
-
449
449
-
450
450
-
---
451
451
-
452
452
-
## Feature Enhancements
453
453
-
454
454
-
### 21. ✅ Add Result-based error_for_status variant
455
455
-
456
456
-
**Status: IMPLEMENTED** in `lib/response.ml`
457
457
-
458
458
-
Provide check_status() that returns (Response.t, Error.error) result instead of raising, enabling functional error handling alongside the existing raise_for_status.
459
459
-
460
460
-
**Cross-Language Consensus:** 2 libraries
461
461
-
**Source Libraries:** reqwest, grequests
462
462
-
463
463
-
**Implementation:**
464
464
-
- `Response.check_status : t -> (t, Error.t) result`
465
465
-
- Returns `Ok response` for 2xx status codes
466
466
-
- Returns `Error (Http_error {...})` for 4xx/5xx status codes
467
467
-
- Complements existing `raise_for_status` for functional style
468
468
-
469
469
-
### 22. ❌ Add request body rewind support for retries
470
470
-
471
471
-
**Status: NOT IMPLEMENTED** - Medium priority
472
472
-
473
473
-
Track whether request bodies are rewindable (seekable) and automatically replay them on retry. Raise clear error when retry requires body replay but body is a consumed stream.
474
474
-
475
475
-
**Cross-Language Consensus:** 4 libraries
476
476
-
**Source Libraries:** isahc, curl-rust, surf, node-fetch
477
477
-
478
478
-
**Affected Files:**
479
479
-
- `lib/body.ml`
480
480
-
- `lib/retry.ml`
481
481
-
- `lib/error.ml`
482
482
-
483
483
-
**Implementation Notes:**
484
484
-
Add is_rewindable field to Body.t. For Body.String/Form, rewindable=true. For Stream without seek, rewindable=false. In retry, check rewindability; raise Body_not_rewindable if retry needed but body consumed.
485
485
-
486
486
-
487
487
-
---
488
488
-
489
489
-
## Architectural Improvements
490
490
-
491
491
-
### 23. ❌ Add event listener/hooks for observability
492
492
-
493
493
-
**Status: NOT IMPLEMENTED** - Low priority
494
494
-
495
495
-
Provide comprehensive event hooks at each request lifecycle stage: DNS start/end, connection start/end, TLS handshake, request headers/body sent, response headers/body received. Enable metrics and tracing integration.
496
496
-
497
497
-
**Cross-Language Consensus:** 3 libraries
498
498
-
**Source Libraries:** okhttp, resty, http-streams
499
499
-
500
500
-
**Affected Files:**
501
501
-
- `lib/requests.ml`
502
502
-
- `lib/requests.mli`
503
503
-
- `lib/http_client.ml`
504
504
-
505
505
-
**Implementation Notes:**
506
506
-
Define event types: Dns_start, Dns_end, Connect_start, etc. Add event_listener callback to session config. Emit events at appropriate points in http_client.ml. Include timing and context in each event.
507
507
-
508
508
-
509
509
-
---
510
510
-
511
511
-
## Feature Enhancements
512
512
-
513
513
-
### 24. ✅ Add XSRF/CSRF token handling
514
514
-
515
515
-
**Status: IMPLEMENTED** in `lib/requests.ml`
516
516
-
517
517
-
Automatically read CSRF token from a configurable cookie name (default: XSRF-TOKEN) and add it to request headers (default: X-XSRF-TOKEN) for same-origin requests.
518
518
-
519
519
-
**Cross-Language Consensus:** 1 libraries
520
520
-
**Source Libraries:** axios
521
521
-
522
522
-
**Implementation:**
523
523
-
- `xsrf_cookie_name` parameter (default: `Some "XSRF-TOKEN"`)
524
524
-
- `xsrf_header_name` parameter (default: `"X-XSRF-TOKEN"`)
525
525
-
- `apply_xsrf_token` function reads cookie and injects header
526
526
-
- Set `xsrf_cookie_name` to `None` to disable
527
527
-
- Applied automatically in `make_request_internal`
528
528
-
529
529
-
530
530
-
---
531
531
-
532
532
-
## Architectural Improvements
533
533
-
534
534
-
### 25. ✅ Add decompression bomb protection
535
535
-
536
536
-
**Status: IMPLEMENTED** in `lib/http_client.ml`
537
537
-
538
538
-
Enforce configurable compression ratio limits (e.g., 100:1) to detect and abort decompression bomb attacks. Track compressed vs decompressed bytes during streaming.
539
539
-
540
540
-
**Cross-Language Consensus:** 1 libraries
541
541
-
**Source Libraries:** axios
542
542
-
543
543
-
**Implementation:**
544
544
-
- `check_decompression_limits` function validates size and ratio
545
545
-
- `max_decompressed_size` in `Response_limits` (absolute size limit)
546
546
-
- `max_compression_ratio` in `Response_limits` (ratio limit)
547
547
-
- `Error.Decompression_bomb` error type with limit and ratio info
548
548
-
- Applied during gzip/deflate/zlib decompression
549
549
-
550
550
-
551
551
-
---
552
552
-
553
553
-
## Feature Enhancements
554
554
-
555
555
-
### 26. ✅ Add HTTP version to response metadata
556
556
-
557
557
-
**Status: IMPLEMENTED** in `lib/http_read.ml`
558
558
-
559
559
-
Expose the HTTP version used for the response (HTTP/1.0, HTTP/1.1, HTTP/2) in Response type. Useful for debugging protocol negotiation and monitoring HTTP/2 adoption.
560
560
-
561
561
-
**Cross-Language Consensus:** 3 libraries
562
562
-
**Source Libraries:** reqwest, surf, curl-rust
563
563
-
564
564
-
**Implementation:**
565
565
-
- `http_version` type: `HTTP_1_0 | HTTP_1_1`
566
566
-
- `http_version_to_string` for display
567
567
-
- `status_line` returns `(http_version, status_code)` tuple
568
568
-
- `response` function returns `(http_version, status, headers, body)`
569
569
-
- `stream_response` includes `http_version` field
570
570
-
571
571
-
### 27. ❌ Add Unix domain socket support
572
572
-
573
573
-
**Status: NOT IMPLEMENTED** - Low priority
574
574
-
575
575
-
Enable connecting to local services via Unix domain sockets (e.g., Docker daemon at /var/run/docker.sock) without TCP overhead.
576
576
-
577
577
-
**Cross-Language Consensus:** 2 libraries
578
578
-
**Source Libraries:** curl-rust, http-streams
579
579
-
580
580
-
**Affected Files:**
581
581
-
- `lib/http_client.ml`
582
582
-
- `lib/requests.ml`
583
583
-
- `lib/one.ml`
584
584
-
585
585
-
**Implementation Notes:**
586
586
-
Add unix:// URL scheme support. Use Eio_unix for socket connection. Handle Host header correctly (use socket path or override). Add to connection pool keyed by socket path.
587
587
-
588
588
-
589
589
-
---
590
590
-
591
591
-
## Security & Spec Compliance
592
592
-
593
593
-
### 28. ✅ Restrict URL protocols to HTTP/HTTPS only
594
594
-
595
595
-
**Status: IMPLEMENTED** in `lib/requests.ml` and `lib/one.ml`
596
596
-
597
597
-
Explicitly whitelist only http:// and https:// protocols to prevent protocol smuggling attacks via file://, ftp://, gopher://, etc. Reject invalid protocols early in URL parsing.
598
598
-
599
599
-
**Cross-Language Consensus:** 1 libraries
600
600
-
**Source Libraries:** buzz
601
601
-
602
602
-
**Implementation:**
603
603
-
- `allowed_redirect_schemes = ["http"; "https"]`
604
604
-
- `validate_redirect_url` checks scheme on redirects
605
605
-
- `Error.Invalid_redirect` raised for disallowed schemes
606
606
-
- Applied during redirect following to prevent SSRF
607
607
-
608
608
-
609
609
-
---
610
610
-
611
611
-
## Feature Enhancements
612
612
-
613
613
-
### 29. ✅ Add path parameter templating
614
614
-
615
615
-
**Status: IMPLEMENTED** in `lib/requests.ml`
616
616
-
617
617
-
Support URL templates like /users/{id}/posts/{post_id} with placeholder substitution from a parameter map. Automatically URL-encode substituted values.
618
618
-
619
619
-
**RFC References:**
620
620
-
- RFC 6570 (URI Template)
621
621
-
622
622
-
**Cross-Language Consensus:** 3 libraries
623
623
-
**Source Libraries:** sling, resty, req (Go)
624
624
-
625
625
-
**Implementation:**
626
626
-
- `substitute_path_params` function for RFC 6570 templating
627
627
-
- `path_params:(string * string) list` parameter on all request methods
628
628
-
- Automatic URL encoding via `Uri.pct_encode`
629
629
-
- Applied before base URL resolution in request pipeline
630
630
-
- Example: `get ~path_params:[("id", "123")] "/users/{id}"`
631
631
-
632
632
-
633
633
-
---
634
634
-
635
635
-
## Architectural Improvements
636
636
-
637
637
-
### 30. ✅ Add default User-Agent header
638
638
-
639
639
-
**Status: IMPLEMENTED** in `lib/version.ml`
640
640
-
641
641
-
Set a default User-Agent identifying the library (ocaml-requests/VERSION) unless user provides one. Helps server-side debugging and follows HTTP best practices.
642
642
-
643
643
-
**RFC References:**
644
644
-
- RFC 9110 Section 10.1.5 (User-Agent)
645
645
-
646
646
-
**Cross-Language Consensus:** 5 libraries
647
647
-
**Source Libraries:** needle, resty, requests (Go), okhttp, guzzle
648
648
-
649
649
-
**Implementation:**
650
650
-
- New `Version` module with library version info
651
651
-
- `Version.user_agent` returns `"ocaml-requests/0.1.0 (OCaml X.XX.X)"`
652
652
-
- Applied automatically if not already set in `make_request_internal`
653
653
-
- Can be overridden via explicit User-Agent header
654
654
-