clawhdf5-remote, h5rs: URLs' credentials are never shown
Every RemoteError message and HttpStorage's Debug output held the URL as given, with any user:password@ and the query string — for a presigned S3/GCS/Azure URL, its signature or token. An application logging the error leaked the credential. - New clawhdf5_remote::redact_url: no userinfo, no fragment, query values replaced by REDACTED (plain key names kept). - HttpStorage formats every message with the redacted URL, and scrubs the URL's secret parts from errors of the HTTP client (whose texts can echo the URI); Debug shows the redacted URL. storage_for_url's and the object store URL errors are redacted too. HttpStorage::url() still returns the URL as given, documented as not for logging. - h5rs prints FILE arguments that are URLs redacted: in errors and in dump/stat/check/diff output. - The test server can force a status and send a wrong Content-Range. Tests: 404, 403 (at open and on a read), wrong Content-Range (at open and on a read), no range support, encoded body, ETag change, timeout, connection closed and bad scheme errors, Display and Debug, contain none of the secrets; h5rs likewise for every subcommand. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -52,6 +52,11 @@ pub struct Shared {
|
||||
/// when checking ranges) and serve zeros past its real end: a hostile
|
||||
/// server lying about the length.
|
||||
pub fake_total: AtomicU64,
|
||||
/// When non-zero, answer every request for a served file with this
|
||||
/// status (and an empty body).
|
||||
pub force_status: AtomicU32,
|
||||
/// Answer ranges with a `Content-Range` one byte off.
|
||||
pub wrong_range: AtomicBool,
|
||||
/// Requests for a served path (every status); requests for other
|
||||
/// paths are not counted.
|
||||
pub requests: AtomicU64,
|
||||
@@ -256,6 +261,11 @@ fn serve(conn: TcpStream, s: &Shared) -> std::io::Result<()> {
|
||||
if delay > 0 {
|
||||
std::thread::sleep(Duration::from_millis(delay));
|
||||
}
|
||||
let forced = s.force_status.load(Ordering::SeqCst);
|
||||
if forced != 0 {
|
||||
write!(out, "HTTP/1.1 {forced} Forced\r\nContent-Length: 0\r\n\r\n")?;
|
||||
continue;
|
||||
}
|
||||
if s.fail_next
|
||||
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |n| n.checked_sub(1))
|
||||
.is_ok()
|
||||
@@ -309,7 +319,11 @@ fn serve(conn: TcpStream, s: &Shared) -> std::io::Result<()> {
|
||||
Some(Ok((a, b))) => (
|
||||
"206 Partial Content",
|
||||
slice_or_zeros(&data, a, b, &mut padded),
|
||||
format!("Content-Range: bytes {a}-{b}/{len}\r\n"),
|
||||
if s.wrong_range.load(Ordering::SeqCst) {
|
||||
format!("Content-Range: bytes {}-{}/{len}\r\n", a + 1, b + 1)
|
||||
} else {
|
||||
format!("Content-Range: bytes {a}-{b}/{len}\r\n")
|
||||
},
|
||||
),
|
||||
None => ("200 OK", &data[..], String::new()),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user