use super::*;
#[cfg(test)]
mod test {
use super::{Request, Response, Status, EMPTY_HEADER, shrink, parse_chunk_size};
const NUM_OF_HEADERS: usize = 4;
#[test]
fn test_shrink() {
let mut arr = [EMPTY_HEADER; 16];
{
let slice = &mut &mut arr[..];
assert_eq!(slice.len(), 16);
shrink(slice, 4);
assert_eq!(slice.len(), 4);
}
assert_eq!(arr.len(), 16);
}
macro_rules! req {
($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
req! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
);
($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => (
#[test]
fn $name() {
let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
let mut req = Request::new(&mut headers[..]);
let status = req.parse($buf.as_ref());
assert_eq!(status, $len);
closure(req);
fn closure($arg: Request) {
$body
}
}
)
}
req! {
test_request_simple,
b"OPTIONS / ICAP/1.0\r\nEncapsulated:null-body=0\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "OPTIONS");
assert_eq!(req.path.unwrap(), "/");
assert_eq!(req.version.unwrap(), 1);
assert_eq!(req.headers.len(), 1);
}
}
req! {
test_icap_options,
b"OPTIONS icap://example.local/service ICAP/1.0\r\nHost: example.local\r\nUser-Agent: Example-ICAP-Client-Library/2.0\r\nEncapsulated:null-body=0\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "OPTIONS");
assert_eq!(req.path.unwrap(), "icap://example.local/service");
assert_eq!(req.headers.len(), 3);
assert_eq!(req.headers[0].name, "Host");
assert_eq!(req.headers[0].value, b"example.local");
assert_eq!(req.headers[1].name, "User-Agent");
assert_eq!(req.headers[1].value, b"Example-ICAP-Client-Library/2.0");
}
}
req! {
test_basic_respmod,
b"RESPMOD / ICAP/1.0\r\nEncapsulated: null-body=0\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "RESPMOD");
}
}
req! {
test_full_respmod,
b"RESPMOD icap://icap.example.org/satisf ICAP/1.0\r
Host: icap.example.org\r
Encapsulated: req-hdr=0, res-hdr=137, res-body=296\r
\r
GET /origin-resource HTTP/1.1\r
Host: www.origin-server.com\r
Accept: text/html, text/plain, image/gif\r
Accept-Encoding: gzip, compress\r
\r
HTTP/1.1 200 OK\r
Date: Mon, 10 Jan 2000 09:52:22 GMT\r
Server: Apache/1.3.6 (Unix)\r
ETag: \"63840-1ab7-378d415b\"\r
Content-Type: text/html\r
Content-Length: 51\r
\r
33\r
This is data that was returned by an origin server.\r
0\r
\r
",
|req| {
use SectionType::RequestHeader;
assert_eq!(req.method.unwrap(), "RESPMOD");
let sections = req.encapsulated_sections.unwrap();
assert_eq!(sections[&RequestHeader], b"GET /origin-resource HTTP/1.1\r
Host: www.origin-server.com\r
Accept: text/html, text/plain, image/gif\r
Accept-Encoding: gzip, compress\r
\r
".to_vec());
}
}
req! {
test_request_headers_max,
b"RESPMOD / ICAP/1.0\r\nA: A\r\nB: B\r\nC: C\r\nEncapsulated:null-body=0\r\n\r\n",
|req| {
assert_eq!(req.headers.len(), NUM_OF_HEADERS);
}
}
req! {
test_request_multibyte,
b"RESPMOD / ICAP/1.0\r\nHost: foo.com\r\nUser-Agent: \xe3\x81\xb2\xe3/1.0\r\nEncapsulated:null-body=0\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "RESPMOD");
assert_eq!(req.path.unwrap(), "/");
assert_eq!(req.version.unwrap(), 1);
assert_eq!(req.headers[0].name, "Host");
assert_eq!(req.headers[0].value, b"foo.com");
assert_eq!(req.headers[1].name, "User-Agent");
assert_eq!(req.headers[1].value, b"\xe3\x81\xb2\xe3/1.0");
}
}
req! {
test_request_partial,
b"RESPMOD / ICAP/1.0\r\n\r", Ok(Status::Partial),
|_req| {}
}
req! {
test_request_newlines,
b"RESPMOD / ICAP/1.0\nHost: foo.bar\nEncapsulated:null-body=0\n\n",
|_r| {}
}
req! {
test_request_empty_lines_prefix,
b"\r\n\r\nRESPMOD / ICAP/1.0\r\nEncapsulated:null-body=0\r\n\r\n",
|req| {
assert_eq!(req.method.unwrap(), "RESPMOD");
assert_eq!(req.path.unwrap(), "/");
assert_eq!(req.version.unwrap(), 1);
assert_eq!(req.headers.len(), 1);
}
}
req! {
test_request_with_invalid_token_delimiter,
b"RESPMOD\n/ ICAP/1.0\r\nHost: foo.bar\r\n\r\n",
Err(::Error::Token),
|_r| {}
}
macro_rules! res {
($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
);
($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => (
#[test]
fn $name() {
let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
let mut res = Response::new(&mut headers[..]);
let status = res.parse($buf.as_ref());
assert_eq!(status, $len);
closure(res);
fn closure($arg: Response) {
$body
}
}
)
}
res! {
test_response_simple,
b"ICAP/1.0 200 OK\r\n\r\n",
|res| {
assert_eq!(res.version.unwrap(), 1);
assert_eq!(res.code.unwrap(), 200);
assert_eq!(res.reason.unwrap(), "OK");
}
}
res! {
test_response_newlines,
b"ICAP/1.0 403 Forbidden\nServer: foo.bar\n\n",
|_r| {}
}
res! {
test_response_reason_missing,
b"ICAP/1.0 200 \r\n\r\n",
|res| {
assert_eq!(res.version.unwrap(), 1);
assert_eq!(res.code.unwrap(), 200);
assert_eq!(res.reason.unwrap(), "");
}
}
res! {
test_response_reason_missing_no_space,
b"ICAP/1.0 200\r\n\r\n",
|res| {
assert_eq!(res.version.unwrap(), 1);
assert_eq!(res.code.unwrap(), 200);
assert_eq!(res.reason.unwrap(), "");
}
}
res! {
test_response_reason_with_space_and_tab,
b"ICAP/1.0 101 Switching Protocols\t\r\n\r\n",
|res| {
assert_eq!(res.version.unwrap(), 1);
assert_eq!(res.code.unwrap(), 101);
assert_eq!(res.reason.unwrap(), "Switching Protocols\t");
}
}
static RESPONSE_REASON_WITH_OBS_TEXT_BYTE: &'static [u8] = b"ICAP/1.0 200 X\xFFZ\r\n\r\n";
res! {
test_response_reason_with_obsolete_text_byte,
RESPONSE_REASON_WITH_OBS_TEXT_BYTE,
Err(::Error::Status),
|_res| {}
}
res! {
test_response_reason_with_nul_byte,
b"ICAP/1.0 200 \x00\r\n\r\n",
Err(::Error::Status),
|_res| {}
}
res! {
test_response_version_missing_space,
b"ICAP/1.0",
Ok(Status::Partial),
|_res| {}
}
res! {
test_response_code_missing_space,
b"ICAP/1.0 200",
Ok(Status::Partial),
|_res| {}
}
res! {
test_response_empty_lines_prefix_lf_only,
b"\n\nICAP/1.0 200 OK\n\n",
|_res| {}
}
#[test]
fn test_chunk_size() {
assert_eq!(parse_chunk_size(b"0\r\n"), Ok(Status::Complete((3, 0))));
assert_eq!(parse_chunk_size(b"12\r\nchunk"), Ok(Status::Complete((4, 18))));
assert_eq!(parse_chunk_size(b"3086d\r\n"), Ok(Status::Complete((7, 198765))));
assert_eq!(parse_chunk_size(b"3735AB1;foo bar*\r\n"), Ok(Status::Complete((18, 57891505))));
assert_eq!(parse_chunk_size(b"3735ab1 ; baz \r\n"), Ok(Status::Complete((16, 57891505))));
assert_eq!(parse_chunk_size(b"77a65\r"), Ok(Status::Partial));
assert_eq!(parse_chunk_size(b"ab"), Ok(Status::Partial));
assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(::InvalidChunkSize));
assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(::InvalidChunkSize));
assert_eq!(parse_chunk_size(b"567xf8a\r\n"), Err(::InvalidChunkSize));
assert_eq!(parse_chunk_size(b"ffffffffffffffff\r\n"), Ok(Status::Complete((18, ::core::u64::MAX))));
assert_eq!(parse_chunk_size(b"1ffffffffffffffff\r\n"), Err(::InvalidChunkSize));
assert_eq!(parse_chunk_size(b"Affffffffffffffff\r\n"), Err(::InvalidChunkSize));
assert_eq!(parse_chunk_size(b"fffffffffffffffff\r\n"), Err(::InvalidChunkSize));
}
#[cfg(feature = "std")]
#[test]
fn test_std_error() {
use super::Error;
use std::error::Error as StdError;
let err = Error::HeaderName;
assert_eq!(err.to_string(), err.description());
}
}