Accept any token to be a valid request method
- Rename read_until_space() to read_token_until_space() - Check if the byte is part of the token in read_token_until_space() - Return HttpMethodError if the token is empty - Remove the unnecessary is_valid_method() function
This commit is contained in:
52
src/http.rs
52
src/http.rs
@@ -296,13 +296,13 @@ pub fn is_token(b: u8) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Read bytes from `stream` into `buf` until a space is encountered.
|
||||
/// Read token bytes from `stream` into `buf` until a space is encountered.
|
||||
/// Returns `Ok(true)` if we read until a space,
|
||||
/// `Ok(false)` if we got to the end of `buf` without encountering a space,
|
||||
/// otherwise returns any error encountered reading the stream.
|
||||
///
|
||||
/// The remaining contents of `buf` are left untouched.
|
||||
fn read_until_space<R: Reader>(stream: &mut R, buf: &mut [u8]) -> HttpResult<bool> {
|
||||
fn read_token_until_space<R: Reader>(stream: &mut R, buf: &mut [u8]) -> HttpResult<bool> {
|
||||
use std::io::BufWriter;
|
||||
let mut bufwrt = BufWriter::new(buf);
|
||||
|
||||
@@ -310,13 +310,19 @@ fn read_until_space<R: Reader>(stream: &mut R, buf: &mut [u8]) -> HttpResult<boo
|
||||
let byte = try!(stream.read_byte());
|
||||
|
||||
if byte == SP {
|
||||
break
|
||||
break;
|
||||
} else if !is_token(byte) {
|
||||
return Err(HttpMethodError);
|
||||
// Read to end but there's still more
|
||||
} else if bufwrt.write_u8(byte).is_err() {
|
||||
return Ok(false)
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
if bufwrt.tell().unwrap() == 0 {
|
||||
return Err(HttpMethodError);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -326,7 +332,7 @@ fn read_until_space<R: Reader>(stream: &mut R, buf: &mut [u8]) -> HttpResult<boo
|
||||
pub fn read_method<R: Reader>(stream: &mut R) -> HttpResult<method::Method> {
|
||||
let mut buf = [SP, ..16];
|
||||
|
||||
if !try!(read_until_space(stream, &mut buf)) {
|
||||
if !try!(read_token_until_space(stream, &mut buf)) {
|
||||
return Err(HttpMethodError);
|
||||
}
|
||||
|
||||
@@ -349,20 +355,14 @@ pub fn read_method<R: Reader>(stream: &mut R) -> HttpResult<method::Method> {
|
||||
|
||||
match (maybe_method, buf[]) {
|
||||
(Some(method), _) => Ok(method),
|
||||
(None, ext) if is_valid_method(&buf) => {
|
||||
(None, ext) => {
|
||||
use std::str::raw;
|
||||
// We already checked that the buffer is ASCII
|
||||
Ok(method::Method::Extension(unsafe { raw::from_utf8(ext) }.trim().into_string()))
|
||||
},
|
||||
_ => Err(HttpMethodError)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_method(buf: &[u8]) -> bool {
|
||||
use std::char;
|
||||
buf.iter().all(|&ch| char::is_uppercase(ch as char) || ch == SP)
|
||||
}
|
||||
|
||||
/// Read a `RequestUri` from a raw stream.
|
||||
pub fn read_uri<R: Reader>(stream: &mut R) -> HttpResult<uri::RequestUri> {
|
||||
let mut b = try!(stream.read_byte());
|
||||
@@ -454,7 +454,7 @@ pub fn read_http_version<R: Reader>(stream: &mut R) -> HttpResult<HttpVersion> {
|
||||
/// The raw bytes when parsing a header line.
|
||||
///
|
||||
/// A String and Vec<u8>, divided by COLON (`:`). The String is guaranteed
|
||||
/// to be all `token`s. See `is_token_char` source for all valid characters.
|
||||
/// to be all `token`s. See `is_token` source for all valid characters.
|
||||
pub type RawHeaderLine = (String, Vec<u8>);
|
||||
|
||||
/// Read a RawHeaderLine from a Reader.
|
||||
@@ -620,7 +620,7 @@ mod tests {
|
||||
use status;
|
||||
use version::HttpVersion;
|
||||
use version::HttpVersion::{Http10, Http11, Http20};
|
||||
use HttpError::HttpVersionError;
|
||||
use HttpError::{HttpVersionError, HttpMethodError};
|
||||
use HttpResult;
|
||||
use url::Url;
|
||||
|
||||
@@ -632,19 +632,21 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_read_method() {
|
||||
fn read(s: &str, m: method::Method) {
|
||||
assert_eq!(read_method(&mut mem(s)), Ok(m));
|
||||
fn read(s: &str, result: HttpResult<method::Method>) {
|
||||
assert_eq!(read_method(&mut mem(s)), result);
|
||||
}
|
||||
|
||||
read("GET /", method::Method::Get);
|
||||
read("POST /", method::Method::Post);
|
||||
read("PUT /", method::Method::Put);
|
||||
read("HEAD /", method::Method::Head);
|
||||
read("OPTIONS /", method::Method::Options);
|
||||
read("CONNECT /", method::Method::Connect);
|
||||
read("TRACE /", method::Method::Trace);
|
||||
read("PATCH /", method::Method::Patch);
|
||||
read("FOO /", method::Method::Extension("FOO".to_string()));
|
||||
read("GET /", Ok(method::Method::Get));
|
||||
read("POST /", Ok(method::Method::Post));
|
||||
read("PUT /", Ok(method::Method::Put));
|
||||
read("HEAD /", Ok(method::Method::Head));
|
||||
read("OPTIONS /", Ok(method::Method::Options));
|
||||
read("CONNECT /", Ok(method::Method::Connect));
|
||||
read("TRACE /", Ok(method::Method::Trace));
|
||||
read("PATCH /", Ok(method::Method::Patch));
|
||||
read("FOO /", Ok(method::Method::Extension("FOO".to_string())));
|
||||
read("akemi!~#HOMURA /", Ok(method::Method::Extension("akemi!~#HOMURA".to_string())));
|
||||
read(" ", Err(HttpMethodError));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user