1use std::io;
3use std::fmt;
4use std::convert::From;
5use std::error::Error;
6
7use hpack::decoder::DecoderError;
8
9pub mod frame;
10pub mod transport;
11pub mod connection;
12pub mod session;
13pub mod priority;
14
15pub mod client;
16pub mod server;
17
18pub type StreamId = u32;
20pub type Header = (Vec<u8>, Vec<u8>);
23
24pub const ALPN_PROTOCOLS: &'static [&'static [u8]] = &[
31 b"h2",
32 b"h2-16",
33 b"h2-15",
34 b"h2-14",
35];
36
37#[derive(Debug)]
40pub enum HttpError {
41 IoError(io::Error),
42 InvalidFrame,
43 CompressionError(DecoderError),
44 UnknownStreamId,
45 UnableToConnect,
46 MalformedResponse,
48 Other(Box<Error + Send + Sync>),
49}
50
51impl From<io::Error> for HttpError {
54 fn from(err: io::Error) -> HttpError {
55 HttpError::IoError(err)
56 }
57}
58
59impl fmt::Display for HttpError {
60 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
61 write!(fmt, "HTTP/2 Error: {}", self.description())
62 }
63}
64
65impl Error for HttpError {
66 fn description(&self) -> &str {
67 match *self {
68 HttpError::IoError(_) => "Encountered an IO error",
69 HttpError::InvalidFrame => "Encountered an invalid HTTP/2 frame",
70 HttpError::CompressionError(_) => "Encountered an error with HPACK compression",
71 HttpError::UnknownStreamId => "Attempted an operation with an unknown HTTP/2 stream ID",
72 HttpError::UnableToConnect => "An error attempting to establish an HTTP/2 connection",
73 HttpError::MalformedResponse => "The received response was malformed",
74 HttpError::Other(_) => "An unknown error",
75 }
76 }
77
78 fn cause(&self) -> Option<&Error> {
79 match *self {
80 HttpError::Other(ref e) => Some(&**e),
81 HttpError::IoError(ref e) => Some(e),
82 _ => None,
83 }
84 }
85}
86
87#[cfg(test)]
89impl PartialEq for HttpError {
90 fn eq(&self, other: &HttpError) -> bool {
91 match (self, other) {
92 (&HttpError::IoError(ref e1), &HttpError::IoError(ref e2)) => {
93 e1.kind() == e2.kind() && e1.description() == e2.description()
94 },
95 (&HttpError::InvalidFrame, &HttpError::InvalidFrame) => true,
96 (&HttpError::CompressionError(ref e1), &HttpError::CompressionError(ref e2)) => {
97 e1 == e2
98 },
99 (&HttpError::UnknownStreamId, &HttpError::UnknownStreamId) => true,
100 (&HttpError::UnableToConnect, &HttpError::UnableToConnect) => true,
101 (&HttpError::MalformedResponse, &HttpError::MalformedResponse) => true,
102 (&HttpError::Other(ref e1), &HttpError::Other(ref e2)) => {
103 e1.description() == e2.description()
104 },
105 _ => false,
106 }
107 }
108}
109
110pub type HttpResult<T> = Result<T, HttpError>;
113
114#[derive(Debug, Copy, Clone, PartialEq)]
116pub enum HttpScheme {
117 Http,
119 Https,
121}
122
123impl HttpScheme {
124 #[inline]
126 pub fn as_bytes(&self) -> &'static [u8] {
127 match *self {
128 HttpScheme::Http => b"http",
129 HttpScheme::Https => b"https",
130 }
131 }
132}
133
134#[derive(Clone)]
139pub struct Response {
140 pub stream_id: StreamId,
143 pub headers: Vec<Header>,
147 pub body: Vec<u8>,
149}
150
151impl Response {
152 pub fn new(stream_id: StreamId, headers: Vec<Header>, body: Vec<u8>)
154 -> Response {
155 Response {
156 stream_id: stream_id,
157 headers: headers,
158 body: body,
159 }
160 }
161
162 pub fn status_code(&self) -> HttpResult<u16> {
166 if self.headers.len() < 1 {
171 return Err(HttpError::MalformedResponse)
172 }
173 if &self.headers[0].0 != &b":status" {
174 Err(HttpError::MalformedResponse)
175 } else {
176 Ok(try!(Response::parse_status_code(&self.headers[0].1)))
177 }
178 }
179
180 fn parse_status_code(buf: &[u8]) -> HttpResult<u16> {
183 if buf.len() != 3 {
185 return Err(HttpError::MalformedResponse);
186 }
187
188 if buf[0] < b'1' || buf[0] > b'5' {
190 return Err(HttpError::MalformedResponse);
191 }
192
193 if buf[1] < b'0' || buf[1] > b'9' || buf[2] < b'0' || buf[2] > b'9' {
195 return Err(HttpError::MalformedResponse);
196 }
197
198 Ok(100 * ((buf[0] - b'0') as u16) +
200 10 * ((buf[1] - b'0') as u16) +
201 1 * ((buf[2] - b'0') as u16))
202 }
203}
204
205#[derive(Clone)]
208pub struct Request {
209 pub stream_id: u32,
210 pub headers: Vec<Header>,
211 pub body: Vec<u8>,
212}
213
214
215#[cfg(test)]
216pub mod tests;