20260817 同步层HTTP User-Agent改为env可配置RPKI_HTTP_USER_AGENT,默认panda-rpki/0.2
This commit is contained in:
parent
e98eb6d68f
commit
49172b57d3
@ -47,6 +47,9 @@ LIVE_TA_REFRESH_MAX_TIME_SECS=120
|
||||
|
||||
# Sync and runtime behavior.
|
||||
RSYNC_SCOPE=module-root
|
||||
# HTTP User-Agent for all outgoing HTTP requests (RRDP / TAL / TA / dead-repo probes).
|
||||
# Unset, empty, or header-illegal values fall back to panda-rpki/0.2.
|
||||
#RPKI_HTTP_USER_AGENT=panda-rpki/0.2
|
||||
DISABLE_COMPETING_RPS=0
|
||||
RUN_ROOT=/var/lib/ours-rp
|
||||
DB_DIR=/var/lib/ours-rp/state/db
|
||||
|
||||
@ -102,6 +102,10 @@ ENABLE_CHILD_CERTIFICATE_VALIDATION_CACHE=0
|
||||
# 实验性 transport 预热:RPKI_EXTRA_ARGS="--enable-transport-request-prefetch --enable-roa-validation-cache"
|
||||
RPKI_EXTRA_ARGS=""
|
||||
|
||||
# 所有出站 HTTP 请求(RRDP / TAL / TA / 死 repo 探针)的 User-Agent。
|
||||
# 不设置、为空或含非法 header 字符时回退默认 panda-rpki/0.2。
|
||||
#RPKI_HTTP_USER_AGENT=panda-rpki/0.2
|
||||
|
||||
# 是否为每轮输出 timing profile 到 runs/run_xxxx/analyze/timing.json。
|
||||
# 性能 profile 或打点验证时设置为 1;普通 soak 建议保持 0,避免额外开销。
|
||||
RPKI_ANALYZE=0
|
||||
|
||||
@ -20,6 +20,28 @@ pub fn with_scoped_http_timeout_override<R>(timeout: Duration, f: impl FnOnce()
|
||||
})
|
||||
}
|
||||
|
||||
/// Default User-Agent sent with every outgoing HTTP request (RRDP
|
||||
/// notification/snapshot/delta, TAL/TA downloads, daemon probes).
|
||||
pub const DEFAULT_HTTP_USER_AGENT: &str = "panda-rpki/0.2";
|
||||
|
||||
/// Environment variable that overrides the HTTP User-Agent. Unset, empty, or
|
||||
/// values containing characters that are illegal in a header value fall back
|
||||
/// to [`DEFAULT_HTTP_USER_AGENT`].
|
||||
pub const HTTP_USER_AGENT_ENV: &str = "RPKI_HTTP_USER_AGENT";
|
||||
|
||||
fn resolve_http_user_agent(env_value: Option<String>) -> String {
|
||||
let Some(value) = env_value else {
|
||||
return DEFAULT_HTTP_USER_AGENT.to_string();
|
||||
};
|
||||
let trimmed = value.trim();
|
||||
let valid = !trimmed.is_empty() && trimmed.bytes().all(|b| (0x20..=0x7e).contains(&b));
|
||||
if valid {
|
||||
trimmed.to_string()
|
||||
} else {
|
||||
DEFAULT_HTTP_USER_AGENT.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HttpFetcherConfig {
|
||||
/// Connection-establishment timeout for HTTP requests.
|
||||
@ -39,7 +61,7 @@ impl Default for HttpFetcherConfig {
|
||||
connect_timeout: Duration::from_secs(15),
|
||||
timeout: Duration::from_secs(30),
|
||||
large_body_timeout: Duration::from_secs(180),
|
||||
user_agent: "rpki-dev/0.1 (stage2)".to_string(),
|
||||
user_agent: resolve_http_user_agent(std::env::var(HTTP_USER_AGENT_ENV).ok()),
|
||||
extra_root_certificates_pem: Vec::new(),
|
||||
}
|
||||
}
|
||||
@ -84,7 +106,7 @@ impl BlockingHttpFetcher {
|
||||
&config,
|
||||
Duration::from_secs(1),
|
||||
Duration::from_secs(1),
|
||||
"rpki-dev/0.1 (stage2)".to_string(),
|
||||
config.user_agent.clone(),
|
||||
)?
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?;
|
||||
@ -532,4 +554,99 @@ mod tests {
|
||||
assert_eq!(profile_large, "large_body");
|
||||
assert_eq!(timeout_large, Duration::from_secs(9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_http_user_agent_falls_back_to_default() {
|
||||
assert_eq!(resolve_http_user_agent(None), DEFAULT_HTTP_USER_AGENT);
|
||||
assert_eq!(
|
||||
resolve_http_user_agent(Some(String::new())),
|
||||
DEFAULT_HTTP_USER_AGENT
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_http_user_agent(Some(" ".to_string())),
|
||||
DEFAULT_HTTP_USER_AGENT
|
||||
);
|
||||
// Control characters are illegal in header values; fall back instead
|
||||
// of letting reqwest fail to build the client.
|
||||
assert_eq!(
|
||||
resolve_http_user_agent(Some("bad\u{1}ua".to_string())),
|
||||
DEFAULT_HTTP_USER_AGENT
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_http_user_agent(Some("non-ascii-ua-中".to_string())),
|
||||
DEFAULT_HTTP_USER_AGENT
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_http_user_agent_accepts_custom_value() {
|
||||
assert_eq!(
|
||||
resolve_http_user_agent(Some("panda-rpki/9.9 (test)".to_string())),
|
||||
"panda-rpki/9.9 (test)"
|
||||
);
|
||||
// Surrounding whitespace is trimmed.
|
||||
assert_eq!(
|
||||
resolve_http_user_agent(Some(" custom/1.0 ".to_string())),
|
||||
"custom/1.0"
|
||||
);
|
||||
}
|
||||
|
||||
fn spawn_user_agent_capture_server() -> (String, std::sync::mpsc::Receiver<String>) {
|
||||
let listener = TcpListener::bind(("127.0.0.1", 0)).expect("bind");
|
||||
let addr = listener.local_addr().expect("addr");
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
thread::spawn(move || {
|
||||
let (mut stream, _) = listener.accept().expect("accept");
|
||||
let mut buf = [0u8; 4096];
|
||||
let read = stream.read(&mut buf).expect("read request");
|
||||
let request = String::from_utf8_lossy(&buf[..read]).to_string();
|
||||
let body = b"ok";
|
||||
let hdr = format!(
|
||||
"HTTP/1.1 200 OK\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
|
||||
body.len()
|
||||
);
|
||||
stream.write_all(hdr.as_bytes()).expect("write hdr");
|
||||
stream.write_all(body).expect("write body");
|
||||
let _ = tx.send(request);
|
||||
});
|
||||
(format!("http://{}/", addr), rx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_bytes_sends_configured_user_agent_header() {
|
||||
let (url, rx) = spawn_user_agent_capture_server();
|
||||
let http = BlockingHttpFetcher::new(HttpFetcherConfig {
|
||||
timeout: Duration::from_secs(2),
|
||||
user_agent: "panda-rpki/0.2".to_string(),
|
||||
..HttpFetcherConfig::default()
|
||||
})
|
||||
.expect("http");
|
||||
http.fetch_bytes(&url).expect("fetch");
|
||||
let request = rx.recv().expect("request captured");
|
||||
assert!(
|
||||
request
|
||||
.to_ascii_lowercase()
|
||||
.contains("user-agent: panda-rpki/0.2"),
|
||||
"{request}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_bytes_sends_custom_user_agent_header() {
|
||||
let (url, rx) = spawn_user_agent_capture_server();
|
||||
let http = BlockingHttpFetcher::new(HttpFetcherConfig {
|
||||
timeout: Duration::from_secs(2),
|
||||
user_agent: "custom-marker/7.7".to_string(),
|
||||
..HttpFetcherConfig::default()
|
||||
})
|
||||
.expect("http");
|
||||
http.fetch_bytes(&url).expect("fetch");
|
||||
let request = rx.recv().expect("request captured");
|
||||
assert!(
|
||||
request
|
||||
.to_ascii_lowercase()
|
||||
.contains("user-agent: custom-marker/7.7"),
|
||||
"{request}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ fn live_http_fetcher() -> BlockingHttpFetcher {
|
||||
BlockingHttpFetcher::new(HttpFetcherConfig {
|
||||
timeout: Duration::from_secs(timeout_secs),
|
||||
large_body_timeout: Duration::from_secs(timeout_secs),
|
||||
user_agent: "rpki-dev/0.1 (stage2 live rrdp delta test)".to_string(),
|
||||
user_agent: "panda-rpki/0.2 (live rrdp delta test)".to_string(),
|
||||
..HttpFetcherConfig::default()
|
||||
})
|
||||
.expect("http fetcher")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user