From 1914f6f252ea9dffc42411ec562e6400709527fe Mon Sep 17 00:00:00 2001 From: TheRealLorenz Date: Wed, 29 Nov 2023 12:45:40 +0100 Subject: [PATCH] Parse query params separately --- demo.http | 7 ++++++- rq-cli/src/app.rs | 37 ++++++++++++++++++++++++++++++++++--- rq-core/src/grammar.pest | 9 +++++++-- rq-core/src/parser.rs | 19 +++++++++++++++++++ rq-core/src/request.rs | 1 + 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/demo.http b/demo.http index c1aa705..b6a90ed 100644 --- a/demo.http +++ b/demo.http @@ -12,8 +12,13 @@ Bar: Baz ### -PUT https://httpin.org/put +PUT https://httpbin.org/put { "foo": "bar" } + +### + +GET https://httpbin.org/get?param1=2¶m2=3 + diff --git a/rq-cli/src/app.rs b/rq-cli/src/app.rs index 5ebed3a..9f15748 100644 --- a/rq-cli/src/app.rs +++ b/rq-cli/src/app.rs @@ -30,10 +30,41 @@ enum FocusState { impl MenuItem for HttpRequest { fn render(&self) -> Vec> { - let mut lines = vec![Line::from(vec![ + let mut lines = Vec::new(); + + let mut first_line_spans = vec![ Span::styled(self.method.to_string(), Style::default().fg(Color::Green)), - Span::raw(format!(" {} {:?}", self.url, self.version)), - ])]; + Span::raw(" "), + Span::raw(self.url.as_str()), + ]; + let version_span = Span::raw(format!(" {:?}", self.version)); + + let mut query = self + .query + .iter() + .enumerate() + .map(|(i, (k, v))| { + Line::from(vec![ + Span::raw(" ".repeat(self.method.to_string().len() + 1)), + Span::styled( + if i == 0 { "?" } else { "&" }, + Style::default().fg(Color::Blue), + ), + Span::raw(k), + Span::raw("="), + Span::raw(v), + ]) + }) + .collect::>(); + + if query.is_empty() { + first_line_spans.push(version_span); + lines.push(Line::from(first_line_spans)); + } else { + lines.push(Line::from(first_line_spans)); + query.last_mut().unwrap().spans.push(version_span); + lines.extend(query); + } let headers: Vec = self .headers() diff --git a/rq-core/src/grammar.pest b/rq-core/src/grammar.pest index 62b3bd6..af2045b 100644 --- a/rq-core/src/grammar.pest +++ b/rq-core/src/grammar.pest @@ -7,12 +7,17 @@ request = { body? } -request_line = _{ (method ~ " "+)? ~ uri ~ (" "+ ~ version)? ~ NEWLINE } -uri = { (!whitespace ~ ANY)+ } +request_line = _{ (method ~ " "+)? ~ uri ~ query? ~ (" "+ ~ version)? ~ NEWLINE } +uri = { (!(whitespace| "?") ~ ANY)+ } method = { ("GET" | "DELETE" | "POST" | "PUT") } version = { "HTTP/" ~ ("0.9" | "1.0" | "1.1" | "2.0" | "3.0") } whitespace = _{ " " | "\t" | NEWLINE } +query = { "?" ~ query_item ~ ("&" ~ query_item)* } +query_item = { query_name ~ "=" ~ query_value } +query_name = { (!(NEWLINE | "=") ~ ANY)+ } +query_value = { (!(NEWLINE | "&") ~ ANY)+ } + headers = { header+ } header = { header_name ~ ":" ~ whitespace ~ header_value ~ NEWLINE } header_name = { (!(NEWLINE | ":") ~ ANY)+ } diff --git a/rq-core/src/parser.rs b/rq-core/src/parser.rs index 623c77f..f6f43ca 100644 --- a/rq-core/src/parser.rs +++ b/rq-core/src/parser.rs @@ -59,6 +59,7 @@ fn http_version_from_str(input: &str) -> Version { pub struct HttpRequest { pub method: Method, pub url: String, + pub query: HashMap, pub version: Version, headers: HttpHeaders, pub body: String, @@ -80,6 +81,23 @@ impl<'i> From> for HttpRequest { .unwrap_or_default(); let url = pairs.next().unwrap().as_str().to_string(); + + let query = pairs + .next_if(|pair| pair.as_rule() == Rule::query) + .map(|pair| { + pair.into_inner() + .map(|pair| { + let mut pairs = pair.into_inner(); + + let key = pairs.next().unwrap().as_str().to_string(); + let value = pairs.next().unwrap().as_str().to_string(); + + (key, value) + }) + .collect::>() + }) + .unwrap_or_default(); + let version = pairs .next_if(|pair| pair.as_rule() == Rule::version) .map(|pair| http_version_from_str(pair.as_str())) @@ -98,6 +116,7 @@ impl<'i> From> for HttpRequest { Self { method, url, + query, version, headers, body, diff --git a/rq-core/src/request.rs b/rq-core/src/request.rs index 9f6b6b2..183dbb6 100644 --- a/rq-core/src/request.rs +++ b/rq-core/src/request.rs @@ -49,6 +49,7 @@ type RequestResult = Result>; pub async fn execute(req: &HttpRequest) -> RequestResult { let request = CLIENT .request(req.method.clone(), &req.url) + .query(&req.query) .headers(req.headers()) .body(req.body.clone());