3
3
4
4
use std:: io:: { Error as WriteError , Write } ;
5
5
6
- use crate :: common:: ascii:: { COLON , CR , LF , SP } ;
7
- use crate :: common:: headers:: { Header , MediaType } ;
8
- use crate :: common:: { Body , Version } ;
6
+ use ascii:: { COLON , CR , LF , SP } ;
7
+ use common:: { Body , Version } ;
8
+ use headers:: { Header , MediaType } ;
9
+ use Method ;
9
10
10
11
/// Wrapper over a response status code.
11
12
///
@@ -23,6 +24,8 @@ pub enum StatusCode {
23
24
BadRequest ,
24
25
/// 404, Not Found
25
26
NotFound ,
27
+ /// 405, Method Not Allowed
28
+ MethodNotAllowed ,
26
29
/// 500, Internal Server Error
27
30
InternalServerError ,
28
31
/// 501, Not Implemented
@@ -40,6 +43,7 @@ impl StatusCode {
40
43
Self :: NoContent => b"204" ,
41
44
Self :: BadRequest => b"400" ,
42
45
Self :: NotFound => b"404" ,
46
+ Self :: MethodNotAllowed => b"405" ,
43
47
Self :: InternalServerError => b"500" ,
44
48
Self :: NotImplemented => b"501" ,
45
49
Self :: ServiceUnavailable => b"503" ,
@@ -77,6 +81,7 @@ pub struct ResponseHeaders {
77
81
content_length : i32 ,
78
82
content_type : MediaType ,
79
83
server : String ,
84
+ allow : Vec < Method > ,
80
85
}
81
86
82
87
impl Default for ResponseHeaders {
@@ -85,11 +90,31 @@ impl Default for ResponseHeaders {
85
90
content_length : Default :: default ( ) ,
86
91
content_type : Default :: default ( ) ,
87
92
server : String :: from ( "Firecracker API" ) ,
93
+ allow : Vec :: new ( ) ,
88
94
}
89
95
}
90
96
}
91
97
92
98
impl ResponseHeaders {
99
+ // The logic pertaining to `Allow` header writing.
100
+ fn write_allow_header < T : Write > ( & self , buf : & mut T ) -> Result < ( ) , WriteError > {
101
+ if self . allow . is_empty ( ) {
102
+ return Ok ( ( ) ) ;
103
+ }
104
+
105
+ buf. write_all ( b"Allow: " ) ?;
106
+
107
+ let delimitator = b", " ;
108
+ for ( idx, method) in self . allow . iter ( ) . enumerate ( ) {
109
+ buf. write_all ( method. raw ( ) ) ?;
110
+ if idx < self . allow . len ( ) - 1 {
111
+ buf. write_all ( delimitator) ?;
112
+ }
113
+ }
114
+
115
+ buf. write_all ( & [ CR , LF ] )
116
+ }
117
+
93
118
/// Writes the headers to `buf` using the HTTP specification.
94
119
pub fn write_all < T : Write > ( & self , buf : & mut T ) -> Result < ( ) , WriteError > {
95
120
buf. write_all ( Header :: Server . raw ( ) ) ?;
@@ -100,6 +125,8 @@ impl ResponseHeaders {
100
125
buf. write_all ( b"Connection: keep-alive" ) ?;
101
126
buf. write_all ( & [ CR , LF ] ) ?;
102
127
128
+ self . write_allow_header ( buf) ?;
129
+
103
130
if self . content_length != 0 {
104
131
buf. write_all ( Header :: ContentType . raw ( ) ) ?;
105
132
buf. write_all ( & [ COLON , SP ] ) ?;
@@ -172,6 +199,16 @@ impl Response {
172
199
self . headers . set_server ( server) ;
173
200
}
174
201
202
+ /// Sets the HTTP allowed methods.
203
+ pub fn set_allow ( & mut self , methods : Vec < Method > ) {
204
+ self . headers . allow = methods;
205
+ }
206
+
207
+ /// Allows a specific HTTP method.
208
+ pub fn allow_method ( & mut self , method : Method ) {
209
+ self . headers . allow . push ( method) ;
210
+ }
211
+
175
212
fn write_body < T : Write > ( & self , mut buf : T ) -> Result < ( ) , WriteError > {
176
213
if let Some ( ref body) = self . body {
177
214
buf. write_all ( body. raw ( ) ) ?;
@@ -216,6 +253,11 @@ impl Response {
216
253
pub fn http_version ( & self ) -> Version {
217
254
self . status_line . http_version
218
255
}
256
+
257
+ /// Returns the allowed HTTP methods.
258
+ pub fn allow ( & self ) -> Vec < Method > {
259
+ self . headers . allow . clone ( )
260
+ }
219
261
}
220
262
221
263
#[ cfg( test) ]
@@ -246,6 +288,20 @@ mod tests {
246
288
assert ! ( response. write_all( & mut response_buf. as_mut( ) ) . is_ok( ) ) ;
247
289
assert ! ( response_buf. as_ref( ) == expected_response) ;
248
290
291
+ // Test response `Allow` header.
292
+ let mut response = Response :: new ( Version :: Http10 , StatusCode :: OK ) ;
293
+ let allowed_methods = vec ! [ Method :: Get , Method :: Patch , Method :: Put ] ;
294
+ response. set_allow ( allowed_methods. clone ( ) ) ;
295
+ assert_eq ! ( response. allow( ) , allowed_methods) ;
296
+
297
+ let expected_response: & ' static [ u8 ] = b"HTTP/1.0 200 \r \n \
298
+ Server: Firecracker API\r \n \
299
+ Connection: keep-alive\r \n \
300
+ Allow: GET, PATCH, PUT\r \n \r \n ";
301
+ let mut response_buf: [ u8 ; 90 ] = [ 0 ; 90 ] ;
302
+ assert ! ( response. write_all( & mut response_buf. as_mut( ) ) . is_ok( ) ) ;
303
+ assert_eq ! ( response_buf. as_ref( ) , expected_response) ;
304
+
249
305
// Test write failed.
250
306
let mut response_buf: [ u8 ; 1 ] = [ 0 ; 1 ] ;
251
307
assert ! ( response. write_all( & mut response_buf. as_mut( ) ) . is_err( ) ) ;
@@ -288,8 +344,17 @@ mod tests {
288
344
assert_eq ! ( StatusCode :: NoContent . raw( ) , b"204" ) ;
289
345
assert_eq ! ( StatusCode :: BadRequest . raw( ) , b"400" ) ;
290
346
assert_eq ! ( StatusCode :: NotFound . raw( ) , b"404" ) ;
347
+ assert_eq ! ( StatusCode :: MethodNotAllowed . raw( ) , b"405" ) ;
291
348
assert_eq ! ( StatusCode :: InternalServerError . raw( ) , b"500" ) ;
292
349
assert_eq ! ( StatusCode :: NotImplemented . raw( ) , b"501" ) ;
293
350
assert_eq ! ( StatusCode :: ServiceUnavailable . raw( ) , b"503" ) ;
294
351
}
352
+
353
+ #[ test]
354
+ fn test_allow_method ( ) {
355
+ let mut response = Response :: new ( Version :: Http10 , StatusCode :: MethodNotAllowed ) ;
356
+ response. allow_method ( Method :: Get ) ;
357
+ response. allow_method ( Method :: Put ) ;
358
+ assert_eq ! ( response. allow( ) , vec![ Method :: Get , Method :: Put ] ) ;
359
+ }
295
360
}
0 commit comments