Skip to content

Commit 4c3da23

Browse files
committed
Improve parsing the first line of a request
This now correctly extracts spans, even if elements of the first line have multiple spaces between them
1 parent ef4295b commit 4c3da23

File tree

3 files changed

+51
-11
lines changed

3 files changed

+51
-11
lines changed

src/models/partial_request.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -151,19 +151,25 @@ fn parse_first_line(
151151
Option<Range<usize>>,
152152
Option<Range<usize>>,
153153
) {
154-
let parts: Vec<_> = first_line.split_whitespace().collect();
155-
156-
let mut start = 0;
154+
let mut parts = vec![];
155+
let mut last_end = 0;
156+
157+
for (i, c) in first_line.char_indices() {
158+
if c.is_whitespace() {
159+
if i > last_end {
160+
parts.push(last_end..i);
161+
}
162+
last_end = i + 1;
163+
}
164+
}
157165

158-
let mut get_span = |part: &str| {
159-
let span = start..start + part.len();
160-
start = span.end + 1;
161-
span
162-
};
166+
if last_end < first_line.len() {
167+
parts.push(last_end..first_line.len());
168+
}
163169

164-
let method_span = parts.get(0).map(|&method| get_span(method));
165-
let uri_span = parts.get(1).map(|&uri| get_span(uri));
166-
let http_version_span = parts.get(2).map(|&version| get_span(version));
170+
let method_span = parts.get(0).cloned();
171+
let uri_span = parts.get(1).cloned();
172+
let http_version_span = parts.get(2).cloned();
167173

168174
(method_span, uri_span, http_version_span)
169175
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
GET https://example.com HTTP/1.1

tests/parse_tests.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,36 @@ fn parse_post_with_body_request() {
194194
request
195195
);
196196
}
197+
198+
#[test]
199+
fn parse_get_with_multiple_spaces_request() {
200+
let content = fs::read_to_string("./tests/fixtures/get_with_multiple_spaces.request")
201+
.expect("should read test fixture");
202+
203+
let partial = PartialHttpRequest::from_str(&content).expect("should be parsable");
204+
205+
assert_eq!(
206+
PartialHttpRequest::new(
207+
&content,
208+
Some(5..24),
209+
Some(0..3),
210+
Some(26..34),
211+
vec![],
212+
None
213+
),
214+
partial
215+
);
216+
217+
let request: HttpRequest = partial.into();
218+
219+
assert_eq!(
220+
HttpRequest {
221+
uri: Uri::new("https://example.com"),
222+
method: "GET".into(),
223+
http_version: "HTTP/1.1".into(),
224+
headers: vec![],
225+
body: None
226+
},
227+
request
228+
);
229+
}

0 commit comments

Comments
 (0)