servo-fetch-cli 0.12.2

A browser engine in a binary — fetch, render, and extract web content as Markdown, JSON, or screenshots. Powered by Servo.
//! servo-fetch CLI.

#![deny(unsafe_code)]

mod cli;
mod commands;
mod exit;
mod logging;
mod mcp;
mod output;
mod progress;
mod serve;
mod tools;

use clap::Parser;

use crate::cli::{Cli, Command};

fn main() -> ! {
    install_process_defaults();

    let args = Cli::parse();
    logging::init(logging::Verbosity::from_flags(args.verbose, args.quiet));

    let code = exit::exit_code(dispatch(&args));
    exit::flush_and_exit(code);
}

fn dispatch(args: &Cli) -> anyhow::Result<()> {
    if args.command.as_ref().is_none_or(Command::needs_servo_init) {
        let policy = if args.allow_private_addresses || std::env::var_os("SERVO_FETCH_ALLOW_PRIVATE").is_some() {
            tracing::warn!("SSRF protection disabled: private/loopback addresses are reachable");
            servo_fetch::NetworkPolicy::PERMISSIVE
        } else {
            servo_fetch::NetworkPolicy::STRICT
        };
        servo_fetch::init(policy);
    }
    match &args.command {
        Some(Command::Mcp(mcp)) => commands::mcp::run(mcp),
        Some(Command::Serve(serve)) => commands::serve::run(serve),
        Some(Command::Crawl(crawl)) => commands::crawl::run(crawl),
        Some(Command::Map(map)) => commands::map::run(map),
        Some(Command::Healthcheck(hc)) => commands::healthcheck::run(hc),
        None => commands::fetch::run(&args.fetch),
    }
}

fn install_process_defaults() {
    #[cfg(unix)]
    #[allow(unsafe_code)]
    unsafe {
        libc::signal(libc::SIGPIPE, libc::SIG_DFL);
    }
    rustls::crypto::aws_lc_rs::default_provider()
        .install_default()
        .expect("failed to install rustls crypto provider");
}