use super::StreamId; use hpack; use frame::{self, Frame, Head, Kind, Error}; use HeaderMap; use http::{self, request, response, version, uri, Method, StatusCode, Uri}; use http::{Request, Response}; use http::header::{self, HeaderName, HeaderValue}; use bytes::{BytesMut, Bytes}; use byteorder::{BigEndian, ByteOrder}; use string::String; use std::io::Cursor; /// Header frame /// /// This could be either a request or a response. #[derive(Debug)] pub struct Headers { /// The ID of the stream with which this frame is associated. stream_id: StreamId, /// The stream dependency information, if any. stream_dep: Option, /// The decoded header fields fields: HeaderMap, /// Pseudo headers, these are broken out as they must be sent as part of the /// headers frame. pseudo: Pseudo, /// The associated flags flags: HeadersFlag, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct HeadersFlag(u8); #[derive(Debug)] pub struct PushPromise { /// The ID of the stream with which this frame is associated. stream_id: StreamId, /// The ID of the stream being reserved by this PushPromise. promised_id: StreamId, /// The associated flags flags: PushPromiseFlag, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct PushPromiseFlag(u8); #[derive(Debug)] pub struct Continuation { /// Stream ID of continuation frame stream_id: StreamId, /// Argument to pass to the HPACK encoder to resume encoding hpack: hpack::EncodeState, /// remaining headers to encode headers: Iter, } #[derive(Debug)] pub struct StreamDependency { /// The ID of the stream dependency target stream_id: StreamId, /// The weight for the stream. The value exposed (and set) here is always in /// the range [0, 255], instead of [1, 256] (as defined in section 5.3.2.) /// so that the value fits into a `u8`. weight: u8, /// True if the stream dependency is exclusive. is_exclusive: bool, } #[derive(Debug, Default)] pub struct Pseudo { // Request method: Option, scheme: Option>, authority: Option>, path: Option>, // Response status: Option, } #[derive(Debug)] pub struct Iter { /// Pseudo headers pseudo: Option, /// Header fields fields: header::IntoIter, } const END_STREAM: u8 = 0x1; const END_HEADERS: u8 = 0x4; const PADDED: u8 = 0x8; const PRIORITY: u8 = 0x20; const ALL: u8 = END_STREAM | END_HEADERS | PADDED | PRIORITY; // ===== impl Headers ===== impl Headers { pub fn new(stream_id: StreamId, pseudo: Pseudo, fields: HeaderMap) -> Self { Headers { stream_id: stream_id, stream_dep: None, fields: fields, pseudo: pseudo, flags: HeadersFlag::default(), } } pub fn load(head: Head, src: &mut Cursor, decoder: &mut hpack::Decoder) -> Result { let flags = HeadersFlag(head.flag()); assert!(!flags.is_priority(), "unimplemented stream priority"); let mut pseudo = Pseudo::default(); let mut fields = HeaderMap::new(); let mut err = false; macro_rules! set_pseudo { ($field:ident, $val:expr) => {{ if pseudo.$field.is_some() { err = true; } else { pseudo.$field = Some($val); } }} } // At this point, we're going to assume that the hpack encoded headers // contain the entire payload. Later, we need to check for stream // priority. // // TODO: Provide a way to abort decoding if an error is hit. try!(decoder.decode(src, |header| { use hpack::Header::*; match header { Field { name, value } => { fields.append(name, value); } Authority(v) => set_pseudo!(authority, v), Method(v) => set_pseudo!(method, v), Scheme(v) => set_pseudo!(scheme, v), Path(v) => set_pseudo!(path, v), Status(v) => set_pseudo!(status, v), } })); if err { return Err(hpack::DecoderError::RepeatedPseudo.into()); } Ok(Headers { stream_id: head.stream_id(), stream_dep: None, fields: fields, pseudo: pseudo, flags: flags, }) } /// Returns `true` if the frame represents trailers /// /// Trailers are header frames that contain no pseudo headers. pub fn is_trailers(&self) -> bool { self.pseudo.method.is_none() && self.pseudo.status.is_none() } pub fn stream_id(&self) -> StreamId { self.stream_id } pub fn is_end_headers(&self) -> bool { self.flags.is_end_headers() } pub fn is_end_stream(&self) -> bool { self.flags.is_end_stream() } pub fn set_end_stream(&mut self) { self.flags.set_end_stream() } pub fn into_response(self) -> http::Result> { let mut b = Response::builder(); if let Some(status) = self.pseudo.status { b.status(status); } let mut response = try!(b.body(())); *response.headers_mut() = self.fields; Ok(response) } pub fn into_request(self) -> http::Result> { let mut b = Request::builder(); // TODO: should we distinguish between HTTP_2 and HTTP_2C? // carllerche/http#42 b.version(version::HTTP_2); if let Some(method) = self.pseudo.method { b.method(method); } // Convert the URI let mut parts = uri::Parts::default(); if let Some(scheme) = self.pseudo.scheme { // TODO: Don't unwrap parts.scheme = Some(uri::Scheme::try_from_shared(scheme.into_inner()).unwrap()); } if let Some(authority) = self.pseudo.authority { // TODO: Don't unwrap parts.authority = Some(uri::Authority::try_from_shared(authority.into_inner()).unwrap()); } if let Some(path) = self.pseudo.path { // TODO: Don't unwrap parts.origin_form = Some(uri::OriginForm::try_from_shared(path.into_inner()).unwrap()); } b.uri(parts); let mut request = try!(b.body(())); *request.headers_mut() = self.fields; Ok(request) } pub fn into_fields(self) -> HeaderMap { self.fields } pub fn encode(self, encoder: &mut hpack::Encoder, dst: &mut BytesMut) -> Option { let head = self.head(); let pos = dst.len(); // At this point, we don't know how big the h2 frame will be. // So, we write the head with length 0, then write the body, and // finally write the length once we know the size. head.encode(0, dst); // Encode the frame let mut headers = Iter { pseudo: Some(self.pseudo), fields: self.fields.into_iter(), }; let ret = match encoder.encode(None, &mut headers, dst) { hpack::Encode::Full => None, hpack::Encode::Partial(state) => { Some(Continuation { stream_id: self.stream_id, hpack: state, headers: headers, }) } }; // Compute the frame length let len = (dst.len() - pos) - frame::HEADER_LEN; // Write the frame length BigEndian::write_uint(&mut dst[pos..pos+3], len as u64, 3); ret } fn head(&self) -> Head { Head::new(Kind::Headers, self.flags.into(), self.stream_id) } } impl From for Frame { fn from(src: Headers) -> Self { Frame::Headers(src) } } // ===== impl PushPromise ===== impl PushPromise { pub fn load(head: Head, payload: &[u8]) -> Result { let flags = PushPromiseFlag(head.flag()); // TODO: Handle padding let promised_id = StreamId::parse(&payload[..4]); Ok(PushPromise { stream_id: head.stream_id(), promised_id: promised_id, flags: flags, }) } } impl From for Frame { fn from(src: PushPromise) -> Self { Frame::PushPromise(src) } } // ===== impl Pseudo ===== impl Pseudo { pub fn request(method: Method, uri: Uri) -> Self { let parts = uri::Parts::from(uri); fn to_string(src: Bytes) -> String { unsafe { String::from_utf8_unchecked(src) } } let path = parts.origin_form .map(|v| v.into()) .unwrap_or_else(|| Bytes::from_static(b"/")); let mut pseudo = Pseudo { method: Some(method), scheme: None, authority: None, path: Some(to_string(path)), status: None, }; // If the URI includes a scheme component, add it to the pseudo headers // // TODO: Scheme must be set... if let Some(scheme) = parts.scheme { pseudo.set_scheme(to_string(scheme.into())); } // If the URI includes an authority component, add it to the pseudo // headers if let Some(authority) = parts.authority { pseudo.set_authority(to_string(authority.into())); } pseudo } pub fn response(status: StatusCode) -> Self { Pseudo { method: None, scheme: None, authority: None, path: None, status: Some(status), } } pub fn set_scheme(&mut self, scheme: String) { self.scheme = Some(scheme); } pub fn set_authority(&mut self, authority: String) { self.authority = Some(authority); } } // ===== impl Iter ===== impl Iterator for Iter { type Item = hpack::Header>; fn next(&mut self) -> Option { use hpack::Header::*; if let Some(ref mut pseudo) = self.pseudo { if let Some(method) = pseudo.method.take() { return Some(Method(method)); } if let Some(scheme) = pseudo.scheme.take() { return Some(Scheme(scheme)); } if let Some(authority) = pseudo.authority.take() { return Some(Authority(authority)); } if let Some(path) = pseudo.path.take() { return Some(Path(path)); } if let Some(status) = pseudo.status.take() { return Some(Status(status)); } } self.pseudo = None; self.fields.next() .map(|(name, value)| { Field { name: name, value: value} }) } } // ===== impl HeadersFlag ===== impl HeadersFlag { pub fn empty() -> HeadersFlag { HeadersFlag(0) } pub fn load(bits: u8) -> HeadersFlag { HeadersFlag(bits & ALL) } pub fn is_end_stream(&self) -> bool { self.0 & END_STREAM == END_STREAM } pub fn set_end_stream(&mut self) { self.0 |= END_STREAM } pub fn is_end_headers(&self) -> bool { self.0 & END_HEADERS == END_HEADERS } pub fn is_padded(&self) -> bool { self.0 & PADDED == PADDED } pub fn is_priority(&self) -> bool { self.0 & PRIORITY == PRIORITY } } impl Default for HeadersFlag { /// Returns a `HeadersFlag` value with `END_HEADERS` set. fn default() -> Self { HeadersFlag(END_HEADERS) } } impl From for u8 { fn from(src: HeadersFlag) -> u8 { src.0 } }