@@ -17,11 +17,13 @@ use micro_http::{
17
17
Body , HttpHeaderError , MediaType , Method , Request , RequestError , Response , StatusCode , Version ,
18
18
} ;
19
19
use serde_json:: { Map , Value } ;
20
- use token_headers:: TokenHeaders ;
21
20
22
21
use crate :: mmds:: data_store:: { Mmds , MmdsDatastoreError as MmdsError , MmdsVersion , OutputFormat } ;
23
22
use crate :: mmds:: token:: PATH_TO_TOKEN ;
24
- use crate :: mmds:: token_headers:: REJECTED_HEADER ;
23
+ use crate :: mmds:: token_headers:: {
24
+ REJECTED_HEADER , X_METADATA_TOKEN_HEADER , X_METADATA_TOKEN_TTL_SECONDS_HEADER ,
25
+ get_header_value_pair,
26
+ } ;
25
27
26
28
#[ rustfmt:: skip]
27
29
#[ derive( Debug , thiserror:: Error , displaydoc:: Display ) ]
@@ -142,23 +144,10 @@ fn respond_to_request_mmdsv1(mmds: &Mmds, request: Request) -> Response {
142
144
}
143
145
144
146
fn respond_to_request_mmdsv2 ( mmds : & mut Mmds , request : Request ) -> Response {
145
- // Fetch custom headers from request.
146
- let token_headers = match TokenHeaders :: try_from ( request. headers . custom_entries ( ) ) {
147
- Ok ( token_headers) => token_headers,
148
- Err ( err) => {
149
- return build_response (
150
- request. http_version ( ) ,
151
- StatusCode :: BadRequest ,
152
- MediaType :: PlainText ,
153
- Body :: new ( err. to_string ( ) ) ,
154
- ) ;
155
- }
156
- } ;
157
-
158
147
// Allow only GET and PUT requests.
159
148
match request. method ( ) {
160
- Method :: Get => respond_to_get_request_checked ( mmds, request, token_headers ) ,
161
- Method :: Put => respond_to_put_request ( mmds, request, token_headers ) ,
149
+ Method :: Get => respond_to_get_request_checked ( mmds, request) ,
150
+ Method :: Put => respond_to_put_request ( mmds, request) ,
162
151
_ => {
163
152
let mut response = build_response (
164
153
request. http_version ( ) ,
@@ -173,26 +162,23 @@ fn respond_to_request_mmdsv2(mmds: &mut Mmds, request: Request) -> Response {
173
162
}
174
163
}
175
164
176
- fn respond_to_get_request_checked (
177
- mmds : & Mmds ,
178
- request : Request ,
179
- token_headers : TokenHeaders ,
180
- ) -> Response {
181
- // Get MMDS token from custom headers.
182
- let token = match token_headers. x_metadata_token ( ) {
183
- Some ( token) => token,
184
- None => {
185
- let error_msg = VmmMmdsError :: NoTokenProvided . to_string ( ) ;
186
- return build_response (
187
- request. http_version ( ) ,
188
- StatusCode :: Unauthorized ,
189
- MediaType :: PlainText ,
190
- Body :: new ( error_msg) ,
191
- ) ;
192
- }
193
- } ;
165
+ fn respond_to_get_request_checked ( mmds : & Mmds , request : Request ) -> Response {
166
+ // Check whether a token exists.
167
+ let token =
168
+ match get_header_value_pair ( request. headers . custom_entries ( ) , X_METADATA_TOKEN_HEADER ) {
169
+ Some ( ( _, token) ) => token,
170
+ None => {
171
+ let error_msg = VmmMmdsError :: NoTokenProvided . to_string ( ) ;
172
+ return build_response (
173
+ request. http_version ( ) ,
174
+ StatusCode :: Unauthorized ,
175
+ MediaType :: PlainText ,
176
+ Body :: new ( error_msg) ,
177
+ ) ;
178
+ }
179
+ } ;
194
180
195
- // Validate MMDS token.
181
+ // Validate the token.
196
182
match mmds. is_valid_token ( token) {
197
183
Ok ( true ) => respond_to_get_request_unchecked ( mmds, request) ,
198
184
Ok ( false ) => build_response (
@@ -248,17 +234,11 @@ fn respond_to_get_request_unchecked(mmds: &Mmds, request: Request) -> Response {
248
234
}
249
235
}
250
236
251
- fn respond_to_put_request (
252
- mmds : & mut Mmds ,
253
- request : Request ,
254
- token_headers : TokenHeaders ,
255
- ) -> Response {
237
+ fn respond_to_put_request ( mmds : & mut Mmds , request : Request ) -> Response {
238
+ let custom_headers = request. headers . custom_entries ( ) ;
239
+
256
240
// Reject `PUT` requests that contain `X-Forwarded-For` header.
257
- if request
258
- . headers
259
- . custom_entries ( )
260
- . contains_key ( REJECTED_HEADER )
261
- {
241
+ if custom_headers. contains_key ( REJECTED_HEADER ) {
262
242
let error_msg = RequestError :: HeaderError ( HttpHeaderError :: UnsupportedName (
263
243
REJECTED_HEADER . to_string ( ) ,
264
244
) )
@@ -287,17 +267,36 @@ fn respond_to_put_request(
287
267
}
288
268
289
269
// Get token lifetime value.
290
- let ttl_seconds = match token_headers. x_metadata_token_ttl_seconds ( ) {
291
- Some ( ttl_seconds) => ttl_seconds,
292
- None => {
293
- return build_response (
294
- request. http_version ( ) ,
295
- StatusCode :: BadRequest ,
296
- MediaType :: PlainText ,
297
- Body :: new ( VmmMmdsError :: NoTtlProvided . to_string ( ) ) ,
298
- ) ;
299
- }
300
- } ;
270
+ let ttl_seconds =
271
+ match get_header_value_pair ( custom_headers, X_METADATA_TOKEN_TTL_SECONDS_HEADER ) {
272
+ // Header found
273
+ Some ( ( k, v) ) => match v. parse :: < u32 > ( ) {
274
+ Ok ( ttl_seconds) => ttl_seconds,
275
+ Err ( _) => {
276
+ return build_response (
277
+ request. http_version ( ) ,
278
+ StatusCode :: BadRequest ,
279
+ MediaType :: PlainText ,
280
+ Body :: new (
281
+ RequestError :: HeaderError ( HttpHeaderError :: InvalidValue (
282
+ k. into ( ) ,
283
+ v. into ( ) ,
284
+ ) )
285
+ . to_string ( ) ,
286
+ ) ,
287
+ ) ;
288
+ }
289
+ } ,
290
+ // Header not found
291
+ None => {
292
+ return build_response (
293
+ request. http_version ( ) ,
294
+ StatusCode :: BadRequest ,
295
+ MediaType :: PlainText ,
296
+ Body :: new ( VmmMmdsError :: NoTtlProvided . to_string ( ) ) ,
297
+ ) ;
298
+ }
299
+ } ;
301
300
302
301
// Generate token.
303
302
let result = mmds. generate_token ( ttl_seconds) ;
@@ -530,7 +529,7 @@ mod tests {
530
529
let actual_response = convert_to_response ( mmds. clone ( ) , request) ;
531
530
assert_eq ! ( actual_response, expected_response) ;
532
531
533
- // Test invalid custom header value is ignored when V1 is configured .
532
+ // Test invalid custom header value is ignored if not PUT request to /latest/api/token .
534
533
let ( request, expected_response) = generate_request_and_expected_response (
535
534
b"GET http://169.254.169.254/ HTTP/1.0\r \n \
536
535
Accept: application/json\r \n \
@@ -576,23 +575,6 @@ mod tests {
576
575
let actual_response = convert_to_response ( mmds. clone ( ) , request) ;
577
576
assert_eq ! ( actual_response, expected_response) ;
578
577
579
- // Test invalid value for custom header.
580
- let request = Request :: try_from (
581
- b"GET http://169.254.169.254/ HTTP/1.0\r \n \
582
- Accept: application/json\r \n \
583
- X-metadata-token-ttl-seconds: -60\r \n \r \n ",
584
- None ,
585
- )
586
- . unwrap ( ) ;
587
- let mut expected_response = Response :: new ( Version :: Http10 , StatusCode :: BadRequest ) ;
588
- expected_response. set_content_type ( MediaType :: PlainText ) ;
589
- expected_response. set_body ( Body :: new (
590
- "Invalid header. Reason: Invalid value. Key:X-metadata-token-ttl-seconds; Value:-60"
591
- . to_string ( ) ,
592
- ) ) ;
593
- let actual_response = convert_to_response ( mmds. clone ( ) , request) ;
594
- assert_eq ! ( actual_response, expected_response) ;
595
-
596
578
// Test PUT requests.
597
579
// Unsupported `X-Forwarded-For` header present.
598
580
let request = Request :: try_from (
@@ -624,6 +606,22 @@ mod tests {
624
606
let actual_response = convert_to_response ( mmds. clone ( ) , request) ;
625
607
assert_eq ! ( actual_response, expected_response) ;
626
608
609
+ // Test invalid X-metadata-token-ttl-seconds value gets BadRequest.
610
+ let request = Request :: try_from (
611
+ b"PUT http://169.254.169.254/latest/api/token HTTP/1.0\r \n \
612
+ X-metadata-token-ttl-seconds: -60\r \n \r \n ",
613
+ None ,
614
+ )
615
+ . unwrap ( ) ;
616
+ let mut expected_response = Response :: new ( Version :: Http10 , StatusCode :: BadRequest ) ;
617
+ expected_response. set_content_type ( MediaType :: PlainText ) ;
618
+ expected_response. set_body ( Body :: new (
619
+ "Invalid header. Reason: Invalid value. Key:X-metadata-token-ttl-seconds; Value:-60"
620
+ . to_string ( ) ,
621
+ ) ) ;
622
+ let actual_response = convert_to_response ( mmds. clone ( ) , request) ;
623
+ assert_eq ! ( actual_response, expected_response) ;
624
+
627
625
// Test invalid lifetime values for token.
628
626
let invalid_values = [ MIN_TOKEN_TTL_SECONDS - 1 , MAX_TOKEN_TTL_SECONDS + 1 ] ;
629
627
for invalid_value in invalid_values. iter ( ) {
@@ -687,6 +685,21 @@ mod tests {
687
685
let actual_response = convert_to_response ( mmds. clone ( ) , request) ;
688
686
assert_eq ! ( actual_response, expected_response) ;
689
687
688
+ // Test invalid customer header value is ignored if not PUT request to /latest/api/token.
689
+ #[ rustfmt:: skip]
690
+ let ( request, expected_response) = generate_request_and_expected_response (
691
+ format ! (
692
+ "GET http://169.254.169.254/ HTTP/1.0\r \n \
693
+ Accept: application/json\r \n \
694
+ X-metadata-token: {valid_token}\r \n \
695
+ X-metadata-token-ttl-seconds: -60\r \n \r \n ",
696
+ )
697
+ . as_bytes ( ) ,
698
+ MediaType :: ApplicationJson ,
699
+ ) ;
700
+ let actual_response = convert_to_response ( mmds. clone ( ) , request) ;
701
+ assert_eq ! ( actual_response, expected_response) ;
702
+
690
703
// Test GET request towards unsupported value type.
691
704
#[ rustfmt:: skip]
692
705
let request = Request :: try_from (
0 commit comments