Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update hyper to version 1, see ci result #1

Closed
wants to merge 2 commits into from
Closed
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
5 changes: 5 additions & 0 deletions .changes/tauri-driver-hyper-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
tauri-driver: 'patch:enhance'
---

Updated `hyper` to version 1. This won't affect the user facing API.
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions crates/tauri-driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ rust-version = "1.77.2"

[dependencies]
anyhow = "1"
hyper = { version = "0.14", features = [
futures = "0.3"
futures-util = "0.3"
http-body-util = "0.1"
hyper = { version = "1", features = ["client", "http1", "server"] }
hyper-util = { version = "0.1", features = [
"client",
"client-legacy",
"http1",
"runtime",
"server",
"stream",
"tcp",
"tokio",
] }
futures = "0.3"
futures-util = "0.3"
pico-args = "0.5"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Expand Down
115 changes: 73 additions & 42 deletions crates/tauri-driver/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,24 @@
use crate::cli::Args;
use anyhow::Error;
use futures_util::TryFutureExt;
use hyper::header::CONTENT_LENGTH;
use hyper::http::uri::Authority;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Client, Method, Request, Response, Server};
use http_body_util::{BodyExt, Full};
use hyper::{
body::{Bytes, Incoming},
header::CONTENT_LENGTH,
http::uri::Authority,
service::service_fn,
Method, Request, Response,
};
use hyper_util::{
client::legacy::{connect::HttpConnector, Client},
rt::{TokioExecutor, TokioIo},
server::conn::auto,
};
use serde::Deserialize;
use serde_json::{json, Map, Value};
use std::convert::Infallible;
use std::path::PathBuf;
use std::process::Child;

type HttpClient = Client<hyper::client::HttpConnector>;
use tokio::net::TcpListener;

const TAURI_OPTIONS: &str = "tauri:options";

Expand Down Expand Up @@ -55,36 +62,46 @@ impl TauriOptions {
}

async fn handle(
client: HttpClient,
mut req: Request<Body>,
client: Client<HttpConnector, Full<Bytes>>,
req: Request<Incoming>,
args: Args,
) -> Result<Response<Body>, Error> {
) -> Result<Response<Incoming>, Error> {
// manipulate a new session to convert options to the native driver format
if let (&Method::POST, "/session") = (req.method(), req.uri().path()) {
let (mut parts, body) = req.into_parts();
let new_req: Request<Full<Bytes>> =
if let (&Method::POST, "/session") = (req.method(), req.uri().path()) {
let (mut parts, body) = req.into_parts();

// get the body from the future stream and parse it as json
let body = hyper::body::to_bytes(body).await?;
let json: Value = serde_json::from_slice(&body)?;
// get the body from the future stream and parse it as json
let body = body.collect().await?.to_bytes().to_vec();
let json: Value = serde_json::from_slice(&body)?;

// manipulate the json to convert from tauri option to native driver options
let json = map_capabilities(json);
// manipulate the json to convert from tauri option to native driver options
let json = map_capabilities(json);

// serialize json and update the content-length header to be accurate
let bytes = serde_json::to_vec(&json)?;
parts.headers.insert(CONTENT_LENGTH, bytes.len().into());
// serialize json and update the content-length header to be accurate
let bytes = serde_json::to_vec(&json)?;
parts.headers.insert(CONTENT_LENGTH, bytes.len().into());

req = Request::from_parts(parts, bytes.into());
}
Request::from_parts(parts, Full::new(bytes.into()))
} else {
let (parts, body) = req.into_parts();

let body = body.collect().await?.to_bytes().to_vec();

Request::from_parts(parts, Full::new(body.into()))
};

client
.request(forward_to_native_driver(req, args)?)
.request(forward_to_native_driver(new_req, args)?)
.err_into()
.await
}

/// Transform the request to a request for the native webdriver server.
fn forward_to_native_driver(mut req: Request<Body>, args: Args) -> Result<Request<Body>, Error> {
fn forward_to_native_driver(
mut req: Request<Full<Bytes>>,
args: Args,
) -> Result<Request<Full<Bytes>>, Error> {
let host: Authority = {
let headers = req.headers_mut();
headers.remove("host").expect("hyper request has host")
Expand Down Expand Up @@ -171,30 +188,44 @@ pub async fn run(args: Args, mut _driver: Child) -> Result<(), Error> {
let address = std::net::SocketAddr::from(([127, 0, 0, 1], args.port));

// the client we use to proxy requests to the native webdriver
let client = Client::builder()
let client = Client::builder(TokioExecutor::new())
.http1_preserve_header_case(true)
.http1_title_case_headers(true)
.retry_canceled_requests(false)
.build_http();

// pass a copy of the client to the http request handler
let service = make_service_fn(move |_| {
let client = client.clone();
let args = args.clone();
async move {
Ok::<_, Infallible>(service_fn(move |request| {
handle(client.clone(), request, args.clone())
}))
}
});

// set up a http1 server that uses the service we just created
Server::bind(&address)
.http1_title_case_headers(true)
.http1_preserve_header_case(true)
.http1_only(true)
.serve(service)
.await?;
let srv = async move {
if let Ok(listener) = TcpListener::bind(address).await {
loop {
let client = client.clone();
let args = args.clone();
if let Ok((stream, _)) = listener.accept().await {
let io = TokioIo::new(stream);

tokio::task::spawn(async move {
if let Err(err) = auto::Builder::new(TokioExecutor::new())
.http1()
.title_case_headers(true)
.preserve_header_case(true)
.serve_connection(
io,
service_fn(|request| handle(client.clone(), request, args.clone())),
)
.await
{
println!("Error serving connection: {:?}", err);
}
});
} else {
println!("accept new stream fail, ignore here");
}
}
} else {
println!("can not listen to address: {:?}", address);
}
};
srv.await;

#[cfg(unix)]
{
Expand Down
Loading