Skip to content

Commit 3bfbbbc

Browse files
Avoid allocation when validating HTTP and HTTPS prefixes (#12313)
1 parent 1a3ee45 commit 3bfbbbc

File tree

1 file changed

+19
-12
lines changed

1 file changed

+19
-12
lines changed

crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,19 @@ impl Violation for SuspiciousFTPLibUsage {
825825

826826
/// S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323
827827
pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
828+
/// Returns `true` if the iterator starts with the given prefix.
829+
fn has_prefix(mut chars: impl Iterator<Item = char>, prefix: &str) -> bool {
830+
for expected in prefix.chars() {
831+
let Some(actual) = chars.next() else {
832+
return false;
833+
};
834+
if actual != expected {
835+
return false;
836+
}
837+
}
838+
true
839+
}
840+
828841
let Some(diagnostic_kind) = checker.semantic().resolve_qualified_name(call.func.as_ref()).and_then(|qualified_name| {
829842
match qualified_name.segments() {
830843
// Pickle
@@ -857,16 +870,14 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
857870
match call.arguments.find_argument("url", 0) {
858871
// If the `url` argument is a string literal, allow `http` and `https` schemes.
859872
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => {
860-
let url = value.to_str().trim_start();
861-
if url.starts_with("http://") || url.starts_with("https://") {
873+
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
862874
return None;
863875
}
864876
},
865877
// If the `url` argument is an f-string literal, allow `http` and `https` schemes.
866878
Some(Expr::FString(ast::ExprFString { value, .. })) => {
867879
if let Some(ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. })) = value.elements().next() {
868-
let url = value.trim_start();
869-
if url.starts_with("http://") || url.starts_with("https://") {
880+
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
870881
return None;
871882
}
872883
}
@@ -883,17 +894,15 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
883894
match call.arguments.find_argument("url", 0) {
884895
// If the `url` argument is a string literal, allow `http` and `https` schemes.
885896
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => {
886-
let url = value.to_str().trim_start();
887-
if url.starts_with("http://") || url.starts_with("https://") {
897+
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
888898
return None;
889899
}
890900
},
891901

892902
// If the `url` argument is an f-string literal, allow `http` and `https` schemes.
893903
Some(Expr::FString(ast::ExprFString { value, .. })) => {
894904
if let Some(ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. })) = value.elements().next() {
895-
let url = value.trim_start();
896-
if url.starts_with("http://") || url.starts_with("https://") {
905+
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
897906
return None;
898907
}
899908
}
@@ -905,17 +914,15 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
905914
match arguments.find_argument("url", 0) {
906915
// If the `url` argument is a string literal, allow `http` and `https` schemes.
907916
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => {
908-
let url = value.to_str().trim_start();
909-
if url.starts_with("http://") || url.starts_with("https://") {
917+
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
910918
return None;
911919
}
912920
},
913921

914922
// If the `url` argument is an f-string literal, allow `http` and `https` schemes.
915923
Some(Expr::FString(ast::ExprFString { value, .. })) => {
916924
if let Some(ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. })) = value.elements().next() {
917-
let url = value.trim_start();
918-
if url.starts_with("http://") || url.starts_with("https://") {
925+
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
919926
return None;
920927
}
921928
}

0 commit comments

Comments
 (0)