Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,4 @@ jobs:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- name: Check examples
run: cargo check --examples --features fetcher
run: cargo check --examples --features fetcher,zip8,rustls
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Bump CDP to `r1566079`
- Use a struct `Arg` for arguments to combine flags automatically
- Browser process no longer inherits stdout
- Update `reqwest` to v0.13
- Update `thiserror` to v2
- Update `heck` to v0.5
- Add support for `zip` v8 and make it default

### Added

Expand Down
22 changes: 12 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "chromiumoxide"
version = "0.8.0"
version = "0.9.0"
rust-version = "1.85"
autotests = false
authors = ["Matthias Seitz <matthias.seitz@outlook.de>"]
Expand All @@ -14,15 +14,15 @@ keywords = ["chrome", "chromedriver", "puppeteer", "automation"]
categories = ["web-programming", "api-bindings", "development-tools::testing"]

[dependencies]
async-tungstenite = { version = "0.32.0", features = ["tokio-runtime"] }
async-tungstenite = { version = "0.32", features = ["tokio-runtime"] }
serde = { version = "1", features = ["derive"] }
futures = "0.3"
chromiumoxide_types = { path = "chromiumoxide_types", version = "0.8" }
chromiumoxide_cdp = { path = "chromiumoxide_cdp", version = "0.8" }
chromiumoxide_fetcher = { path = "chromiumoxide_fetcher", version = "0.8", default-features = false, optional = true }
chromiumoxide_types = { path = "chromiumoxide_types", version = "0.9" }
chromiumoxide_cdp = { path = "chromiumoxide_cdp", version = "0.9" }
chromiumoxide_fetcher = { path = "chromiumoxide_fetcher", version = "0.9", default-features = false, optional = true }
serde_json = "1"
which = "8"
thiserror = "1"
thiserror = "2"
url = "2"
base64 = "0.22"
fnv = "1"
Expand All @@ -39,10 +39,10 @@ tracing = "0.1"
pin-project-lite = "0.2"
dunce = "1"
bytes = { version = "1", features = ["serde"], optional = true }
reqwest = { version = "0.12", default-features = false }
reqwest = { version = "0.13", default-features = false }

[target.'cfg(windows)'.dependencies]
windows-registry = "0.5"
windows-registry = "0.6"

[dev-dependencies]
quote = "1"
Expand All @@ -55,14 +55,16 @@ tokio = { version = "1", features = ["rt-multi-thread", "time", "macros"] }
default = ["bytes"]
fetcher = ["chromiumoxide_fetcher"]
bytes = ["dep:bytes"]
serde0 = []

rustls = ["chromiumoxide_fetcher/rustls"]
native-tls = ["chromiumoxide_fetcher/native-tls"]

zip0 = ["chromiumoxide_fetcher/zip0"]
zip8 = ["chromiumoxide_fetcher/zip8"]

[[example]]
name = "fetcher"
required-features = ["fetcher"]
required-features = ["fetcher", "zip8", "rustls"]

[[test]]
name = "chromiumoxide_tests"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ All Events are bundled in single enum (`CdpEvent`)
By default `chromiumoxide` will try to find an installed version of chromium on the computer it runs on.
It is possible to download and install one automatically for some platforms using the `fetcher` feature.

You need to enable either the `rustls` or the `native-tls` feature to allow the fetcher to download binaries.
You need to enable either the `rustls` or the `native-tls` feature and the `zip0` or `zip8` feature to allow the fetcher to download binaries.

```rust
use std::path::Path;
Expand Down
15 changes: 7 additions & 8 deletions chromiumoxide_cdp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "chromiumoxide_cdp"
version = "0.8.0"
version = "0.9.0"
authors = ["Matthias Seitz <matthias.seitz@outlook.de>"]
edition = "2024"
rust-version = "1.85"
Expand All @@ -11,16 +11,15 @@ repository = "https://github.com/mattsse/chromiumoxide"
readme = "../README.md"
include = ["src/**/*", "*.pdl", "LICENSE-*"]

[features]
serde0 = []

[dev-dependencies]
chromiumoxide_pdl = { path = "../chromiumoxide_pdl", version = "0.8" }
ureq = "2.10.0"
tempfile = "3.10.1"
chromiumoxide_pdl = { path = "../chromiumoxide_pdl", version = "0.9" }
reqwest = { version = "0.13", features = ["rustls"], default-features = false }
tempfile = "3.10"
tokio = { version = "1", features = ["rt", "fs", "process", "macros"] }

[dependencies]
chromiumoxide_pdl = { path = "../chromiumoxide_pdl", version = "0.8" }
chromiumoxide_types = { path = "../chromiumoxide_types", version = "0.8" }
chromiumoxide_pdl = { path = "../chromiumoxide_pdl", version = "0.9" }
chromiumoxide_types = { path = "../chromiumoxide_types", version = "0.9" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
30 changes: 17 additions & 13 deletions chromiumoxide_cdp/tests/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ fn generated_code_is_fresh() {
}

/// Check that the PDL files are up to date
#[test]
fn pdl_is_fresh() {
#[tokio::test]
async fn pdl_is_fresh() {
const BASE_URL: &str = "https://raw.githubusercontent.com/ChromeDevTools/devtools-protocol";

let dir = Path::new(env!("CARGO_MANIFEST_DIR"));
Expand All @@ -48,12 +48,13 @@ fn pdl_is_fresh() {
.unwrap_or_else(|_| dir.join("pdl/js_protocol.pdl"));

let js_proto_old = fs::read_to_string(&js_proto).unwrap_or_default();
let js_proto_new = ureq::get(&format!(
let js_proto_new = reqwest::get(&format!(
"{BASE_URL}/{CURRENT_REVISION}/pdl/js_protocol.pdl",
))
.call()
.await
.unwrap()
.into_string()
.text()
.await
.unwrap();
assert!(js_proto_new.contains("The Chromium Authors"));

Expand All @@ -68,12 +69,13 @@ fn pdl_is_fresh() {
.unwrap_or_else(|_| dir.join("pdl/browser_protocol.pdl"));

let browser_proto_old = fs::read_to_string(&browser_proto).unwrap_or_default();
let browser_proto_new = ureq::get(&format!(
let browser_proto_new = reqwest::get(&format!(
"{BASE_URL}/{CURRENT_REVISION}/pdl/browser_protocol.pdl"
))
.call()
.await
.unwrap()
.into_string()
.text()
.await
.unwrap();
assert!(browser_proto_new.contains("The Chromium Authors"));

Expand All @@ -95,11 +97,13 @@ fn pdl_is_fresh() {
let include_path = dir.join("pdl").join(include);

let include_proto_old = fs::read_to_string(&include_path).unwrap_or_default();
let include_proto_new = ureq::get(&format!("{BASE_URL}/{CURRENT_REVISION}/pdl/{include}"))
.call()
.unwrap()
.into_string()
.unwrap();
let include_proto_new =
reqwest::get(&format!("{BASE_URL}/{CURRENT_REVISION}/pdl/{include}"))
.await
.unwrap()
.text()
.await
.unwrap();
assert!(include_proto_new.contains("The Chromium Authors"));

if include_proto_new != include_proto_old {
Expand Down
21 changes: 12 additions & 9 deletions chromiumoxide_fetcher/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "chromiumoxide_fetcher"
version = "0.8.0"
version = "0.9.0"
authors = ["Matthias Seitz <matthias.seitz@outlook.de>"]
edition = "2024"
rust-version = "1.85"
Expand All @@ -22,26 +22,29 @@ path = "tests/lib.rs"
harness = true

[dev-dependencies]
reqwest = { version = "0.12", features = [
"rustls-tls",
], default-features = false }
reqwest = { version = "0.13", features = ["rustls"], default-features = false }
tokio = { version = "1", features = ["rt", "fs", "process", "macros"] }

[dependencies]
thiserror = "1"
thiserror = "2"
anyhow = "1"
directories = "6"
serde = { version = "1", features = ["derive"] }
tracing = "0.1"
zip = { version = "0.6", default-features = false, features = ["deflate"] }
zip0 = { package = "zip", version = "0.6", default-features = false, features = [
"deflate",
], optional = true }
zip8 = { package = "zip", version = "8", default-features = false, features = [
"deflate-flate2-zlib-rs",
], optional = true }
tokio = { version = "1", features = ["fs", "io-util"] }
reqwest = { version = "0.12", default-features = false, features = ["json"] }
reqwest = { version = "0.13", default-features = false, features = ["json"] }

[target.'cfg(target_os = "windows")'.dependencies]
windows-version = "0.1"

[features]
default = ["rustls"]
default = ["rustls", "zip8"]

rustls = ["reqwest/rustls-tls"]
rustls = ["reqwest/rustls"]
native-tls = ["reqwest/native-tls"]
9 changes: 9 additions & 0 deletions chromiumoxide_fetcher/src/runtime/zip/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#[cfg(feature = "zip0")]
mod zip0;
#[cfg(feature = "zip0")]
pub use zip0::ZipArchive;

#[cfg(feature = "zip8")]
mod zip8;
#[cfg(feature = "zip8")]
pub use zip8::ZipArchive;
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn create_symlink(link_target: Vec<u8>, link_path: &Path) -> ZipResult<()> {
fn create_symlink(link_target: Vec<u8>, link_path: &Path) -> ZipResult<()> {
// Only supports UTF-8 paths which is enough for our usecase
let link_target = String::from_utf8(link_target)
.map_err(|_| ZipError::InvalidArchive("Invalid synmlink target name"))?;
.map_err(|_| ZipError::InvalidArchive("Invalid symlink target name"))?;
std::os::windows::fs::symlink_file(link_target, link_path)?;

Ok(())
Expand Down
111 changes: 111 additions & 0 deletions chromiumoxide_fetcher/src/runtime/zip/zip8.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use std::fs;
use std::io::{self, Read, Seek};
use std::ops::{Deref, DerefMut};
use std::path::Path;

use zip8::{
read::ZipFile,
result::{ZipError, ZipResult},
};

#[derive(Clone, Debug)]
pub struct ZipArchive<R: Read + Seek>(zip8::ZipArchive<R>);

impl<R: Read + Seek> Deref for ZipArchive<R> {
type Target = zip8::ZipArchive<R>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<R: Read + Seek> DerefMut for ZipArchive<R> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl<R: Read + Seek> ZipArchive<R> {
pub fn new(reader: R) -> ZipResult<Self> {
zip8::ZipArchive::new(reader).map(Self)
}

/// We need this custom extract function to support symlinks.
/// This is based on https://github.com/zip-rs/zip/pull/213.
///
/// We must be careful with this implementation since it is not
/// protected against malicious symlinks, but we trust the binaries
/// provided by chromium.
pub fn extract<P: AsRef<Path>>(&mut self, directory: P) -> ZipResult<()> {
for i in 0..self.len() {
let mut file = self.by_index(i)?;

let filepath = file
.enclosed_name()
.ok_or(ZipError::InvalidArchive("Invalid file path".into()))?;
let outpath = directory.as_ref().join(filepath);

if file.is_dir() {
fs::create_dir_all(&outpath)?;
} else {
if let Some(p) = outpath.parent() {
if !p.exists() {
fs::create_dir_all(p)?;
}
}

match read_symlink(&mut file)? {
Some(target) => {
create_symlink(target, &outpath)?;
}
None => {
let mut outfile = fs::File::create(&outpath)?;
io::copy(&mut file, &mut outfile)?;

// Get and Set permissions
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
if let Some(mode) = file.unix_mode() {
fs::set_permissions(&outpath, fs::Permissions::from_mode(mode))?;
}
}
}
}
}
}
Ok(())
}
}

fn read_symlink<R: Read + Seek>(entry: &mut ZipFile<'_, R>) -> ZipResult<Option<Vec<u8>>> {
if let Some(mode) = entry.unix_mode() {
const S_IFLNK: u32 = 0o120000; // symbolic link
if mode & S_IFLNK == S_IFLNK {
let mut contents = Vec::new();
entry.read_to_end(&mut contents)?;
return Ok(Some(contents));
}
}
Ok(None)
}

#[cfg(target_family = "unix")]
fn create_symlink(link_target: Vec<u8>, link_path: &Path) -> ZipResult<()> {
use std::os::unix::ffi::OsStringExt as _;

let link_target = std::ffi::OsString::from_vec(link_target);
std::os::unix::fs::symlink(link_target, link_path)?;

Ok(())
}

#[cfg(target_family = "windows")]
fn create_symlink(link_target: Vec<u8>, link_path: &Path) -> ZipResult<()> {
// Only supports UTF-8 paths which is enough for our usecase
let link_target = String::from_utf8(link_target)
.map_err(|_| ZipError::InvalidArchive("Invalid symlink target name".into()))?;
std::os::windows::fs::symlink_file(link_target, link_path)?;

Ok(())
}
20 changes: 10 additions & 10 deletions chromiumoxide_pdl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "chromiumoxide_pdl"
version = "0.8.0"
version = "0.9.0"
authors = ["Matthias Seitz <matthias.seitz@outlook.de>"]
edition = "2024"
rust-version = "1.85"
Expand All @@ -12,15 +12,15 @@ readme = "../README.md"
include = ["src/**/*", "LICENSE-*"]

[dependencies]
once_cell = "1.8.0"
regex = "1.5.4"
quote = "1.0.10"
proc-macro2 = "1.0.32"
heck = "0.4"
once_cell = "1.8"
regex = "1.5"
quote = "1"
proc-macro2 = "1"
heck = "0.5"
serde_json = "1"
serde = { version = "1", features = ["derive"] }
chromiumoxide_types = { path = "../chromiumoxide_types", version = "0.8" }
either = "1.6.1"
serde = { version = "1", features = ["derive"], optional = true }
chromiumoxide_types = { path = "../chromiumoxide_types", version = "0.9" }
either = "1.6"

[features]
serde0 = []
serde = ["dep:serde"]
Loading