Skip to content

Commit a000291

Browse files
authored
Merge pull request #826 from hatoo/fix-host
Remove redundant fields in Client
2 parents 3410aed + 983695d commit a000291

5 files changed

Lines changed: 50 additions & 41 deletions

File tree

src/client.rs

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use hyper::{Method, Request, http};
66
use hyper_util::rt::{TokioExecutor, TokioIo};
77
use rand::prelude::*;
88
use std::{
9+
borrow::Cow,
910
io::Write,
1011
sync::{
1112
Arc,
@@ -207,8 +208,6 @@ pub enum ClientError {
207208

208209
pub struct Client {
209210
pub request_generator: RequestGenerator,
210-
pub url: Url,
211-
pub http_version: http::Version,
212211
pub proxy_http_version: http::Version,
213212
pub proxy_headers: http::header::HeaderMap,
214213
pub dns: Dns,
@@ -246,15 +245,14 @@ impl Default for Client {
246245
url_generator: crate::url_generator::UrlGenerator::new_static(
247246
"http://example.com".parse().unwrap(),
248247
),
248+
https: false,
249249
http_proxy: None,
250250
method: http::Method::GET,
251251
version: http::Version::HTTP_11,
252252
headers: http::header::HeaderMap::new(),
253253
body_generator: BodyGenerator::Static(Bytes::new()),
254254
aws_config: None,
255255
},
256-
url: "http://example.com".parse().unwrap(),
257-
http_version: http::Version::HTTP_11,
258256
proxy_http_version: http::Version::HTTP_11,
259257
proxy_headers: http::header::HeaderMap::new(),
260258
dns: Dns {
@@ -411,7 +409,7 @@ impl Stream {
411409
impl Client {
412410
#[inline]
413411
fn is_http2(&self) -> bool {
414-
self.http_version == http::Version::HTTP_2
412+
self.request_generator.version == http::Version::HTTP_2
415413
}
416414

417415
#[inline]
@@ -421,7 +419,7 @@ impl Client {
421419

422420
fn is_work_http2(&self) -> bool {
423421
if self.proxy_url.is_some() {
424-
if self.url.scheme() == "https" {
422+
if self.request_generator.https {
425423
self.is_http2()
426424
} else {
427425
self.is_proxy_http2()
@@ -433,7 +431,7 @@ impl Client {
433431

434432
fn work_type(&self) -> HttpWorkType {
435433
#[cfg(feature = "http3")]
436-
if self.http_version == http::Version::HTTP_3 {
434+
if self.request_generator.version == http::Version::HTTP_3 {
437435
return HttpWorkType::H3;
438436
}
439437
if self.is_work_http2() {
@@ -458,17 +456,19 @@ impl Client {
458456
}
459457

460458
let mut rng = StdRng::from_os_rng();
459+
let url = self.request_generator.url_generator.generate(&mut rng)?;
461460
// It automatically caches the result
462-
self.dns.lookup(&self.url, &mut rng).await?;
461+
self.dns.lookup(&url, &mut rng).await?;
463462
Ok(())
464463
}
465464

465+
#[allow(clippy::type_complexity)]
466466
pub fn generate_request<R: Rng + Copy>(
467467
&self,
468468
rng: &mut R,
469-
) -> Result<(Request<Full<Bytes>>, R), ClientError> {
469+
) -> Result<(Cow<'_, Url>, Request<Full<Bytes>>, R), ClientError> {
470470
let snapshot = *rng;
471-
let mut req = self.request_generator.generate(rng)?;
471+
let (url, mut req) = self.request_generator.generate(rng)?;
472472
if self.proxy_url.is_some() && req.uri().scheme_str() == Some("http") {
473473
if let Some(authority) = req.uri().authority() {
474474
let requested_host = authority.host();
@@ -486,7 +486,7 @@ impl Client {
486486
}
487487
}
488488
}
489-
Ok((req, snapshot))
489+
Ok((url, req, snapshot))
490490
}
491491

492492
/**
@@ -665,7 +665,7 @@ impl Client {
665665
};
666666
let stream = hyper::upgrade::on(res).await?;
667667
let stream = self
668-
.connect_tls(TokioIo::new(stream), url, self.http_version)
668+
.connect_tls(TokioIo::new(stream), url, self.request_generator.version)
669669
.await?;
670670
let (send_request, conn) =
671671
hyper::client::conn::http1::handshake(TokioIo::new(stream)).await?;
@@ -686,7 +686,7 @@ impl Client {
686686
client_state: &mut ClientStateHttp1,
687687
) -> Result<RequestResult, ClientError> {
688688
let do_req = async {
689-
let (request, rng) = self.generate_request(&mut client_state.rng)?;
689+
let (url, request, rng) = self.generate_request(&mut client_state.rng)?;
690690
let mut start = std::time::Instant::now();
691691
let mut first_byte: Option<std::time::Instant> = None;
692692
let mut connection_time: Option<ConnectionTime> = None;
@@ -695,7 +695,7 @@ impl Client {
695695
send_request
696696
} else {
697697
let (dns_lookup, send_request) =
698-
self.client_http1(&self.url, &mut client_state.rng).await?;
698+
self.client_http1(&url, &mut client_state.rng).await?;
699699
let dialup = std::time::Instant::now();
700700

701701
connection_time = Some(ConnectionTime {
@@ -709,7 +709,7 @@ impl Client {
709709
// This re-connects
710710
start = std::time::Instant::now();
711711
let (dns_lookup, send_request_) =
712-
self.client_http1(&self.url, &mut client_state.rng).await?;
712+
self.client_http1(&url, &mut client_state.rng).await?;
713713
send_request = send_request_;
714714
let dialup = std::time::Instant::now();
715715
connection_time = Some(ConnectionTime {
@@ -734,6 +734,7 @@ impl Client {
734734
if let Some(location) = parts.headers.get("Location") {
735735
let (send_request_redirect, new_status, len) = self
736736
.redirect(
737+
url,
737738
rng,
738739
send_request,
739740
location,
@@ -864,7 +865,9 @@ impl Client {
864865
))
865866
}
866867
} else {
867-
let (dns_lookup, stream) = self.client(url, rng, self.http_version).await?;
868+
let (dns_lookup, stream) = self
869+
.client(url, rng, self.request_generator.version)
870+
.await?;
868871
let send_request = stream.handshake_http2().await?;
869872
let dialup = std::time::Instant::now();
870873
Ok((
@@ -882,7 +885,7 @@ impl Client {
882885
client_state: &mut ClientStateHttp2,
883886
) -> Result<RequestResult, ClientError> {
884887
let do_req = async {
885-
let (request, rng) = self.generate_request(&mut client_state.rng)?;
888+
let (_url, request, rng) = self.generate_request(&mut client_state.rng)?;
886889
let start = std::time::Instant::now();
887890
let mut first_byte: Option<std::time::Instant> = None;
888891
let connection_time: Option<ConnectionTime> = None;
@@ -936,6 +939,7 @@ impl Client {
936939
#[allow(clippy::type_complexity)]
937940
async fn redirect<R: Rng + Send + Copy>(
938941
&self,
942+
base_url: Cow<'_, Url>,
939943
seed: R,
940944
send_request: SendRequestHttp1,
941945
location: &http::header::HeaderValue,
@@ -948,13 +952,13 @@ impl Client {
948952
let url = match Url::parse(location.to_str()?) {
949953
Ok(url) => url,
950954
Err(ParseError::RelativeUrlWithoutBase) => Url::options()
951-
.base_url(Some(&self.url))
955+
.base_url(Some(&base_url))
952956
.parse(location.to_str()?)?,
953957
Err(err) => Err(err)?,
954958
};
955959

956960
let (mut send_request, send_request_base) =
957-
if self.url.authority() == url.authority() && !self.disable_keepalive {
961+
if base_url.authority() == url.authority() && !self.disable_keepalive {
958962
// reuse connection
959963
(send_request, None)
960964
} else {
@@ -967,8 +971,8 @@ impl Client {
967971
send_request = stream;
968972
}
969973

970-
let mut request = self.generate_request(&mut seed.clone())?.0;
971-
if url.authority() != self.url.authority() {
974+
let mut request = self.generate_request(&mut seed.clone())?.1;
975+
if url.authority() != base_url.authority() {
972976
request.headers_mut().insert(
973977
http::header::HOST,
974978
http::HeaderValue::from_str(url.authority())?,
@@ -1008,7 +1012,8 @@ impl Client {
10081012

10091013
if let Some(location) = parts.headers.get("Location") {
10101014
let (send_request_redirect, new_status, len) =
1011-
Box::pin(self.redirect(seed, send_request, location, limit - 1, rng)).await?;
1015+
Box::pin(self.redirect(base_url, seed, send_request, location, limit - 1, rng))
1016+
.await?;
10121017
send_request = send_request_redirect;
10131018
status = new_status;
10141019
len_bytes = len;
@@ -1056,7 +1061,8 @@ async fn setup_http2<R: Rng>(
10561061
client: &Client,
10571062
rng: &mut R,
10581063
) -> Result<(ConnectionTime, SendRequestHttp2), ClientError> {
1059-
let (connection_time, send_request) = client.connect_http2(&client.url, rng).await?;
1064+
let url = client.request_generator.url_generator.generate(rng)?;
1065+
let (connection_time, send_request) = client.connect_http2(&url, rng).await?;
10601066

10611067
Ok((connection_time, send_request))
10621068
}
@@ -1099,29 +1105,27 @@ pub(crate) fn set_start_latency_correction<E>(
10991105

11001106
pub async fn work_debug<W: Write>(w: &mut W, client: Arc<Client>) -> Result<(), ClientError> {
11011107
let mut rng = Pcg64Si::from_os_rng();
1102-
let (request, _) = client.generate_request(&mut rng)?;
1108+
let (url, request, _) = client.generate_request(&mut rng)?;
11031109

11041110
writeln!(w, "{request:#?}")?;
11051111

11061112
let response = match client.work_type() {
11071113
#[cfg(feature = "http3")]
11081114
HttpWorkType::H3 => {
1109-
let (_, (h3_connection, client_state)) =
1110-
client.connect_http3(&client.url, &mut rng).await?;
1115+
let (_, (h3_connection, client_state)) = client.connect_http3(&url, &mut rng).await?;
11111116

11121117
send_debug_request_http3(h3_connection, client_state, request).await?
11131118
}
11141119
HttpWorkType::H2 => {
1115-
let (_, mut client_state) = client.connect_http2(&client.url, &mut rng).await?;
1120+
let (_, mut client_state) = client.connect_http2(&url, &mut rng).await?;
11161121
let response = client_state.send_request(request).await?;
11171122
let (parts, body) = response.into_parts();
11181123
let body = body.collect().await.unwrap().to_bytes();
11191124

11201125
http::Response::from_parts(parts, body)
11211126
}
11221127
HttpWorkType::H1 => {
1123-
let (_dns_lookup, mut send_request) =
1124-
client.client_http1(&client.url, &mut rng).await?;
1128+
let (_dns_lookup, mut send_request) = client.client_http1(&url, &mut rng).await?;
11251129

11261130
let response = send_request.send_request(request).await?;
11271131
let (parts, body) = response.into_parts();

src/client_h3.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ impl Client {
119119
client_state: &mut ClientStateHttp3,
120120
) -> Result<RequestResult, ClientError> {
121121
let do_req = async {
122-
let (request, rng) = self.generate_request(&mut client_state.rng)?;
122+
let (_url, request, rng) = self.generate_request(&mut client_state.rng)?;
123123
let start = std::time::Instant::now();
124124
let connection_time: Option<ConnectionTime> = None;
125125
let mut first_byte: Option<std::time::Instant> = None;
@@ -374,8 +374,9 @@ pub(crate) async fn setup_http3<R: Rng>(
374374
client: &Client,
375375
rng: &mut R,
376376
) -> Result<(ConnectionTime, SendRequestHttp3), ClientError> {
377+
let url = client.request_generator.url_generator.generate(rng)?;
377378
// Whatever rng state, all urls should have the same authority
378-
let (connection_time, send_request) = client.connect_http3(&client.url, rng).await?;
379+
let (connection_time, send_request) = client.connect_http3(&url, rng).await?;
379380

380381
Ok((connection_time, send_request))
381382
}

src/db.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn store(
3232
let mut affected_rows = 0;
3333

3434
for request in request_records {
35-
let req = client.generate_request(&mut request.rng.clone()).unwrap().0;
35+
let req = client.generate_request(&mut request.rng.clone()).unwrap().1;
3636
let url = req.uri();
3737
affected_rows += t.execute(
3838
"INSERT INTO oha (url, start, start_latency_correction, end, duration, status, len_bytes, run) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",

src/lib.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -497,11 +497,6 @@ pub async fn run(mut opts: Opts) -> anyhow::Result<()> {
497497

498498
if let Some(h) = opts.host {
499499
headers.insert(http::header::HOST, HeaderValue::from_bytes(h.as_bytes())?);
500-
} else if http_version < http::Version::HTTP_2 {
501-
headers.insert(
502-
http::header::HOST,
503-
http::header::HeaderValue::from_str(url.authority())?,
504-
);
505500
}
506501

507502
if let Some(auth) = opts.basic_auth {
@@ -572,6 +567,7 @@ pub async fn run(mut opts: Opts) -> anyhow::Result<()> {
572567
let client = Arc::new(client::Client {
573568
request_generator: RequestGenerator {
574569
url_generator,
570+
https: url.scheme() == "https",
575571
version: http_version,
576572
aws_config,
577573
method,
@@ -586,8 +582,6 @@ pub async fn run(mut opts: Opts) -> anyhow::Result<()> {
586582
None
587583
},
588584
},
589-
url,
590-
http_version,
591585
proxy_http_version,
592586
proxy_headers,
593587
dns: client::Dns {

src/request_generator.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
use std::borrow::Cow;
2+
13
use bytes::Bytes;
24
use http_body_util::Full;
35
use hyper::http;
46
use hyper::{HeaderMap, Method, Version};
57
use rand::Rng;
68
use rand::seq::IndexedRandom;
79
use thiserror::Error;
10+
use url::Url;
811

912
use crate::aws_auth::{self, AwsSignatureConfig};
1013
use crate::url_generator;
@@ -21,6 +24,7 @@ pub enum BodyGenerator {
2124

2225
pub struct RequestGenerator {
2326
pub url_generator: url_generator::UrlGenerator,
27+
pub https: bool,
2428
// Only if http with proxy
2529
pub http_proxy: Option<Proxy>,
2630
pub method: Method,
@@ -56,7 +60,7 @@ impl RequestGenerator {
5660
pub fn generate<R: Rng>(
5761
&self,
5862
rng: &mut R,
59-
) -> Result<hyper::Request<Full<Bytes>>, RequestGenerationError> {
63+
) -> Result<(Cow<'_, Url>, hyper::Request<Full<Bytes>>), RequestGenerationError> {
6064
let url = self.url_generator.generate(rng)?;
6165
let body = self.generate_body(rng);
6266

@@ -87,9 +91,15 @@ impl RequestGenerator {
8791
}
8892
}
8993

94+
if self.version < Version::HTTP_2 {
95+
headers
96+
.entry(http::header::HOST)
97+
.or_insert_with(|| http::header::HeaderValue::from_str(url.authority()).unwrap());
98+
}
99+
90100
*builder.headers_mut().unwrap() = headers;
91101

92102
let req = builder.body(Full::new(body))?;
93-
Ok(req)
103+
Ok((url, req))
94104
}
95105
}

0 commit comments

Comments
 (0)