use crate::canonical::canonical_matches_page;
use crate::models::{HttpLinkHeader, VideoObjectEntity};
pub fn evaluate_gate_block(
page_url: &str,
status_code: i32,
has_noindex: bool,
body_canonical: Option<&str>,
page_title: Option<&str>,
redirect_location: Option<&str>,
http_links: &[HttpLinkHeader],
video_objects: &[VideoObjectEntity],
) -> Option<String> {
if (300..=399).contains(&status_code) {
let Some(loc) = redirect_location else {
return Some(format!(
"HTTP {status_code} 重定向缺少 Location 响应标头 (FATAL_MALFORMED_REDIRECT)"
));
};
if canonical_matches_page(page_url, loc) {
return Some(format!(
"HTTP {status_code} 重定向目标指向自身,存在死循环风险: {loc}"
));
}
return Some(format!("HTTP {status_code} 重定向至: {loc}"));
}
if status_code != 200 {
return Some(format!("HTTP {status_code}"));
}
if has_noindex {
return Some("noindex directive present".to_string());
}
let header_canonical = http_links
.iter()
.find(|l| l.rel == "canonical")
.map(|l| l.uri.as_str());
if let (Some(h_canon), Some(b_canon)) = (header_canonical, body_canonical) {
if !canonical_matches_page(h_canon, b_canon) {
return Some(format!(
"跨层 Canonical 冲突:HTTP Header 声明 ({h_canon}) 与 HTML Body 声明 ({b_canon}) 不一致 (CRITICAL_SEO_HEADER_LOOP)"
));
}
}
let effective_canonical = header_canonical.or(body_canonical);
if let Some(canon) = effective_canonical {
if !canonical_matches_page(page_url, canon) {
return Some(format!("Canonical URL mismatch: {canon}"));
}
}
for (idx, video) in video_objects.iter().enumerate() {
if let Some(ref embed) = video.embed_url {
if canonical_matches_page(page_url, embed) {
return Some(format!(
"VideoObject #{idx} 语义自环:embedUrl ({embed}) 直接指向当前网页 HTML,将导致 Google 视频抓取器解码崩溃"
));
}
}
if let Some(ref content) = video.content_url {
if canonical_matches_page(page_url, content) {
return Some(format!(
"VideoObject #{idx} 语义自环:contentUrl ({content}) 直接指向当前网页 HTML,将被视为损坏的媒体流"
));
}
}
}
if page_title.map(str::trim).map(str::is_empty).unwrap_or(true) {
return Some("Missing <title> tag".to_string());
}
None
}