add scope test

This commit is contained in:
Rob Ede 2021-08-30 19:15:30 +01:00
parent 1c394c803a
commit e36d171f1e
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
3 changed files with 79 additions and 11 deletions

View File

@ -21,7 +21,7 @@ default = ["http"]
[dependencies]
bytestring = ">=0.1.5, <2"
firestorm = "0.4"
firestorm = "0.5"
http = { version = "0.2.3", optional = true }
log = "0.4"
regex = "1.5"
@ -29,7 +29,7 @@ serde = "1"
[dev-dependencies]
criterion = { version = "0.3", features = ["html_reports"] }
firestorm = { version = "0.4", features = ["enable_system_time"] }
firestorm = { version = "0.5", features = ["enable_system_time"] }
http = "0.2.3"
serde = { version = "1", features = ["derive"] }

View File

@ -104,11 +104,11 @@ const REGEX_FLAGS: &str = "(?s-m)";
///
///
/// # Prefix Resources
/// A prefix resource is defined as pattern that can match just the start of a path.
/// A prefix resource is defined as pattern that can match just the start of a path, up to a
/// segment boundary.
///
/// Prefix patterns with a trailing slash may have a weird, though correct, behavior.
/// They basically define and require an empty segment to match.
/// Examples are given below.
/// Prefix patterns with a trailing slash may have an unexpected, though correct, behavior.
/// They define and therefore require an empty segment in order to match. Examples are given below.
///
/// Empty pattern matches any path as a prefix.
///
@ -140,7 +140,7 @@ const REGEX_FLAGS: &str = "(?s-m)";
/// `{name:regex}`. For example, `/user/{id:\d+}` will only match paths where the user ID
/// is numeric.
///
/// The regex could pontentially match multiple segments. If this is not wanted, then care must be
/// The regex could potentially match multiple segments. If this is not wanted, then care must be
/// taken to avoid matching a slash `/`. It is guaranteed, however, that the match ends at a
/// segment boundary; the pattern `r"(/|$)` is always appended to the regex.
///
@ -1104,10 +1104,12 @@ impl ResourceDef {
let mut re = format!("({})", re);
// Ensure the match ends at a segment boundary
if !is_prefix && !has_tail_segment {
re.push('$');
} else if is_prefix && !has_tail_segment {
re.push_str(r"(/|$)");
if !has_tail_segment {
if is_prefix {
re.push_str(r"(/|$)");
} else {
re.push('$');
}
}
let re = match Regex::new(&re) {

View File

@ -1153,4 +1153,70 @@ mod tests {
Bytes::from_static(b"http://localhost:8080/a/b/c/12345")
);
}
#[actix_rt::test]
async fn dynamic_scopes() {
let srv = init_service(
App::new().service(
web::scope("/{a}/").service(
web::scope("/{b}/")
.route("", web::get().to(|_: HttpRequest| HttpResponse::Created()))
.route(
"/",
web::get().to(|_: HttpRequest| HttpResponse::Accepted()),
)
.route("/{c}", web::get().to(|_: HttpRequest| HttpResponse::Ok())),
),
),
)
.await;
// note the unintuitive behavior with trailing slashes on scopes with dynamic segments
let req = TestRequest::with_uri("/a//b//c").to_request();
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/a//b/").to_request();
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::CREATED);
let req = TestRequest::with_uri("/a//b//").to_request();
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::ACCEPTED);
let req = TestRequest::with_uri("/a//b//c/d").to_request();
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let srv = init_service(
App::new().service(
web::scope("/{a}").service(
web::scope("/{b}")
.route("", web::get().to(|_: HttpRequest| HttpResponse::Created()))
.route(
"/",
web::get().to(|_: HttpRequest| HttpResponse::Accepted()),
)
.route("/{c}", web::get().to(|_: HttpRequest| HttpResponse::Ok())),
),
),
)
.await;
let req = TestRequest::with_uri("/a/b/c").to_request();
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/a/b").to_request();
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::CREATED);
let req = TestRequest::with_uri("/a/b/").to_request();
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::ACCEPTED);
let req = TestRequest::with_uri("/a/b/c/d").to_request();
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
}
}