From 5833556e5f8d9ccb346ef586cb1b5f51add64357 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Wed, 28 Feb 2024 10:39:59 -0500 Subject: [PATCH] chore: resolve TODOs in the pingora client example Signed-off-by: Shane Utt --- pingora/Cargo.toml | 1 + pingora/examples/client.rs | 66 ++++++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/pingora/Cargo.toml b/pingora/Cargo.toml index c269199..9d6aea3 100644 --- a/pingora/Cargo.toml +++ b/pingora/Cargo.toml @@ -40,6 +40,7 @@ log = { workspace = true } prometheus = "0.13" once_cell = { workspace = true } bytes = { workspace = true } +regex = "1" [features] default = ["openssl"] diff --git a/pingora/examples/client.rs b/pingora/examples/client.rs index c235dd1..9462aa2 100644 --- a/pingora/examples/client.rs +++ b/pingora/examples/client.rs @@ -12,29 +12,61 @@ // See the License for the specific language governing permissions and // limitations under the License. -use pingora::connectors::http::Connector; -use pingora::upstreams::peer::HttpPeer; +use pingora::{connectors::http::Connector, prelude::*}; use pingora_http::RequestHeader; +use regex::Regex; #[tokio::main] -async fn main() { +async fn main() -> Result<()> { let connector = Connector::new(None); - let mut peer = HttpPeer::new("1.1.1.1:443", true, "one.one.one.one".into()); + // create the HTTP session + let peer_addr = "1.1.1.1:443"; + let mut peer = HttpPeer::new(peer_addr, true, "one.one.one.one".into()); peer.options.set_http_version(2, 1); - let (mut http, _reused) = connector.get_http_session(&peer).await.unwrap(); + let (mut http, _reused) = connector.get_http_session(&peer).await?; + + // perform a GET request + let mut new_request = RequestHeader::build("GET", b"/", None)?; + new_request.insert_header("Host", "one.one.one.one")?; + http.write_request_header(Box::new(new_request)).await?; - let mut new_request = RequestHeader::build("GET", b"/", None).unwrap(); - new_request - .insert_header("Host", "one.one.one.one") - .unwrap(); - http.write_request_header(Box::new(new_request)) - .await - .unwrap(); // Servers usually don't respond until the full request body is read. - http.finish_request_body().await.unwrap(); - http.read_response_header().await.unwrap(); - println!("{:#?}", http.response_header().unwrap()); - // TODO: continue reading the body - // TODO: return the connection back to the `connector` (or discard it) + http.finish_request_body().await?; + http.read_response_header().await?; + + // display the headers from the response + if let Some(header) = http.response_header() { + println!("{header:#?}"); + } else { + return Error::e_explain(ErrorType::InvalidHTTPHeader, "No response header"); + }; + + // collect the response body + let mut response_body = String::new(); + while let Some(chunk) = http.read_response_body().await? { + response_body.push_str(&String::from_utf8_lossy(&chunk)); + } + + // verify that the response body is valid HTML by displaying the page + let re = Regex::new(r"<title>(.*?)") + .or_err(ErrorType::InternalError, "Failed to compile regex")?; + if let Some(title) = re + .captures(&response_body) + .and_then(|caps| caps.get(1).map(|match_| match_.as_str())) + { + println!("Page Title: {title}"); + } else { + return Error::e_explain( + ErrorType::new("InvalidHTML"), + "No found in response body", + ); + } + + // gracefully release the connection + connector + .release_http_session(http, &peer, Some(std::time::Duration::from_secs(5))) + .await; + + Ok(()) }