84 84 | }
|
85 85 | }
|
86 86 |
|
87 87 | /// Get the string to sign for the test
|
88 88 | pub(crate) fn string_to_sign(&self, signature_location: SignatureLocation) -> String {
|
89 89 | match signature_location {
|
90 90 | SignatureLocation::QueryParams => read(&self.path("query-string-to-sign.txt")),
|
91 91 | SignatureLocation::Headers => read(&self.path("header-string-to-sign.txt")),
|
92 92 | }
|
93 93 | }
|
94 94 |
|
95 95 | /// Get the signature for the test
|
96 96 | pub(crate) fn signature(&self, signature_location: SignatureLocation) -> String {
|
97 97 | match signature_location {
|
98 98 | SignatureLocation::QueryParams => read(&self.path("query-signature.txt")),
|
99 99 | SignatureLocation::Headers => read(&self.path("header-signature.txt")),
|
100 100 | }
|
101 101 | }
|
102 102 |
|
103 103 | /// Get the test context for the test
|
104 104 | pub(crate) fn context(&self) -> TestContext {
|
105 105 | let context = read(&self.path("context.json"));
|
106 106 | let tc_builder: TestContextBuilder = serde_json::from_str(&context).unwrap();
|
107 107 | tc_builder.build()
|
108 108 | }
|
109 109 | }
|
110 110 |
|
111 111 | fn test_parsed_request(path: &str) -> TestRequest {
|
112 112 | match parse_request(read(path).as_bytes()) {
|
113 113 | Ok(parsed) => parsed,
|
114 - | Err(err) => panic!("Failed to parse {}: {}", path, err),
|
114 + | Err(err) => panic!("Failed to parse {path}: {err}"),
|
115 115 | }
|
116 116 | }
|
117 117 |
|
118 118 | fn new_v4_signing_params_from_context(
|
119 119 | test_context: &'_ TestContext,
|
120 120 | signature_location: SignatureLocation,
|
121 121 | ) -> crate::http_request::SigningParams<'_> {
|
122 122 | let mut params = crate::sign::v4::SigningParams::from(test_context);
|
123 123 | params.settings.signature_location = signature_location;
|
124 124 | params.into()
|
125 125 | }
|
126 126 |
|
127 127 | /// Run the given test from the v4 suite for both header and query
|
128 128 | /// signature locations
|
129 129 | pub(crate) fn run_test_suite_v4(test_name: &'static str) {
|
130 130 | run_v4_test(test_name, SignatureLocation::Headers);
|
131 131 | run_v4_test(test_name, SignatureLocation::QueryParams);
|
132 132 | }
|
133 133 |
|
134 134 | fn assert_uri_eq(expected: &Uri, actual: &Uri) {
|
135 135 | assert_eq!(expected.scheme(), actual.scheme());
|
136 136 | assert_eq!(expected.authority(), actual.authority());
|
137 137 | assert_eq!(expected.path(), actual.path());
|
138 138 |
|
139 139 | // query params may be out of order
|
140 140 | let mut expected_params: Vec<(Cow<'_, str>, Cow<'_, str>)> =
|
141 141 | form_urlencoded::parse(expected.query().unwrap_or_default().as_bytes()).collect();
|
142 142 | expected_params.sort();
|
143 143 |
|
144 144 | let mut actual_params: Vec<(Cow<'_, str>, Cow<'_, str>)> =
|
421 421 | #[test]
|
422 422 | fn test_read_query_params() {
|
423 423 | let req = SigningSuiteTest::v4a("get-header-value-trim").request();
|
424 424 | assert_eq!(req.method, "GET");
|
425 425 | assert_eq!(req.uri, "https://example.amazonaws.com/");
|
426 426 | assert!(!req.headers.is_empty());
|
427 427 | }
|
428 428 | }
|
429 429 |
|
430 430 | fn read(path: &str) -> String {
|
431 - | println!("Loading `{}` for test case...", path);
|
431 + | println!("Loading `{path}` for test case...");
|
432 432 | let v = {
|
433 433 | match std::fs::read_to_string(path) {
|
434 434 | // This replacement is necessary for tests to pass on Windows, as reading the
|
435 435 | // test snapshots from the file system results in CRLF line endings being inserted.
|
436 436 | Ok(value) => value.replace("\r\n", "\n"),
|
437 437 | Err(err) => {
|
438 - | panic!("failed to load test case `{}`: {}", path, err);
|
438 + | panic!("failed to load test case `{path}`: {err}");
|
439 439 | }
|
440 440 | }
|
441 441 | };
|
442 442 |
|
443 443 | v.trim().to_string()
|
444 444 | }
|
445 445 |
|
446 446 | pub(crate) struct TestRequest {
|
447 447 | pub(crate) uri: String,
|
448 448 | pub(crate) method: String,
|
449 449 | pub(crate) headers: Vec<(String, String)>,
|
450 450 | pub(crate) body: TestSignedBody,
|
451 451 | }
|
452 452 |
|
453 453 | pub(crate) enum TestSignedBody {
|
454 454 | Signable(SignableBody<'static>),
|
455 455 | Bytes(Vec<u8>),
|
456 456 | }
|
457 457 |
|
458 458 | impl TestSignedBody {
|
459 459 | fn as_signable_body(&self) -> SignableBody<'_> {
|
460 460 | match self {
|
461 461 | TestSignedBody::Signable(data) => data.clone(),
|
462 462 | TestSignedBody::Bytes(data) => SignableBody::Bytes(data.as_slice()),
|
463 463 | }
|
464 464 | }
|
465 465 | }
|
466 466 |
|
467 467 | impl TestRequest {
|
468 468 | pub(crate) fn set_body(&mut self, body: SignableBody<'static>) {
|
469 469 | self.body = TestSignedBody::Signable(body);
|
470 470 | }
|
471 471 |
|
472 472 | pub(crate) fn as_http_request(&self) -> http0::Request<&'static str> {
|
473 473 | let mut builder = http0::Request::builder()
|
474 474 | .uri(&self.uri)
|
475 475 | .method(Method::from_bytes(self.method.as_bytes()).unwrap());
|
476 476 | for (k, v) in &self.headers {
|
477 477 | builder = builder.header(k, v);
|
478 478 | }
|
479 479 | builder.body("body").unwrap()
|
480 480 | }
|
481 481 | }
|
482 482 |
|
483 483 | impl<B: AsRef<[u8]>> From<http0::Request<B>> for TestRequest {
|
484 484 | fn from(value: http0::Request<B>) -> Self {
|
485 485 | let invalid = value
|
486 486 | .headers()
|
487 487 | .values()
|
488 488 | .find(|h| std::str::from_utf8(h.as_bytes()).is_err());
|
489 489 | if let Some(invalid) = invalid {
|
490 - | panic!("invalid header: {:?}", invalid);
|
490 + | panic!("invalid header: {invalid:?}");
|
491 491 | }
|
492 492 | Self {
|
493 493 | uri: value.uri().to_string(),
|
494 494 | method: value.method().to_string(),
|
495 495 | headers: value
|
496 496 | .headers()
|
497 497 | .iter()
|
498 498 | .map(|(k, v)| {
|
499 499 | (
|
500 500 | k.to_string(),
|