forked from mirrors/kingfisher
changes in response to PR review
This commit is contained in:
parent
51b3b65706
commit
eee7697e24
7 changed files with 246 additions and 19 deletions
|
|
@ -233,6 +233,33 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn html_embedded_context_extracts_uppercase_script_and_style_candidates() {
|
||||
let source = br#"
|
||||
<HTML>
|
||||
<BODY>
|
||||
<SCRIPT>const auth0_client_secret = "secret-value";</SCRIPT>
|
||||
<STYLE>.banner::before { content: "hello"; }</STYLE>
|
||||
</BODY>
|
||||
</HTML>
|
||||
"#;
|
||||
let mut texts = Vec::new();
|
||||
stream_context_candidates(source, &Language::Html, |text| {
|
||||
texts.push(text.to_string());
|
||||
true
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
texts.iter().any(|text| text.contains("<script> = const auth0_client_secret")),
|
||||
"expected uppercase script tag to be handled like lowercase script"
|
||||
);
|
||||
assert!(
|
||||
texts.iter().any(|text| text.contains("content =")),
|
||||
"expected uppercase style tag to emit CSS declaration candidates"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_only_python_context_is_ignored() {
|
||||
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::cell::Cell;
|
||||
|
||||
use anyhow::Result;
|
||||
use cssparser::{
|
||||
parse_important, AtRuleParser, CowRcStr, DeclarationParser, ParseError, Parser, ParserInput,
|
||||
|
|
@ -15,14 +17,20 @@ where
|
|||
|
||||
let mut input = ParserInput::new(&css);
|
||||
let mut parser = Parser::new(&mut input);
|
||||
let mut collector = Collector { sink, stopped: false };
|
||||
for _ in StyleSheetParser::new(&mut parser, &mut collector) {}
|
||||
let stopped = Cell::new(false);
|
||||
let mut collector = Collector { sink, stopped: &stopped };
|
||||
let mut stylesheet = StyleSheetParser::new(&mut parser, &mut collector);
|
||||
while !stopped.get() {
|
||||
if stylesheet.next().is_none() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Collector<'a, F> {
|
||||
sink: &'a mut F,
|
||||
stopped: bool,
|
||||
stopped: &'a Cell<bool>,
|
||||
}
|
||||
|
||||
impl<'a, F> Collector<'a, F>
|
||||
|
|
@ -30,11 +38,11 @@ where
|
|||
F: FnMut(&str) -> bool,
|
||||
{
|
||||
fn emit(&mut self, name: &str, value: &str) {
|
||||
if self.stopped {
|
||||
if self.stopped.get() {
|
||||
return;
|
||||
}
|
||||
let candidate = format!("{name} = {value}");
|
||||
self.stopped = !(self.sink)(&candidate);
|
||||
self.stopped.set(!(self.sink)(&candidate));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +90,7 @@ where
|
|||
|
||||
for value in values {
|
||||
self.emit(&name, &value);
|
||||
if self.stopped {
|
||||
if self.stopped.get() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -118,7 +126,13 @@ where
|
|||
_start: &ParserState,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<(), ParseError<'i, ()>> {
|
||||
for _ in RuleBodyParser::new(input, self) {}
|
||||
let stopped = self.stopped;
|
||||
let mut rule_body = RuleBodyParser::new(input, self);
|
||||
while !stopped.get() {
|
||||
if rule_body.next().is_none() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ where
|
|||
continue;
|
||||
};
|
||||
let tag_name = tag.name().as_utf8_str().to_string();
|
||||
let normalized_tag_name = tag_name.to_ascii_lowercase();
|
||||
|
||||
for (key, value) in tag.attributes().iter() {
|
||||
let Some(value) = value else {
|
||||
|
|
@ -35,7 +36,7 @@ where
|
|||
}
|
||||
|
||||
let inner_text = tag.inner_text(parser).trim().to_string();
|
||||
match tag_name.as_str() {
|
||||
match normalized_tag_name.as_str() {
|
||||
"script" => {
|
||||
let candidate = format!("<script> = {inner_text}");
|
||||
if !inner_text.is_empty() && !sink(&candidate) {
|
||||
|
|
|
|||
|
|
@ -766,9 +766,9 @@ async fn validate_single(
|
|||
om.validation_success = cached.is_valid;
|
||||
om.validation_response_body = cached.body.clone();
|
||||
om.validation_response_status = cached.status;
|
||||
if om.validation_success {
|
||||
if om.validation_success && is_counted_validation_status(om.validation_response_status) {
|
||||
success_count.fetch_add(1, Ordering::Relaxed);
|
||||
} else if om.validation_response_status != http::StatusCode::CONTINUE {
|
||||
} else if is_counted_validation_status(om.validation_response_status) {
|
||||
fail_count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
maybe_record_access_map(om, access_map);
|
||||
|
|
@ -787,9 +787,10 @@ async fn validate_single(
|
|||
om.validation_success = cached.is_valid;
|
||||
om.validation_response_body = cached.body.clone();
|
||||
om.validation_response_status = cached.status;
|
||||
if om.validation_success {
|
||||
if om.validation_success && is_counted_validation_status(om.validation_response_status)
|
||||
{
|
||||
success_count.fetch_add(1, Ordering::Relaxed);
|
||||
} else if om.validation_response_status != http::StatusCode::CONTINUE {
|
||||
} else if is_counted_validation_status(om.validation_response_status) {
|
||||
fail_count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
maybe_record_access_map(om, access_map);
|
||||
|
|
@ -818,9 +819,10 @@ async fn validate_single(
|
|||
// Store result in cache
|
||||
match outcome {
|
||||
Ok(_) => {
|
||||
if om.validation_success {
|
||||
if om.validation_success && is_counted_validation_status(om.validation_response_status)
|
||||
{
|
||||
success_count.fetch_add(1, Ordering::Relaxed);
|
||||
} else if om.validation_response_status != http::StatusCode::CONTINUE {
|
||||
} else if is_counted_validation_status(om.validation_response_status) {
|
||||
fail_count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
cache.insert(
|
||||
|
|
@ -849,6 +851,10 @@ async fn validate_single(
|
|||
}
|
||||
}
|
||||
|
||||
fn is_counted_validation_status(status: StatusCode) -> bool {
|
||||
!matches!(status, StatusCode::CONTINUE | StatusCode::PRECONDITION_REQUIRED)
|
||||
}
|
||||
|
||||
// Helper to compute the cache key for an OwnedBlobMatch
|
||||
fn build_cache_key(
|
||||
om: &OwnedBlobMatch,
|
||||
|
|
@ -1358,3 +1364,16 @@ fn extract_azure_devops_org_from_body(
|
|||
let text = validation_body::clone_as_string(body);
|
||||
ORG_RE.captures(&text).and_then(|caps| caps.get(1).map(|m| m.as_str().to_string()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn counted_validation_status_excludes_skipped_statuses() {
|
||||
assert!(!is_counted_validation_status(StatusCode::CONTINUE));
|
||||
assert!(!is_counted_validation_status(StatusCode::PRECONDITION_REQUIRED));
|
||||
assert!(is_counted_validation_status(StatusCode::OK));
|
||||
assert!(is_counted_validation_status(StatusCode::UNAUTHORIZED));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue