Skip to content

Commit eb8b8cb

Browse files
committed
Add optional limit on request size
Signed-off-by: Luminita Voicu <[email protected]>
1 parent 7f3a14f commit eb8b8cb

File tree

4 files changed

+58
-39
lines changed

4 files changed

+58
-39
lines changed

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
//! ```
4848
//! use micro_http::{Request, Version};
4949
//!
50-
//! let http_request = Request::try_from(b"GET http://localhost/home HTTP/1.0\r\n\r\n").unwrap();
50+
//! let request_bytes = b"GET http://localhost/home HTTP/1.0\r\n\r\n";
51+
//! let http_request = Request::try_from(request_bytes, None).unwrap();
5152
//! assert_eq!(http_request.http_version(), Version::Http10);
5253
//! assert_eq!(http_request.uri().get_abs_path(), "/home");
5354
//! ```

src/request.rs

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,18 @@ impl Request {
181181
/// ```
182182
/// use micro_http::Request;
183183
///
184-
/// let http_request = Request::try_from(b"GET http://localhost/home HTTP/1.0\r\n\r\n").unwrap();
184+
/// let max_request_len = 2000;
185+
/// let request_bytes = b"GET http://localhost/home HTTP/1.0\r\n\r\n";
186+
/// let http_request = Request::try_from(request_bytes, Some(max_request_len)).unwrap();
185187
/// ```
186-
pub fn try_from(byte_stream: &[u8]) -> Result<Self, RequestError> {
188+
pub fn try_from(byte_stream: &[u8], max_len: Option<usize>) -> Result<Self, RequestError> {
189+
// If a size limit is provided, verify the request length does not exceed it.
190+
if let Some(limit) = max_len {
191+
if byte_stream.len() >= limit {
192+
return Err(RequestError::InvalidRequest);
193+
}
194+
}
195+
187196
// The first line of the request is the Request Line. The line ending is CR LF.
188197
let request_line_end = match find(byte_stream, &[CR, LF]) {
189198
Some(len) => len,
@@ -439,7 +448,7 @@ mod tests {
439448
};
440449
let request_bytes = b"GET http://localhost/home HTTP/1.0\r\n\
441450
Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT\r\n\r\n";
442-
let request = Request::try_from(request_bytes).unwrap();
451+
let request = Request::try_from(request_bytes, None).unwrap();
443452
assert_eq!(request, expected_request);
444453
assert_eq!(request.uri(), &Uri::new("http://localhost/home"));
445454
assert_eq!(request.http_version(), Version::Http10);
@@ -448,14 +457,14 @@ mod tests {
448457
// Test for invalid Request (missing CR LF).
449458
let request_bytes = b"GET / HTTP/1.1";
450459
assert_eq!(
451-
Request::try_from(request_bytes).unwrap_err(),
460+
Request::try_from(request_bytes, None).unwrap_err(),
452461
RequestError::InvalidRequest
453462
);
454463

455464
// Test for invalid Request (length is less than minimum).
456465
let request_bytes = b"GET";
457466
assert_eq!(
458-
Request::try_from(request_bytes).unwrap_err(),
467+
Request::try_from(request_bytes, None).unwrap_err(),
459468
RequestError::InvalidRequest
460469
);
461470

@@ -464,18 +473,29 @@ mod tests {
464473
Content-Length: 13\r\n\
465474
Content-Type: application/json\r\n\r\nwhatever body";
466475
assert_eq!(
467-
Request::try_from(request_bytes).unwrap_err(),
476+
Request::try_from(request_bytes, None).unwrap_err(),
468477
RequestError::InvalidRequest
469478
);
470479

480+
// Test for request larger than maximum len provided.
481+
let request_bytes = b"GET http://localhost/home HTTP/1.0\r\n\
482+
Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT\r\n\r\n";
483+
assert_eq!(
484+
Request::try_from(request_bytes, Some(20)).unwrap_err(),
485+
RequestError::InvalidRequest
486+
);
487+
488+
// Test request smaller than maximum len provided is ok.
489+
let request_bytes = b"GET http://localhost/home HTTP/1.0\r\n\
490+
Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT\r\n\r\n";
491+
assert!(Request::try_from(request_bytes, Some(500)).is_ok());
492+
471493
// Test for a request with the headers we are looking for.
472-
let request = Request::try_from(
473-
b"PATCH http://localhost/home HTTP/1.1\r\n\
474-
Expect: 100-continue\r\n\
475-
Transfer-Encoding: chunked\r\n\
476-
Content-Length: 26\r\n\r\nthis is not\n\r\na json \nbody",
477-
)
478-
.unwrap();
494+
let request_bytes = b"PATCH http://localhost/home HTTP/1.1\r\n\
495+
Expect: 100-continue\r\n\
496+
Transfer-Encoding: chunked\r\n\
497+
Content-Length: 26\r\n\r\nthis is not\n\r\na json \nbody";
498+
let request = Request::try_from(request_bytes, None).unwrap();
479499
assert_eq!(request.uri(), &Uri::new("http://localhost/home"));
480500
assert_eq!(request.http_version(), Version::Http11);
481501
assert_eq!(request.method(), Method::Patch);
@@ -490,31 +510,26 @@ mod tests {
490510
);
491511

492512
// Test for an invalid request format.
493-
Request::try_from(b"PATCH http://localhost/home HTTP/1.1\r\n").unwrap_err();
513+
Request::try_from(b"PATCH http://localhost/home HTTP/1.1\r\n", None).unwrap_err();
494514

495515
// Test for an invalid encoding.
496-
assert!(Request::try_from(
497-
b"PATCH http://localhost/home HTTP/1.1\r\n\
498-
Expect: 100-continue\r\n\
499-
Transfer-Encoding: identity; q=0\r\n\
500-
Content-Length: 26\r\n\r\nthis is not\n\r\na json \nbody",
501-
)
502-
.is_ok());
516+
let request_bytes = b"PATCH http://localhost/home HTTP/1.1\r\n\
517+
Expect: 100-continue\r\n\
518+
Transfer-Encoding: identity; q=0\r\n\
519+
Content-Length: 26\r\n\r\nthis is not\n\r\na json \nbody";
520+
521+
assert!(Request::try_from(request_bytes, None).is_ok());
503522

504523
// Test for an invalid content length.
505-
let request = Request::try_from(
506-
b"PATCH http://localhost/home HTTP/1.1\r\n\
507-
Content-Length: 5000\r\n\r\nthis is a short body",
508-
)
509-
.unwrap_err();
524+
let request_bytes = b"PATCH http://localhost/home HTTP/1.1\r\n\
525+
Content-Length: 5000\r\n\r\nthis is a short body";
526+
let request = Request::try_from(request_bytes, None).unwrap_err();
510527
assert_eq!(request, RequestError::InvalidRequest);
511528

512529
// Test for a request without a body and an optional header.
513-
let request = Request::try_from(
514-
b"GET http://localhost/ HTTP/1.0\r\n\
515-
Accept-Encoding: gzip\r\n\r\n",
516-
)
517-
.unwrap();
530+
let request_bytes = b"GET http://localhost/ HTTP/1.0\r\n\
531+
Accept-Encoding: gzip\r\n\r\n";
532+
let request = Request::try_from(request_bytes, None).unwrap();
518533
assert_eq!(request.uri(), &Uri::new("http://localhost/"));
519534
assert_eq!(request.http_version(), Version::Http10);
520535
assert_eq!(request.method(), Method::Get);
@@ -523,8 +538,9 @@ mod tests {
523538
assert_eq!(request.headers.content_length(), 0);
524539
assert!(request.body.is_none());
525540

526-
let request = Request::try_from(b"GET http://localhost/ HTTP/1.0\r\n\
527-
Accept-Encoding: identity;q=0\r\n\r\n");
541+
let request_bytes = b"GET http://localhost/ HTTP/1.0\r\n\
542+
Accept-Encoding: identity;q=0\r\n\r\n";
543+
let request = Request::try_from(request_bytes, None);
528544
assert_eq!(
529545
request.unwrap_err(),
530546
RequestError::HeaderError(HttpHeaderError::InvalidValue(

src/router.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ impl<T: Send> HttpRoutes<T> {
7979
/// let handler = MockHandler {};
8080
/// router.add_route(Method::Get, "/func1".to_string(), Box::new(handler)).unwrap();
8181
///
82-
/// let request =
83-
/// Request::try_from(b"GET http://localhost/api/v1/func1 HTTP/1.1\r\n\r\n").unwrap();
82+
/// let request_bytes = b"GET http://localhost/api/v1/func1 HTTP/1.1\r\n\r\n";
83+
/// let request = Request::try_from(request_bytes, None).unwrap();
8484
/// let arg = HandlerArg(true);
8585
/// let reply = router.handle_http_request(&request, &arg);
8686
/// assert_eq!(reply.status(), StatusCode::OK);
@@ -148,7 +148,7 @@ mod tests {
148148
.unwrap();
149149

150150
let request =
151-
Request::try_from(b"GET http://localhost/api/v1/func2 HTTP/1.1\r\n\r\n").unwrap();
151+
Request::try_from(b"GET http://localhost/api/v1/func2 HTTP/1.1\r\n\r\n", None).unwrap();
152152
let arg = HandlerArg(true);
153153
let reply = router.handle_http_request(&request, &arg);
154154
assert_eq!(reply.status(), StatusCode::NotFound);

src/server.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,8 @@ mod tests {
765765
second_server_request.request,
766766
Request::try_from(
767767
b"GET /machine-config HTTP/1.1\r\n\
768-
Content-Type: application/json\r\n\r\n"
768+
Content-Type: application/json\r\n\r\n",
769+
None
769770
)
770771
.unwrap()
771772
);
@@ -989,7 +990,8 @@ mod tests {
989990
second_server_request.request,
990991
Request::try_from(
991992
b"GET /machine-config HTTP/1.1\r\n\
992-
Content-Type: application/json\r\n\r\n"
993+
Content-Type: application/json\r\n\r\n",
994+
None
993995
)
994996
.unwrap()
995997
);

0 commit comments

Comments
 (0)