micro-http: added MethodNotAllow status code
When server returns `Method Not Allow` responses, it can attach to the response a HTTP `Allow` header. Added support for HTTP response `Allow` header as well. Signed-off-by: Iulian Barbu <iul@amazon.com> Signed-off-by: YUAN LYU <lyuyuan92@gmail.com>
This commit is contained in:
committed by
Adrian Catangiu
parent
530b36bfd9
commit
d37f9671af
@@ -142,7 +142,7 @@ impl Body {
|
||||
}
|
||||
|
||||
/// Supported HTTP Methods.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Method {
|
||||
/// GET Method.
|
||||
Get,
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
use std::io::{Error as WriteError, Write};
|
||||
|
||||
use crate::common::ascii::{COLON, CR, LF, SP};
|
||||
use crate::common::headers::{Header, MediaType};
|
||||
use crate::common::{Body, Version};
|
||||
use ascii::{COLON, CR, LF, SP};
|
||||
use common::{Body, Version};
|
||||
use headers::{Header, MediaType};
|
||||
use Method;
|
||||
|
||||
/// Wrapper over a response status code.
|
||||
///
|
||||
@@ -23,6 +24,8 @@ pub enum StatusCode {
|
||||
BadRequest,
|
||||
/// 404, Not Found
|
||||
NotFound,
|
||||
/// 405, Method Not Allowed
|
||||
MethodNotAllowed,
|
||||
/// 500, Internal Server Error
|
||||
InternalServerError,
|
||||
/// 501, Not Implemented
|
||||
@@ -40,6 +43,7 @@ impl StatusCode {
|
||||
Self::NoContent => b"204",
|
||||
Self::BadRequest => b"400",
|
||||
Self::NotFound => b"404",
|
||||
Self::MethodNotAllowed => b"405",
|
||||
Self::InternalServerError => b"500",
|
||||
Self::NotImplemented => b"501",
|
||||
Self::ServiceUnavailable => b"503",
|
||||
@@ -77,6 +81,7 @@ pub struct ResponseHeaders {
|
||||
content_length: i32,
|
||||
content_type: MediaType,
|
||||
server: String,
|
||||
allow: Vec<Method>,
|
||||
}
|
||||
|
||||
impl Default for ResponseHeaders {
|
||||
@@ -85,11 +90,31 @@ impl Default for ResponseHeaders {
|
||||
content_length: Default::default(),
|
||||
content_type: Default::default(),
|
||||
server: String::from("Firecracker API"),
|
||||
allow: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseHeaders {
|
||||
// The logic pertaining to `Allow` header writing.
|
||||
fn write_allow_header<T: Write>(&self, buf: &mut T) -> Result<(), WriteError> {
|
||||
if self.allow.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
buf.write_all(b"Allow: ")?;
|
||||
|
||||
let delimitator = b", ";
|
||||
for (idx, method) in self.allow.iter().enumerate() {
|
||||
buf.write_all(method.raw())?;
|
||||
if idx < self.allow.len() - 1 {
|
||||
buf.write_all(delimitator)?;
|
||||
}
|
||||
}
|
||||
|
||||
buf.write_all(&[CR, LF])
|
||||
}
|
||||
|
||||
/// Writes the headers to `buf` using the HTTP specification.
|
||||
pub fn write_all<T: Write>(&self, buf: &mut T) -> Result<(), WriteError> {
|
||||
buf.write_all(Header::Server.raw())?;
|
||||
@@ -100,6 +125,8 @@ impl ResponseHeaders {
|
||||
buf.write_all(b"Connection: keep-alive")?;
|
||||
buf.write_all(&[CR, LF])?;
|
||||
|
||||
self.write_allow_header(buf)?;
|
||||
|
||||
if self.content_length != 0 {
|
||||
buf.write_all(Header::ContentType.raw())?;
|
||||
buf.write_all(&[COLON, SP])?;
|
||||
@@ -172,6 +199,16 @@ impl Response {
|
||||
self.headers.set_server(server);
|
||||
}
|
||||
|
||||
/// Sets the HTTP allowed methods.
|
||||
pub fn set_allow(&mut self, methods: Vec<Method>) {
|
||||
self.headers.allow = methods;
|
||||
}
|
||||
|
||||
/// Allows a specific HTTP method.
|
||||
pub fn allow_method(&mut self, method: Method) {
|
||||
self.headers.allow.push(method);
|
||||
}
|
||||
|
||||
fn write_body<T: Write>(&self, mut buf: T) -> Result<(), WriteError> {
|
||||
if let Some(ref body) = self.body {
|
||||
buf.write_all(body.raw())?;
|
||||
@@ -216,6 +253,11 @@ impl Response {
|
||||
pub fn http_version(&self) -> Version {
|
||||
self.status_line.http_version
|
||||
}
|
||||
|
||||
/// Returns the allowed HTTP methods.
|
||||
pub fn allow(&self) -> Vec<Method> {
|
||||
self.headers.allow.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -246,6 +288,20 @@ mod tests {
|
||||
assert!(response.write_all(&mut response_buf.as_mut()).is_ok());
|
||||
assert!(response_buf.as_ref() == expected_response);
|
||||
|
||||
// Test response `Allow` header.
|
||||
let mut response = Response::new(Version::Http10, StatusCode::OK);
|
||||
let allowed_methods = vec![Method::Get, Method::Patch, Method::Put];
|
||||
response.set_allow(allowed_methods.clone());
|
||||
assert_eq!(response.allow(), allowed_methods);
|
||||
|
||||
let expected_response: &'static [u8] = b"HTTP/1.0 200 \r\n\
|
||||
Server: Firecracker API\r\n\
|
||||
Connection: keep-alive\r\n\
|
||||
Allow: GET, PATCH, PUT\r\n\r\n";
|
||||
let mut response_buf: [u8; 90] = [0; 90];
|
||||
assert!(response.write_all(&mut response_buf.as_mut()).is_ok());
|
||||
assert_eq!(response_buf.as_ref(), expected_response);
|
||||
|
||||
// Test write failed.
|
||||
let mut response_buf: [u8; 1] = [0; 1];
|
||||
assert!(response.write_all(&mut response_buf.as_mut()).is_err());
|
||||
@@ -288,8 +344,17 @@ mod tests {
|
||||
assert_eq!(StatusCode::NoContent.raw(), b"204");
|
||||
assert_eq!(StatusCode::BadRequest.raw(), b"400");
|
||||
assert_eq!(StatusCode::NotFound.raw(), b"404");
|
||||
assert_eq!(StatusCode::MethodNotAllowed.raw(), b"405");
|
||||
assert_eq!(StatusCode::InternalServerError.raw(), b"500");
|
||||
assert_eq!(StatusCode::NotImplemented.raw(), b"501");
|
||||
assert_eq!(StatusCode::ServiceUnavailable.raw(), b"503");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_allow_method() {
|
||||
let mut response = Response::new(Version::Http10, StatusCode::MethodNotAllowed);
|
||||
response.allow_method(Method::Get);
|
||||
response.allow_method(Method::Put);
|
||||
assert_eq!(response.allow(), vec![Method::Get, Method::Put]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user