Files
chrome-use/cli/src/flags.rs
T
Zhiwei Li 53187a603c feat: add support for ignoring HTTPS certificate errors (#93)
* feat: add support for ignoring HTTPS certificate errors

* fix: update warning message for already running daemon to include ignore HTTPS errors option

* docs: add documentation for --ignore-https-errors option in README and SKILL.md

* feat: initialize ignore_https_errors flag in command context

* fix: change launch_cmd to mutable for cdp value handling
2026-01-24 23:54:33 -06:00

286 lines
8.7 KiB
Rust

use std::env;
pub struct Flags {
pub json: bool,
pub full: bool,
pub headed: bool,
pub debug: bool,
pub session: String,
pub headers: Option<String>,
pub executable_path: Option<String>,
pub cdp: Option<String>,
pub extensions: Vec<String>,
pub profile: Option<String>,
pub proxy: Option<String>,
pub proxy_bypass: Option<String>,
pub args: Option<String>,
pub user_agent: Option<String>,
pub provider: Option<String>,
pub ignore_https_errors: bool,
}
pub fn parse_flags(args: &[String]) -> Flags {
let extensions_env = env::var("AGENT_BROWSER_EXTENSIONS")
.ok()
.map(|s| s.split(',').map(|p| p.trim().to_string()).filter(|p| !p.is_empty()).collect::<Vec<_>>())
.unwrap_or_default();
let mut flags = Flags {
json: false,
full: false,
headed: false,
debug: false,
session: env::var("AGENT_BROWSER_SESSION").unwrap_or_else(|_| "default".to_string()),
headers: None,
executable_path: env::var("AGENT_BROWSER_EXECUTABLE_PATH").ok(),
cdp: None,
extensions: extensions_env,
profile: env::var("AGENT_BROWSER_PROFILE").ok(),
proxy: env::var("AGENT_BROWSER_PROXY").ok(),
proxy_bypass: env::var("AGENT_BROWSER_PROXY_BYPASS").ok(),
args: env::var("AGENT_BROWSER_ARGS").ok(),
user_agent: env::var("AGENT_BROWSER_USER_AGENT").ok(),
provider: env::var("AGENT_BROWSER_PROVIDER").ok(),
ignore_https_errors: false,
};
let mut i = 0;
while i < args.len() {
match args[i].as_str() {
"--json" => flags.json = true,
"--full" | "-f" => flags.full = true,
"--headed" => flags.headed = true,
"--debug" => flags.debug = true,
"--session" => {
if let Some(s) = args.get(i + 1) {
flags.session = s.clone();
i += 1;
}
}
"--headers" => {
if let Some(h) = args.get(i + 1) {
flags.headers = Some(h.clone());
i += 1;
}
}
"--executable-path" => {
if let Some(s) = args.get(i + 1) {
flags.executable_path = Some(s.clone());
i += 1;
}
},
"--extension" => {
if let Some(s) = args.get(i + 1) {
flags.extensions.push(s.clone());
i += 1;
}
},
"--cdp" => {
if let Some(s) = args.get(i + 1) {
flags.cdp = Some(s.clone());
i += 1;
}
}
"--profile" => {
if let Some(s) = args.get(i + 1) {
flags.profile = Some(s.clone());
i += 1;
}
}
"--proxy" => {
if let Some(p) = args.get(i + 1) {
flags.proxy = Some(p.clone());
i += 1;
}
}
"--proxy-bypass" => {
if let Some(s) = args.get(i + 1) {
flags.proxy_bypass = Some(s.clone());
i += 1;
}
}
"--args" => {
if let Some(s) = args.get(i + 1) {
flags.args = Some(s.clone());
i += 1;
}
}
"--user-agent" => {
if let Some(s) = args.get(i + 1) {
flags.user_agent = Some(s.clone());
i += 1;
}
}
"-p" | "--provider" => {
if let Some(p) = args.get(i + 1) {
flags.provider = Some(p.clone());
i += 1;
}
}
"--ignore-https-errors" => flags.ignore_https_errors = true,
_ => {}
}
i += 1;
}
flags
}
pub fn clean_args(args: &[String]) -> Vec<String> {
let mut result = Vec::new();
let mut skip_next = false;
// Global flags that should be stripped from command args
const GLOBAL_FLAGS: &[&str] = &["--json", "--full", "--headed", "--debug", "--ignore-https-errors"];
// Global flags that take a value (need to skip the next arg too)
const GLOBAL_FLAGS_WITH_VALUE: &[&str] = &[
"--session",
"--headers",
"--executable-path",
"--cdp",
"--extension",
"--profile",
"--proxy",
"--proxy-bypass",
"--args",
"--user-agent",
"-p",
"--provider",
];
for arg in args.iter() {
if skip_next {
skip_next = false;
continue;
}
if GLOBAL_FLAGS_WITH_VALUE.contains(&arg.as_str()) {
skip_next = true;
continue;
}
// Only strip known global flags, not command-specific flags
if GLOBAL_FLAGS.contains(&arg.as_str()) || arg == "-f" {
continue;
}
result.push(arg.clone());
}
result
}
#[cfg(test)]
mod tests {
use super::*;
fn args(s: &str) -> Vec<String> {
s.split_whitespace().map(String::from).collect()
}
#[test]
fn test_parse_headers_flag() {
let flags = parse_flags(&args(r#"open example.com --headers {"Auth":"token"}"#));
assert_eq!(flags.headers, Some(r#"{"Auth":"token"}"#.to_string()));
}
#[test]
fn test_parse_headers_flag_with_spaces() {
// Headers JSON is passed as a single quoted argument in shell
let input: Vec<String> = vec![
"open".to_string(),
"example.com".to_string(),
"--headers".to_string(),
r#"{"Authorization": "Bearer token"}"#.to_string(),
];
let flags = parse_flags(&input);
assert_eq!(
flags.headers,
Some(r#"{"Authorization": "Bearer token"}"#.to_string())
);
}
#[test]
fn test_parse_no_headers_flag() {
let flags = parse_flags(&args("open example.com"));
assert!(flags.headers.is_none());
}
#[test]
fn test_clean_args_removes_headers() {
let input: Vec<String> = vec![
"open".to_string(),
"example.com".to_string(),
"--headers".to_string(),
r#"{"Auth":"token"}"#.to_string(),
];
let clean = clean_args(&input);
assert_eq!(clean, vec!["open", "example.com"]);
}
#[test]
fn test_clean_args_removes_headers_at_start() {
let input: Vec<String> = vec![
"--headers".to_string(),
r#"{"Auth":"token"}"#.to_string(),
"open".to_string(),
"example.com".to_string(),
];
let clean = clean_args(&input);
assert_eq!(clean, vec!["open", "example.com"]);
}
#[test]
fn test_headers_with_other_flags() {
let input: Vec<String> = vec![
"open".to_string(),
"example.com".to_string(),
"--headers".to_string(),
r#"{"Auth":"token"}"#.to_string(),
"--json".to_string(),
"--headed".to_string(),
];
let flags = parse_flags(&input);
assert_eq!(flags.headers, Some(r#"{"Auth":"token"}"#.to_string()));
assert!(flags.json);
assert!(flags.headed);
let clean = clean_args(&input);
assert_eq!(clean, vec!["open", "example.com"]);
}
#[test]
fn test_parse_executable_path_flag() {
let flags = parse_flags(&args(
"--executable-path /path/to/chromium open example.com",
));
assert_eq!(flags.executable_path, Some("/path/to/chromium".to_string()));
}
#[test]
fn test_parse_executable_path_flag_no_value() {
let flags = parse_flags(&args("--executable-path"));
assert_eq!(flags.executable_path, None);
}
#[test]
fn test_clean_args_removes_executable_path() {
let cleaned = clean_args(&args(
"--executable-path /path/to/chromium open example.com",
));
assert_eq!(cleaned, vec!["open", "example.com"]);
}
#[test]
fn test_clean_args_removes_executable_path_with_other_flags() {
let cleaned = clean_args(&args(
"--json --executable-path /path/to/chromium --headed open example.com",
));
assert_eq!(cleaned, vec!["open", "example.com"]);
}
#[test]
fn test_parse_flags_with_session_and_executable_path() {
let flags = parse_flags(&args(
"--session test --executable-path /custom/chrome open example.com",
));
assert_eq!(flags.session, "test");
assert_eq!(flags.executable_path, Some("/custom/chrome".to_string()));
}
}