1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! The two pieces of HTTP drep performs for itself.
//!
//! Reviews go through open-agent-sdk, which owns its own transport. What is
//! left is `drep init` asking two questions over plain GET: which models an
//! endpoint serves ([`crate::llm::models`]) and what those models accept
//! ([`crate::llm::quirks`]). Both are one request against a host the user
//! named, both must be bounded, and both must be non-fatal.
//!
//! They live here rather than in either module because the bound is a safety
//! property, and a safety property written twice is written once and forgotten
//! once. That is exactly what happened: the quirks fetcher was given a size
//! ceiling and a chunked read, while the older listing fetcher next to it kept
//! calling `text()` with no ceiling at all - against an endpoint typed at a
//! prompt, while holding a key.
//!
//! What is deliberately *not* shared is classification. The two callers
//! disagree about what a status means - a 404 is an ordinary answer for a
//! listing and a fault for the registry - so each keeps its own error enum and
//! maps [`ReadError`] into it.
use Duration;
use Error;
/// Why a body could not be read.
///
/// Split the way both callers already split their own errors: something went
/// wrong with the transfer, or the bytes are not text.
/// A client with `timeout` covering the whole request.
///
/// The one place a proxy, a user agent or a redirect policy would ever go.
/// There used to be two of these, differing by accident rather than by choice.
///
/// The error is a `String` so each caller can map it into its own enum without
/// this module knowing about either.
/// Read a response body, refusing one larger than `max_bytes`.
///
/// A declared `Content-Length` past the ceiling is refused before a byte is
/// read, but that is a shortcut rather than the guarantee: reqwest strips the
/// header from a response it decompresses, and chunked transfer encoding never
/// sends one. The per-chunk cap is what actually holds, and it counts *decoded*
/// bytes - which is both what gets allocated and what makes a body that
/// inflates without limit refusable.
///
/// The timeout on the client is not a size bound. A fast host can send a great
/// deal inside one, and the body is buffered whole.
pub async