handshake: add the ability to iterate over headers.

pull/7/head
Alexey Galakhov 8 years ago
parent d27f768599
commit e6b658d94f
  1. 58
      src/handshake/mod.rs

@ -5,6 +5,7 @@ pub mod tls;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::str::from_utf8; use std::str::from_utf8;
use std::slice;
use base64; use base64;
use bytes::Buf; use bytes::Buf;
@ -76,9 +77,15 @@ impl Headers {
/// Get first header with the given name, if any. /// Get first header with the given name, if any.
pub fn find_first(&self, name: &str) -> Option<&[u8]> { pub fn find_first(&self, name: &str) -> Option<&[u8]> {
self.data.iter() self.find(name).next()
.find(|&&(ref n, _)| n.eq_ignore_ascii_case(name)) }
.map(|&(_, ref v)| v.as_ref())
/// Iterate over all headers with the given name.
pub fn find<'headers, 'name>(&'headers self, name: &'name str) -> HeadersIter<'name, 'headers> {
HeadersIter {
name: name,
iter: self.data.iter()
}
} }
/// Check if the given header has the given value. /// Check if the given header has the given value.
@ -103,6 +110,25 @@ impl Headers {
} }
/// The iterator over headers.
pub struct HeadersIter<'name, 'headers> {
name: &'name str,
iter: slice::Iter<'headers, (String, Box<[u8]>)>,
}
impl<'name, 'headers> Iterator for HeadersIter<'name, 'headers> {
type Item = &'headers [u8];
fn next(&mut self) -> Option<Self::Item> {
while let Some(&(ref name, ref value)) = self.iter.next() {
if name.eq_ignore_ascii_case(self.name) {
return Some(value)
}
}
None
}
}
/// Trait to read HTTP parseable objects. /// Trait to read HTTP parseable objects.
trait Httparse: Sized { trait Httparse: Sized {
fn httparse(buf: &[u8]) -> Result<Option<(usize, Self)>>; fn httparse(buf: &[u8]) -> Result<Option<(usize, Self)>>;
@ -159,7 +185,10 @@ mod tests {
#[test] #[test]
fn headers() { fn headers() {
const data: &'static [u8] = const data: &'static [u8] =
b"Host: foo.com\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n"; b"Host: foo.com\r\n\
Connection: Upgrade\r\n\
Upgrade: websocket\r\n\
\r\n";
let mut inp = Cursor::new(data); let mut inp = Cursor::new(data);
let hdr = Headers::parse(&mut inp).unwrap().unwrap(); let hdr = Headers::parse(&mut inp).unwrap().unwrap();
assert_eq!(hdr.find_first("Host"), Some(&b"foo.com"[..])); assert_eq!(hdr.find_first("Host"), Some(&b"foo.com"[..]));
@ -171,10 +200,29 @@ mod tests {
assert!(hdr.header_is_ignore_case("upgrade", "Websocket")); assert!(hdr.header_is_ignore_case("upgrade", "Websocket"));
} }
#[test]
fn headers_iter() {
const data: &'static [u8] =
b"Host: foo.com\r\n\
Sec-WebSocket-Extensions: permessage-deflate\r\n\
Connection: Upgrade\r\n\
Sec-WebSocket-ExtenSIONS: permessage-unknown\r\n\
Upgrade: websocket\r\n\
\r\n";
let mut inp = Cursor::new(data);
let hdr = Headers::parse(&mut inp).unwrap().unwrap();
let mut iter = hdr.find("Sec-WebSocket-Extensions");
assert_eq!(iter.next(), Some(&b"permessage-deflate"[..]));
assert_eq!(iter.next(), Some(&b"permessage-unknown"[..]));
assert_eq!(iter.next(), None);
}
#[test] #[test]
fn headers_incomplete() { fn headers_incomplete() {
const data: &'static [u8] = const data: &'static [u8] =
b"Host: foo.com\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n"; b"Host: foo.com\r\n\
Connection: Upgrade\r\n\
Upgrade: websocket\r\n";
let mut inp = Cursor::new(data); let mut inp = Cursor::new(data);
let hdr = Headers::parse(&mut inp).unwrap(); let hdr = Headers::parse(&mut inp).unwrap();
assert!(hdr.is_none()); assert!(hdr.is_none());

Loading…
Cancel
Save