Skip to content

Commit

Permalink
Validate request URL using bound data
Browse files Browse the repository at this point in the history
Fixes #132. Should perform
protocol validations after bounding the URL so that the variables are
taken into account. This will fix the regression that prevented URLs
like "{{API_ROOT}}/get" from being accepted when the API_ROOT variable
itself starts with http:// or https://.
  • Loading branch information
danirod committed Feb 12, 2025
1 parent 7531079 commit acdf6c0
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 28 deletions.
7 changes: 7 additions & 0 deletions src/client/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use std::{
io::{BufWriter, Write},
};
use thiserror::Error;
use url::Url;

use crate::{
entities::{EndpointData, KeyValueTable, RawEncoding, RequestMethod, RequestPayload},
Expand All @@ -37,6 +38,12 @@ pub struct BoundRequest {
pub body: Option<Vec<u8>>,
}

impl BoundRequest {
pub fn full_url(&self) -> Result<Url, url::ParseError> {
Url::parse(&self.url)
}
}

#[derive(Default, Debug, Clone)]
struct BoundBody {
content: Vec<u8>,
Expand Down
51 changes: 23 additions & 28 deletions src/widgets/endpoint_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,39 +401,34 @@ mod imp {
})
}

/// Add http:// to the beginning of the typed URL if the protocol has not been specified.
fn assert_protocol_is_present(&self) {
let url = self.request_url.text().to_string();
if let Ok(url_object) = Url::parse(&url) {
if !url_object.scheme().is_empty() {
return;
}
}
let protocoled_url = format!("http://{}", url);
self.request_url.set_text(&protocoled_url);
}

fn assert_protocol_is_valid(&self) -> Option<CarteroError> {
let url = self.request_url.text().to_string();
match Url::parse(&url) {
Err(_) => Some(CarteroError::InvalidProtocol),
Ok(url_object) => match url_object.scheme() {
"http" | "https" => None,
_ => Some(CarteroError::InvalidProtocol),
},
}
}

/// Executes an HTTP request based on the current contents of the pane.
pub(super) async fn perform_request(&self) -> Result<(), CarteroError> {
self.assert_protocol_is_present();
if let Some(err) = self.assert_protocol_is_valid() {
return Err(err);
};
let request = self.extract_endpoint()?;
let request = BoundRequest::try_from(request)?;
let request_obj = isahc::Request::try_from(request)?;

// Protocol validation.
let request_url = match request.full_url() {
Ok(r) => r,
Err(url::ParseError::RelativeUrlWithoutBase) => {
// The URL is not considered an absolute URL, missing protocol.
let url_field = self.request_url.text().to_string();
let url_field = format!("http://{}", url_field);
self.request_url.set_text(&url_field);

// Now try again.
return std::boxed::Box::pin(self.perform_request()).await;
}
Err(_) => return Err(RequestError::InvalidUrl.into()),
};

// Validate protocol is supported.
let request_scheme = request_url.scheme();
if request_scheme != "http" && request_scheme != "https" {
return Err(CarteroError::InvalidProtocol);
}

// Execute the request.
let request_obj = isahc::Request::try_from(request)?;
let start = Instant::now();
let mut response_obj = request_obj
.send_async()
Expand Down

0 comments on commit acdf6c0

Please sign in to comment.