in src/mmds/src/lib.rs [469:654]
fn test_respond_to_request_mmdsv2() {
// Populate MMDS with data.
let mmds = populate_mmds();
// Set version to V2.
mmds.lock()
.expect("Poisoned lock")
.set_version(MmdsVersion::V2)
.unwrap();
assert_eq!(
mmds.lock().expect("Poisoned lock").version(),
MmdsVersion::V2
);
// Test not allowed PATCH HTTP Method.
let request_bytes = b"PATCH http://169.254.169.255/ HTTP/1.0\r\n\r\n";
let request = Request::try_from(request_bytes, None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::MethodNotAllowed);
expected_response.set_body(Body::new(Error::MethodNotAllowed.to_string()));
expected_response.allow_method(Method::Get);
expected_response.allow_method(Method::Put);
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Test invalid value for custom header.
let request_bytes = b"GET http://169.254.169.254/ HTTP/1.0\r\n\
Accept: application/json\r\n
X-metadata-token-ttl-seconds: application/json\r\n\r\n";
let request = Request::try_from(request_bytes, None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::BadRequest);
expected_response.set_body(Body::new(
"Invalid header. Reason: Invalid value. \
Key:X-metadata-token-ttl-seconds; Value:application/json"
.to_string(),
));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Test PUT requests.
// Unsupported `X-Forwarded-For` header present.
let request_bytes = b"PUT http://169.254.169.254/latest/api/token HTTP/1.0\r\n\
X-Forwarded-For: 203.0.113.195\r\n\r\n";
let request = Request::try_from(request_bytes, None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::BadRequest);
expected_response.set_body(Body::new(
"Invalid header. Reason: Unsupported header name. Key: X-Forwarded-For".to_string(),
));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Test invalid path.
let request_bytes = b"PUT http://169.254.169.254/token HTTP/1.0\r\n\
X-metadata-token-ttl-seconds: 60\r\n\r\n";
let request = Request::try_from(request_bytes, None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::NotFound);
expected_response.set_body(Body::new(
Error::ResourceNotFound(String::from("/token")).to_string(),
));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Test invalid lifetime values for token.
let invalid_values = [MIN_TOKEN_TTL_SECONDS - 1, MAX_TOKEN_TTL_SECONDS + 1];
for invalid_value in invalid_values.iter() {
let request_bytes = format!(
"PUT http://169.254.169.254/latest/api/token HTTP/1.0\r\n\
X-metadata-token-ttl-seconds: {}\r\n\r\n",
invalid_value
);
let request = Request::try_from(request_bytes.as_bytes(), None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::BadRequest);
let error_msg = format!(
"Invalid time to live value provided for token: {}. \
Please provide a value between {} and {}.",
invalid_value, MIN_TOKEN_TTL_SECONDS, MAX_TOKEN_TTL_SECONDS
);
expected_response.set_body(Body::new(error_msg));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
}
// Test no lifetime value provided for token.
let request_bytes = b"PUT http://169.254.169.254/latest/api/token HTTP/1.0\r\n\r\n";
let request = Request::try_from(request_bytes, None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::BadRequest);
expected_response.set_body(Body::new(Error::NoTtlProvided.to_string()));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Test valid PUT.
let request_bytes = b"PUT http://169.254.169.254/latest/api/token HTTP/1.0\r\n\
X-metadata-token-ttl-seconds: 60\r\n\r\n";
let request = Request::try_from(request_bytes, None).unwrap();
let actual_response = convert_to_response(request);
assert_eq!(actual_response.status(), StatusCode::OK);
assert_eq!(actual_response.content_type(), MediaType::PlainText);
// Test valid GET.
let valid_token = String::from_utf8(actual_response.body().unwrap().body).unwrap();
let request_bytes = format!(
"GET http://169.254.169.254/ HTTP/1.0\r\n\
Accept: application/json\r\n\
X-metadata-token: {}\r\n\r\n",
valid_token
);
let request = Request::try_from(request_bytes.as_bytes(), None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::OK);
let mut body = get_json_data().to_string();
body.retain(|c| !c.is_whitespace());
expected_response.set_body(Body::new(body));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Test GET request towards unsupported value type.
let request_bytes = format!(
"GET /age HTTP/1.1\r\n\
X-metadata-token: {}\r\n\r\n",
valid_token
);
let request = Request::try_from(request_bytes.as_bytes(), None).unwrap();
let mut expected_response = Response::new(Version::Http11, StatusCode::NotImplemented);
let body = "Cannot retrieve value. The value has an unsupported type.".to_string();
expected_response.set_body(Body::new(body));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Test GET request towards invalid resource.
let request_bytes = format!(
"GET http://169.254.169.254/invalid HTTP/1.0\r\n\
X-metadata-token: {}\r\n\r\n",
valid_token
);
let request = Request::try_from(request_bytes.as_bytes(), None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::NotFound);
expected_response.set_body(Body::new(
Error::ResourceNotFound(String::from("/invalid")).to_string(),
));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Test GET request without token should return Unauthorized status code.
let request_bytes = b"GET http://169.254.169.254/ HTTP/1.0\r\n\r\n";
let request = Request::try_from(request_bytes, None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::Unauthorized);
expected_response.set_body(Body::new(Error::NoTokenProvided.to_string()));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Test GET request with invalid token should return Unauthorized status code.
let request_bytes = b"GET http://169.254.169.254/ HTTP/1.0\r\n\
X-metadata-token: foo\r\n\r\n";
let request = Request::try_from(request_bytes, None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::Unauthorized);
expected_response.set_body(Body::new(Error::InvalidToken.to_string()));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Create a new MMDS token that expires in one second.
let request_bytes = b"PUT http://169.254.169.254/latest/api/token HTTP/1.0\r\n\
X-metadata-token-ttl-seconds: 1\r\n\r\n";
let request = Request::try_from(request_bytes, None).unwrap();
let actual_response = convert_to_response(request);
assert_eq!(actual_response.status(), StatusCode::OK);
assert_eq!(actual_response.content_type(), MediaType::PlainText);
// Test GET request with invalid tokens.
// `valid_token` will become invalid after one second, when it expires.
let valid_token = String::from_utf8(actual_response.body().unwrap().body).unwrap();
let invalid_token = std::iter::repeat("a").take(58).collect::<String>();
let tokens = [invalid_token, valid_token];
for token in tokens.iter() {
let request_bytes = format!(
"GET http://169.254.169.254/ HTTP/1.0\r\n\
X-metadata-token: {}\r\n\r\n",
token
);
let request = Request::try_from(request_bytes.as_bytes(), None).unwrap();
let mut expected_response = Response::new(Version::Http10, StatusCode::Unauthorized);
expected_response.set_body(Body::new(Error::InvalidToken.to_string()));
let actual_response = convert_to_response(request);
assert_eq!(actual_response, expected_response);
// Wait for the second token to expire.
std::thread::sleep(Duration::from_secs(1));
}
}