├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── appveyor.yml ├── examples ├── client_async.rs ├── client_simple.rs └── server_simple.rs └── src ├── client ├── async.rs ├── mod.rs ├── simple.rs └── tests.rs ├── http ├── client │ ├── mod.rs │ └── tls.rs ├── connection.rs ├── frame │ ├── builder.rs │ ├── data.rs │ ├── goaway.rs │ ├── headers.rs │ ├── mod.rs │ ├── ping.rs │ ├── rst_stream.rs │ ├── settings.rs │ └── window_update.rs ├── mod.rs ├── priority.rs ├── server.rs ├── session.rs ├── tests │ ├── common.rs │ └── mod.rs └── transport.rs ├── lib.rs └── server └── mod.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | # necessary for `travis-cargo coveralls --no-sudo` 4 | addons: 5 | apt: 6 | packages: 7 | - libcurl4-openssl-dev 8 | - libelf-dev 9 | - libdw-dev 10 | 11 | matrix: 12 | include: 13 | - rust: nightly 14 | - rust: beta 15 | - rust: stable 16 | 17 | # load travis-cargo 18 | before_script: 19 | - | 20 | pip install 'travis-cargo<0.2' --user && 21 | export PATH=$HOME/.local/bin:$PATH 22 | 23 | script: 24 | - cargo test --features="tls" 25 | - travis-cargo --only stable doc -- --no-deps --features="tls" 26 | 27 | sudo: false 28 | 29 | after_success: 30 | - travis-cargo --only stable doc-upload 31 | - travis-cargo --only stable coveralls --no-sudo -- --features="tls" 32 | 33 | env: 34 | global: 35 | secure: eSYRUJ2wTq1g6AiPp0zvtxVJFn/3FnrCRAJmGCN1TBYpnl11ZvLZfhUA9IC4S48/YVmdeP1pywpIjY3ZGk7gWuaRLpTrwBxgm01RbOglQS1if6Pryc01FcwCSGb1fJKY4qR0v6iQRb23jaFfSELHfThf4rmG4QiKiNviHJRzb0c= 36 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "solicit" 4 | version = "0.4.4" 5 | authors = ["Marko Lalic "] 6 | 7 | description = "A library implementation of HTTP/2" 8 | repository = "https://github.com/mlalic/solicit" 9 | homepage = "https://github.com/mlalic/solicit" 10 | readme = "README.md" 11 | license = "MIT" 12 | keywords = ["http2", "protocol", "solicit"] 13 | documentation = "https://mlalic.github.io/solicit/solicit/index.html" 14 | 15 | [dependencies] 16 | hpack = "0.3" 17 | log = "^0.3" 18 | 19 | [dependencies.openssl] 20 | version = "0.6" 21 | features = ["tlsv1_2", "npn"] 22 | optional = true 23 | 24 | [features] 25 | live_tests = [] 26 | tls = ["openssl", "openssl/tlsv1_2", "openssl/npn"] 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Marko Lalic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # solicit 2 | 3 | [![Travis Build Status](https://img.shields.io/travis/mlalic/solicit/master.svg?style=flat-square&label=Travis%20Build)](https://travis-ci.org/mlalic/solicit) 4 | [![AppVeyor Build Status](https://img.shields.io/appveyor/ci/mlalic/solicit/master.svg?style=flat-square&label=AppVeyor%20Build)](https://ci.appveyor.com/project/mlalic/solicit) 5 | [![Coverage Status](https://coveralls.io/repos/github/mlalic/solicit/badge.svg?branch=master)](https://coveralls.io/github/mlalic/solicit?branch=master) 6 | [![Crates.io](https://img.shields.io/crates/v/solicit.svg?style=flat-square)](https://crates.io/crates/solicit) 7 | 8 | An HTTP/2 implementation in Rust. 9 | 10 | [API Documentation](https://mlalic.github.io/solicit/) 11 | 12 | # Goals 13 | 14 | The main goal of the project is to provide a low-level implementation of the 15 | HTTP/2 protocol and expose it in a way that higher-level libraries can make use 16 | of it. For example, it should be possible for a higher level libary to write a 17 | simple adapter that exposes the responses obtained over an HTTP/2 connection in 18 | the same manner as those obtained over HTTP/1.1. 19 | 20 | The API should make it possible to use an HTTP/2 connection at any level -- 21 | everything from sending and managing individual HTTP/2 frames to only 22 | manipulating requests and responses -- depending on the needs of the end users 23 | of the library. 24 | 25 | The core of the library should be decoupled from the particulars of the 26 | underlying IO -- it should be possible to use the same APIs regardless if the 27 | IO is evented or blocking. In the same time, the library provides convenience 28 | adapters that allow the usage of Rust's standard library socket IO as the 29 | transport layer out of the box. 30 | 31 | Extensive test coverage is also a major goal. No code is committed without 32 | accompanying tests. 33 | 34 | At this stage, performance was not considered as one of the primary goals. 35 | 36 | # Examples 37 | 38 | As mentioned in the goals section, this library does not aim to provide a 39 | full high-level client or server implementation (no caching, no automatic 40 | redirect following, no strongly-typed headers, etc.). 41 | 42 | However, in order to demonstrate how such components could be built or provide 43 | a baseline for less demanding versions of the same, implementations of a limited 44 | client and server are included in the crate (the modules `solicit::client` and 45 | `solicit::server`, respectively). 46 | 47 | ## Simple Client 48 | 49 | The [simple client](https://github.com/mlalic/solicit/blob/master/src/client/simple.rs) 50 | implementation allows users to issue a number of requests before blocking to 51 | read one of the responses. After a response is received, more requests can 52 | be sent over the same connection; however, requests cannot be queued while a 53 | response is being read. 54 | 55 | In a way, this is similar to how HTTP/1.1 connections with keep-alive (and 56 | pipelining) work. 57 | 58 | ### Example 59 | 60 | A clear-text (`http://`) connection. 61 | 62 | ```rust 63 | extern crate solicit; 64 | use solicit::http::client::CleartextConnector; 65 | use solicit::client::SimpleClient; 66 | use std::str; 67 | 68 | fn main() { 69 | // Connect to an HTTP/2 aware server 70 | let connector = CleartextConnector::new("http2bin.org"); 71 | let mut client = SimpleClient::with_connector(connector).unwrap(); 72 | let response = client.get(b"/get", &[]).unwrap(); 73 | assert_eq!(response.stream_id, 1); 74 | assert_eq!(response.status_code().unwrap(), 200); 75 | // Dump the headers and the response body to stdout. 76 | // They are returned as raw bytes for the user to do as they please. 77 | // (Note: in general directly decoding assuming a utf8 encoding might not 78 | // always work -- this is meant as a simple example that shows that the 79 | // response is well formed.) 80 | for header in response.headers.iter() { 81 | println!("{}: {}", 82 | str::from_utf8(header.name()).unwrap(), 83 | str::from_utf8(header.value()).unwrap()); 84 | } 85 | println!("{}", str::from_utf8(&response.body).unwrap()); 86 | // We can issue more requests after reading this one... 87 | // These calls block until the request itself is sent, but do not wait 88 | // for a response. 89 | let req_id1 = client.request(b"GET", b"/get?hi=hello", &[], None).unwrap(); 90 | let req_id2 = client.request(b"GET", b"/asdf", &[], None).unwrap(); 91 | // Now we get a response for both requests... This does block. 92 | let (resp1, resp2) = ( 93 | client.get_response(req_id1).unwrap(), 94 | client.get_response(req_id2).unwrap(), 95 | ); 96 | assert_eq!(resp1.status_code().unwrap(), 200); 97 | assert_eq!(resp2.status_code().unwrap(), 404); 98 | } 99 | ``` 100 | 101 | A TLS-protected (and negotiated) `https://` connection. The only difference is 102 | in the type of the connector provided to the `SimpleClient`. 103 | 104 | Requires the `tls` feature of the crate. 105 | 106 | ```rust 107 | extern crate solicit; 108 | use solicit::http::client::tls::TlsConnector; 109 | use solicit::client::SimpleClient; 110 | use std::str; 111 | 112 | fn main() { 113 | // Connect to an HTTP/2 aware server 114 | let path = "/path/to/certs.pem"; 115 | let connector = TlsConnector::new("http2bin.org", &path); 116 | let mut client = SimpleClient::with_connector(connector).unwrap(); 117 | let response = client.get(b"/get", &[]).unwrap(); 118 | assert_eq!(response.stream_id, 1); 119 | assert_eq!(response.status_code().unwrap(), 200); 120 | // Dump the headers and the response body to stdout. 121 | // They are returned as raw bytes for the user to do as they please. 122 | // (Note: in general directly decoding assuming a utf8 encoding might not 123 | // always work -- this is meant as a simple example that shows that the 124 | // response is well formed.) 125 | for header in response.headers.iter() { 126 | println!("{}: {}", 127 | str::from_utf8(header.name()).unwrap(), 128 | str::from_utf8(header.value()).unwrap()); 129 | } 130 | println!("{}", str::from_utf8(&response.body).unwrap()); 131 | } 132 | ``` 133 | 134 | For how it leverages the `solicit::http` API for its implementation, check out the 135 | [`solicit::client::simple`](https://github.com/mlalic/solicit/blob/master/src/client/simple.rs) 136 | module. 137 | 138 | ## Async Client 139 | 140 | The [async client](https://github.com/mlalic/solicit/blob/master/src/client/async.rs) 141 | leverages more features specific to HTTP/2, as compared to HTTP/1.1. 142 | 143 | It allows multiple clients to issue requests to the same underlying 144 | connection concurrently. The responses are returned to the clients in the form 145 | of a `Future`, allowing them to block on waiting for the response only once 146 | they don't have anything else to do (which could be immediately after issuing 147 | it). 148 | 149 | This client spawns one background thread per HTTP/2 connection, which exits 150 | gracefully once there are no more clients connected to it (and thus no more 151 | potential requests can be issued) or the HTTP/2 connection returns an error. 152 | 153 | This client implementation is also just an example of what can be achieved 154 | using the `solicit::htp` API -- see: 155 | [`solicit::client::async`](https://github.com/mlalic/solicit/blob/master/src/client/async.rs) 156 | 157 | ### Example 158 | 159 | ```rust 160 | extern crate solicit; 161 | 162 | use solicit::client::Client; 163 | use solicit::http::Header; 164 | use solicit::http::client::CleartextConnector; 165 | use std::thread; 166 | use std::str; 167 | 168 | fn main() { 169 | // Connect to a server that supports HTTP/2 170 | let connector = CleartextConnector::new("http2bin.org"); 171 | let client = Client::with_connector(connector).unwrap(); 172 | 173 | // Issue 5 requests from 5 different threads concurrently and wait for all 174 | // threads to receive their response. 175 | let threads: Vec<_> = (0..5).map(|i| { 176 | let this = client.clone(); 177 | thread::spawn(move || { 178 | let resp = this.get(b"/get", &[Header::new(b"x-thread".to_vec(), vec![b'0' + i])]).unwrap(); 179 | let response = resp.recv().unwrap(); 180 | 181 | println!("Thread {} got response ... {}", i, response.status_code().ok().unwrap()); 182 | 183 | response 184 | }) 185 | }).collect(); 186 | 187 | let responses: Vec<_> = threads.into_iter().map(|thread| thread.join()) 188 | .collect(); 189 | 190 | println!("All threads joined. Full responses are:"); 191 | for response in responses.into_iter() { 192 | let response = response.unwrap(); 193 | println!("The response contains the following headers:"); 194 | for header in response.headers.iter() { 195 | println!(" {}: {}", 196 | str::from_utf8(header.name()).unwrap(), 197 | str::from_utf8(header.value()).unwrap()); 198 | } 199 | println!("{}", str::from_utf8(&response.body).unwrap()); 200 | } 201 | } 202 | ``` 203 | 204 | ## Simple Server 205 | 206 | The simple server implementation works similarly to the `SimpleClient`; this 207 | server implementation is fully single-threaded: no responses can be written 208 | while reading a request (and vice-versa). It does show how the API can be used 209 | to implement an HTTP/2 server, though. 210 | 211 | Provided by the [`solicit::server`](https://github.com/mlalic/solicit/blob/master/src/server/mod.rs) 212 | module. 213 | 214 | ### Example 215 | 216 | A server that echoes the body of each request that it receives. 217 | 218 | ```rust 219 | extern crate solicit; 220 | use std::str; 221 | use std::net::{TcpListener, TcpStream}; 222 | use std::thread; 223 | 224 | use solicit::http::Response; 225 | use solicit::server::SimpleServer; 226 | 227 | fn main() { 228 | fn handle_client(stream: TcpStream) { 229 | let mut server = SimpleServer::new(stream, |req| { 230 | println!("Received request:"); 231 | for header in req.headers.iter() { 232 | println!(" {}: {}", 233 | str::from_utf8(header.name()).unwrap(), 234 | str::from_utf8(header.value()).unwrap()); 235 | } 236 | println!("Body:\n{}", str::from_utf8(&req.body).unwrap()); 237 | 238 | // Return a dummy response for every request 239 | Response { 240 | headers: vec![ 241 | (b":status".to_vec(), b"200".to_vec()), 242 | (b"x-solicit".to_vec(), b"Hello, World!".to_vec()), 243 | ], 244 | body: req.body.to_vec(), 245 | stream_id: req.stream_id, 246 | } 247 | }).unwrap(); 248 | while let Ok(_) = server.handle_next() {} 249 | println!("Server done (client disconnected)"); 250 | } 251 | 252 | let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); 253 | for stream in listener.incoming() { 254 | let stream = stream.unwrap(); 255 | thread::spawn(move || { 256 | handle_client(stream) 257 | }); 258 | } 259 | } 260 | ``` 261 | 262 | # License 263 | 264 | The project is published under the terms of the [MIT License](https://github.com/mlalic/solicit/blob/master/LICENSE). 265 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | install: 2 | - ps: | 3 | if ($env:PLATFORM -eq "x86") { 4 | Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe' -FileName rust.exe 5 | } else { 6 | Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-x86_64-pc-windows-gnu.exe' -FileName rust.exe 7 | } 8 | - rust.exe /VERYSILENT /NORESTART /DIR="C:\Program Files\Rust" 9 | - SET PATH=%PATH%;C:\Program Files\Rust\bin;C:\MinGW\bin 10 | - rustc -V 11 | - cargo -V 12 | 13 | platform: 14 | - x86 15 | 16 | build: false 17 | 18 | test_script: 19 | - cargo test --verbose 20 | -------------------------------------------------------------------------------- /examples/client_async.rs: -------------------------------------------------------------------------------- 1 | extern crate solicit; 2 | 3 | use solicit::http::Header; 4 | use solicit::client::Client; 5 | use solicit::http::client::CleartextConnector; 6 | use std::thread; 7 | use std::str; 8 | 9 | fn main() { 10 | // Connect to a server that supports HTTP/2 11 | let connector = CleartextConnector::new("http2bin.org"); 12 | let client = Client::with_connector(connector).unwrap(); 13 | 14 | // Issue 5 requests from 5 different threads concurrently and wait for all 15 | // threads to receive their response. 16 | let threads: Vec<_> = (0..5).map(|i| { 17 | let this = client.clone(); 18 | thread::spawn(move || { 19 | let resp = this.get(b"/get", &[ 20 | // A fully static header 21 | Header::new(&b"x-solicit"[..], &b"Hello"[..]), 22 | // A header with a static name, but dynamically allocated value 23 | Header::new(&b"x-solicit"[..], vec![b'0' + i as u8]), 24 | ]).unwrap(); 25 | let response = resp.recv().unwrap(); 26 | println!("Thread {} got response ... {}", i, response.status_code().ok().unwrap()); 27 | println!("The response contains the following headers:"); 28 | for header in response.headers.iter() { 29 | println!(" {}: {}", 30 | str::from_utf8(header.name()).unwrap(), 31 | str::from_utf8(header.value()).unwrap()); 32 | } 33 | println!("Body:"); 34 | println!("{}", str::from_utf8(&response.body).unwrap()); 35 | }) 36 | }).collect(); 37 | 38 | let _: Vec<_> = threads.into_iter().map(|thread| thread.join()).collect(); 39 | } 40 | -------------------------------------------------------------------------------- /examples/client_simple.rs: -------------------------------------------------------------------------------- 1 | //! An example of usage of the `solicit::client::SimpleClient` API. 2 | //! 3 | //! This is a simple implementation of an HTTP/2 client, built on top of the API of `solicit::http` 4 | //! that performs all IO in the main thread. 5 | 6 | extern crate solicit; 7 | 8 | use std::env; 9 | use std::str; 10 | 11 | use solicit::http::Response; 12 | use solicit::http::client::CleartextConnector; 13 | use solicit::client::SimpleClient; 14 | 15 | fn fetch(host: &str, port: u16, paths: &[String]) -> Vec> { 16 | let mut client = SimpleClient::with_connector(CleartextConnector::with_port(host, port)).unwrap(); 17 | paths.iter().map(|path| client.get(path.as_bytes(), &[]).unwrap()).collect() 18 | } 19 | 20 | fn main() { 21 | fn print_usage() { 22 | println!("Usage: client_simple [:] [...]"); 23 | println!( 24 | "NOTE: The example does not accept URLs, rather the host name and a list of paths"); 25 | } 26 | 27 | let host = env::args().nth(1); 28 | let paths: Vec<_> = env::args().skip(2).collect(); 29 | 30 | if host.is_none() || paths.is_empty() { 31 | print_usage(); 32 | return; 33 | } 34 | let host = host.unwrap(); 35 | // Split off the port, if present 36 | let parts: Vec<_> = host.split(":").collect(); 37 | if parts.len() > 2 { 38 | println!("Invalid host!"); 39 | print_usage(); 40 | return; 41 | } 42 | 43 | let (host, port) = if parts.len() == 1 { 44 | (parts[0], 80) 45 | } else { 46 | let port = match str::FromStr::from_str(parts[1]) { 47 | Err(_) => { 48 | println!("Invalid host (invalid port given)"); 49 | print_usage(); 50 | return; 51 | }, 52 | Ok(port) => port, 53 | }; 54 | (parts[0], port) 55 | }; 56 | 57 | let responses = fetch(&host, port, &paths); 58 | for (path, response) in paths.iter().zip(responses) { 59 | println!("Request path: {}", path); 60 | 61 | println!(" status == {}", response.status_code().unwrap()); 62 | // Dump the headers and the response body to stdout. 63 | // They are returned as raw bytes for the user to do as they please. 64 | // (Note: in general directly decoding assuming a utf8 encoding might not 65 | // always work -- this is meant as a simple example that shows that the 66 | // response is well formed.) 67 | for header in response.headers.iter() { 68 | println!(" {}: {}", 69 | str::from_utf8(header.name()).unwrap(), 70 | str::from_utf8(header.value()).unwrap()); 71 | } 72 | println!(""); 73 | println!("{}", str::from_utf8(&response.body).unwrap()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/server_simple.rs: -------------------------------------------------------------------------------- 1 | //! An example of usage of the `solicit::server::SimpleServer` API. 2 | //! 3 | //! It spawns a new dedicated thread for handling each new HTTP/2 connection (which corresponds to 4 | //! a single TCP connection). Within that thread, all requests that are received are handled 5 | //! sequentially, returning identical dummy "Hello, World!" responses. 6 | //! 7 | //! Only for demonstration purposes. 8 | 9 | extern crate solicit; 10 | 11 | use std::str; 12 | use std::net::{TcpListener, TcpStream}; 13 | use std::thread; 14 | 15 | use solicit::http::{Response, Header}; 16 | use solicit::server::SimpleServer; 17 | 18 | fn main() { 19 | fn handle_client(stream: TcpStream) { 20 | let mut server = SimpleServer::new(stream, |req| { 21 | println!("Received request:"); 22 | for header in req.headers.iter() { 23 | println!(" {}: {}", 24 | str::from_utf8(header.name()).unwrap(), 25 | str::from_utf8(header.value()).unwrap()); 26 | } 27 | println!("Body:\n{}", str::from_utf8(&req.body).unwrap()); 28 | 29 | // Return a dummy response for every request 30 | Response { 31 | headers: vec![ 32 | Header::new(b":status", b"200"), 33 | Header::new(b"x-solicit".to_vec(), b"Hello, World!".to_vec()), 34 | ], 35 | body: req.body.to_vec(), 36 | stream_id: req.stream_id, 37 | } 38 | }).unwrap(); 39 | while let Ok(_) = server.handle_next() {} 40 | println!("Server done (client disconnected)"); 41 | } 42 | 43 | let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); 44 | println!("Server started on 127.0.0.1:8080..."); 45 | println!("Waiting for clients..."); 46 | for stream in listener.incoming() { 47 | let stream = stream.unwrap(); 48 | println!("New client connected!"); 49 | thread::spawn(move || { 50 | handle_client(stream) 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/client/mod.rs: -------------------------------------------------------------------------------- 1 | //! The module contains implementations of HTTP/2 clients that could be 2 | //! directly used to access HTTP/2 servers, i.e. send requests and read 3 | //! responses. 4 | 5 | pub use self::simple::SimpleClient; 6 | pub use self::async::Client; 7 | 8 | mod simple; 9 | mod async; 10 | #[cfg(test)]mod tests; 11 | -------------------------------------------------------------------------------- /src/client/simple.rs: -------------------------------------------------------------------------------- 1 | //! The module contains an implementation of a simple HTTP/2 client. 2 | 3 | use http::{StreamId, HttpResult, HttpError, Response, Header, HttpScheme}; 4 | use http::transport::{TransportStream, TransportReceiveFrame}; 5 | use http::connection::{HttpConnection, SendStatus}; 6 | use http::session::{SessionState, DefaultSessionState, DefaultStream, Stream}; 7 | use http::session::Client as ClientMarker; 8 | use http::client::{ClientConnection, HttpConnect, RequestStream, ClientStream}; 9 | 10 | /// A struct implementing a simple HTTP/2 client. 11 | /// 12 | /// This client works as an HTTP/1.1 client with a Keep-Alive connection and 13 | /// pipelining might work. 14 | /// 15 | /// Multiple requests can be queued up (and sent to the server) by calling 16 | /// `request` multiple times, before any `get_response`. 17 | /// 18 | /// Once a `get_response` is issued, the client blocks until it receives the 19 | /// response for the particular request that was referenced in the `get_response` 20 | /// call. 21 | /// 22 | /// Therefore, by doing `request` -> `get_response` we can use the HTTP/2 23 | /// connection as a `Keep-Alive` HTTP/1.1 connection and a pipelined flow by 24 | /// queuing up a sequence of requests and then "joining" over them by calling 25 | /// `get_response` for each of them. 26 | /// 27 | /// The responses that are returned by the client are very raw representations 28 | /// of the response. 29 | /// 30 | /// # Examples 31 | /// 32 | /// Issue a simple GET request using the helper `get` method. Premade connection 33 | /// passed to the client. 34 | /// 35 | /// ```no_run 36 | /// use std::net::TcpStream; 37 | /// use solicit::http::HttpScheme; 38 | /// use solicit::http::connection::HttpConnection; 39 | /// use solicit::http::client::write_preface; 40 | /// use solicit::client::SimpleClient; 41 | /// use std::str; 42 | /// 43 | /// // Prepare a stream manually... We must write the preface ourselves in this case. 44 | /// // This is a more advanced way to use the client and the `HttpConnect` implementations 45 | /// // should usually be preferred for their convenience. 46 | /// let mut stream = TcpStream::connect(&("http2bin.org", 80)).unwrap(); 47 | /// write_preface(&mut stream); 48 | /// // So, the preface is written, now give up ownership of the stream to the client... 49 | /// let mut client = SimpleClient::with_stream( 50 | /// stream, 51 | /// "http2bin.org".into(), 52 | /// HttpScheme::Http).unwrap(); 53 | /// let response = client.get(b"/", &[]).unwrap(); 54 | /// assert_eq!(response.stream_id, 1); 55 | /// assert_eq!(response.status_code().unwrap(), 200); 56 | /// // Dump the headers and the response body to stdout. 57 | /// // They are returned as raw bytes for the user to do as they please. 58 | /// // (Note: in general directly decoding assuming a utf8 encoding might not 59 | /// // always work -- this is meant as a simple example that shows that the 60 | /// // response is well formed.) 61 | /// for header in response.headers.iter() { 62 | /// println!("{}: {}", 63 | /// str::from_utf8(header.name()).unwrap(), 64 | /// str::from_utf8(header.value()).unwrap()); 65 | /// } 66 | /// println!("{}", str::from_utf8(&response.body).unwrap()); 67 | /// ``` 68 | /// 69 | /// Issue a simple GET request using the helper `get` method. Pass a connector 70 | /// to establish a new connection. 71 | /// 72 | /// ```no_run 73 | /// use solicit::http::client::CleartextConnector; 74 | /// use solicit::client::SimpleClient; 75 | /// use std::str; 76 | /// 77 | /// // Connect to an HTTP/2 aware server 78 | /// let connector = CleartextConnector::new("http2bin.org"); 79 | /// let mut client = SimpleClient::with_connector(connector).unwrap(); 80 | /// let response = client.get(b"/", &[]).unwrap(); 81 | /// assert_eq!(response.stream_id, 1); 82 | /// assert_eq!(response.status_code().unwrap(), 200); 83 | /// // Dump the headers and the response body to stdout. 84 | /// // They are returned as raw bytes for the user to do as they please. 85 | /// // (Note: in general directly decoding assuming a utf8 encoding might not 86 | /// // always work -- this is meant as a simple example that shows that the 87 | /// // response is well formed.) 88 | /// for header in response.headers.iter() { 89 | /// println!("{}: {}", 90 | /// str::from_utf8(header.name()).unwrap(), 91 | /// str::from_utf8(header.value()).unwrap()); 92 | /// } 93 | /// println!("{}", str::from_utf8(&response.body).unwrap()); 94 | /// ``` 95 | pub struct SimpleClient 96 | where S: TransportStream 97 | { 98 | /// The underlying `ClientConnection` that the client uses 99 | conn: ClientConnection, 100 | /// The name of the host to which the client is connected to. 101 | host: Vec, 102 | /// The receiving end of the underlying transport stream. Allows us to extract the next frame 103 | /// that the HTTP connection should process. 104 | receiver: S, 105 | /// The sending end of the underlying transport stream. 106 | sender: S, 107 | } 108 | 109 | impl SimpleClient 110 | where S: TransportStream 111 | { 112 | /// Creates a new `SimpleClient` instance that will use the given `stream` instance for its 113 | /// underlying communication with the host. Additionally, requires the host identifier and the 114 | /// scheme of the connection. 115 | /// 116 | /// It assumes that the given `stream` has already been initialized for HTTP/2 communication 117 | /// (by having the required protocol negotiation done and writing the client preface). 118 | pub fn with_stream(stream: S, host: String, scheme: HttpScheme) -> HttpResult> { 119 | let state = DefaultSessionState::::new(); 120 | let receiver = try!(stream.try_split()); 121 | let conn = HttpConnection::new(scheme); 122 | let mut client = SimpleClient { 123 | conn: ClientConnection::with_connection(conn, state), 124 | host: host.as_bytes().to_vec(), 125 | receiver: receiver, 126 | sender: stream, 127 | }; 128 | 129 | try!(client.init()); 130 | 131 | Ok(client) 132 | } 133 | 134 | /// A convenience constructor that first tries to establish an HTTP/2 135 | /// connection by using the given connector instance (an implementation of 136 | /// the `HttpConnect` trait). 137 | /// 138 | /// # Panics 139 | /// 140 | /// Currently, it panics if the connector returns an error. 141 | pub fn with_connector(connector: C) -> HttpResult> 142 | where C: HttpConnect 143 | { 144 | let ClientStream(stream, scheme, host) = try!(connector.connect()); 145 | SimpleClient::with_stream(stream, host, scheme) 146 | } 147 | 148 | /// Internal helper method that performs the initialization of the client's 149 | /// connection. 150 | #[inline] 151 | fn init(&mut self) -> HttpResult<()> { 152 | self.conn.expect_settings(&mut TransportReceiveFrame::new(&mut self.receiver), 153 | &mut self.sender) 154 | } 155 | 156 | /// Send a request to the server. Blocks until the entire request has been 157 | /// sent. 158 | /// 159 | /// The request is described by the method, the path on which it should be 160 | /// invoked and the "real" headers that should be included. Clients should 161 | /// never put pseudo-headers in the `headers` parameter, as those are 162 | /// automatically included based on metadata. 163 | /// 164 | /// # Returns 165 | /// 166 | /// If the full request is successfully sent, returns the ID of the stream 167 | /// on which the request was sent. Clients can use this ID to refer to the 168 | /// response. 169 | /// 170 | /// Any IO errors are propagated. 171 | pub fn request(&mut self, 172 | method: &[u8], 173 | path: &[u8], 174 | extras: &[Header], 175 | body: Option>) 176 | -> HttpResult { 177 | // Prepares the request stream 178 | let stream = self.new_stream(method, path, extras, body); 179 | // Starts the request (i.e. sends out the headers) 180 | let stream_id = try!(self.conn.start_request(stream, &mut self.receiver)); 181 | // TODO(mlalic): Remove when `Stream::on_id_assigned` is invoked by the session. 182 | self.conn.state.get_stream_mut(stream_id).unwrap().stream_id = Some(stream_id); 183 | 184 | // And now makes sure the data is sent out... 185 | // Note: Since for now there is no flow control, sending data will always continue 186 | // progressing, but it might violate flow control windows, causing the peer to shut 187 | // down the connection. 188 | debug!("Trying to send the body"); 189 | while let SendStatus::Sent = try!(self.conn.send_next_data(&mut self.sender)) { 190 | // We iterate until the data is sent, as the contract of this call is that it blocks 191 | // until such a time. 192 | } 193 | 194 | Ok(stream_id) 195 | } 196 | 197 | /// Gets the response for the stream with the given ID. If a valid stream ID 198 | /// is given, it blocks until a response is received. 199 | /// 200 | /// # Returns 201 | /// 202 | /// A `Response` if the response can be successfully read. 203 | /// 204 | /// Any underlying IO errors are propagated. Errors in the HTTP/2 protocol 205 | /// also stop processing and are returned to the client. 206 | pub fn get_response(&mut self, stream_id: StreamId) -> HttpResult> { 207 | match self.conn.state.get_stream_ref(stream_id) { 208 | None => return Err(HttpError::UnknownStreamId), 209 | Some(_) => {} 210 | }; 211 | loop { 212 | if let Some(stream) = self.conn.state.get_stream_ref(stream_id) { 213 | if stream.is_closed() { 214 | return Ok(Response { 215 | stream_id: stream_id, 216 | headers: stream.headers.clone().unwrap(), 217 | body: stream.body.clone(), 218 | }); 219 | } 220 | } 221 | try!(self.handle_next_frame()); 222 | } 223 | } 224 | 225 | /// Performs a GET request on the given path. This is a shortcut method for 226 | /// calling `request` followed by `get_response` for the returned stream ID. 227 | pub fn get(&mut self, 228 | path: &[u8], 229 | extra_headers: &[Header]) 230 | -> HttpResult> { 231 | let stream_id = try!(self.request(b"GET", path, extra_headers, None)); 232 | self.get_response(stream_id) 233 | } 234 | 235 | /// Performs a POST request on the given path. 236 | pub fn post(&mut self, 237 | path: &[u8], 238 | extra_headers: &[Header], 239 | body: Vec) 240 | -> HttpResult> { 241 | let stream_id = try!(self.request(b"POST", path, extra_headers, Some(body))); 242 | self.get_response(stream_id) 243 | } 244 | 245 | /// Internal helper method that prepares a new `RequestStream` instance based on the given 246 | /// request parameters. 247 | /// 248 | /// The `RequestStream` is then ready to be passed on to the connection instance in order to 249 | /// start the request. 250 | fn new_stream<'n, 'v>(&self, 251 | method: &'v [u8], 252 | path: &'v [u8], 253 | extras: &[Header<'n, 'v>], 254 | body: Option>) 255 | -> RequestStream<'n, 'v, DefaultStream> { 256 | let mut stream = DefaultStream::new(); 257 | match body { 258 | Some(body) => stream.set_full_data(body), 259 | None => stream.close_local(), 260 | }; 261 | 262 | let mut headers: Vec
= vec![ 263 | Header::new(b":method", method), 264 | Header::new(b":path", path), 265 | Header::new(b":authority", self.host.clone()), 266 | Header::new(b":scheme", self.conn.scheme().as_bytes().to_vec()), 267 | ]; 268 | // The clone is lightweight if the original Header was just borrowing something; it's a 269 | // deep copy if it was already owned. Consider requiring that this method gets an iterator 270 | // of Headers... 271 | headers.extend(extras.iter().cloned()); 272 | 273 | RequestStream { 274 | headers: headers, 275 | stream: stream, 276 | } 277 | } 278 | 279 | /// Internal helper method that triggers the client to handle the next 280 | /// frame off the HTTP/2 connection. 281 | #[inline] 282 | fn handle_next_frame(&mut self) -> HttpResult<()> { 283 | self.conn.handle_next_frame(&mut TransportReceiveFrame::new(&mut self.receiver), 284 | &mut self.sender) 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /src/client/tests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for the `solict::client` module. 2 | 3 | #[cfg(feature="live_tests")] 4 | mod simple { 5 | use http::{Response, HttpError}; 6 | use http::client::CleartextConnector; 7 | use client::SimpleClient; 8 | use std::str; 9 | 10 | /// The function establishes a (prior knowledge clear-text TCP) HTTP/2 connection to the given 11 | /// host and GETs the resource at the given paths. Returns a list of responses 12 | fn get(host: &str, paths: &[String]) -> Vec> { 13 | let mut client = SimpleClient::with_connector(CleartextConnector::new(host)).unwrap(); 14 | paths.iter().map(|path| client.get(path.as_bytes(), &[]).unwrap()).collect() 15 | } 16 | 17 | #[test] 18 | fn test_live_get() { 19 | let paths = vec![ 20 | "/get".into(), 21 | "/status/404".into(), 22 | "/status/418".into(), 23 | ]; 24 | let res = get("http2bin.org", &paths); 25 | let statuses: Vec<_> = res.into_iter().map(|r| r.status_code().unwrap()).collect(); 26 | 27 | assert_eq!(statuses, vec![200, 404, 418]); 28 | } 29 | 30 | #[test] 31 | fn test_live_post() { 32 | let host = "http2bin.org"; 33 | let mut client = SimpleClient::with_connector(CleartextConnector::new(host)).unwrap(); 34 | 35 | let res = client.post(b"/post", &[], b"Hello, World!".to_vec()).unwrap(); 36 | 37 | let body = str::from_utf8(&res.body).unwrap(); 38 | assert!(body.contains("Hello, World!")); 39 | } 40 | 41 | /// Tests that `with_connector` returns an error when the connector is unable to establish a 42 | /// new connection. 43 | #[test] 44 | fn test_error_on_connect_failure() { 45 | let connector = CleartextConnector::new("unknown.host.name.lcl"); 46 | let client = SimpleClient::with_connector(connector); 47 | 48 | assert!(client.is_err()); 49 | assert!(match client.err().unwrap() { 50 | HttpError::Other(_) => true, 51 | _ => false, 52 | }); 53 | } 54 | } 55 | 56 | #[cfg(feature="live_tests")] 57 | mod async { 58 | use std::str; 59 | use std::thread; 60 | 61 | use http::Response; 62 | use http::client::CleartextConnector; 63 | use client::Client; 64 | 65 | /// The function establishes a (prior knowledge clear-text TCP) HTTP/2 connection to the given 66 | /// host and GETs the resource at the given paths. Returns a list of responses. 67 | /// 68 | /// The requests are all issued concurrently (spawning as many threads as there are requests). 69 | fn get(host: &str, paths: &[String]) -> Vec> { 70 | let client = Client::with_connector(CleartextConnector::new(host)).unwrap(); 71 | let threads: Vec<_> = paths.iter() 72 | .map(|path| { 73 | let this = client.clone(); 74 | let path = path.clone(); 75 | thread::spawn(move || { 76 | this.get(path.as_bytes(), &[]).unwrap().recv().unwrap() 77 | }) 78 | }) 79 | .collect(); 80 | 81 | threads.into_iter().map(|t| t.join().unwrap()).collect() 82 | } 83 | 84 | #[test] 85 | fn test_live_get() { 86 | let paths = vec![ 87 | "/get".into(), 88 | "/status/404".into(), 89 | "/status/418".into(), 90 | ]; 91 | let res = get("http2bin.org", &paths); 92 | let statuses: Vec<_> = res.into_iter().map(|r| r.status_code().unwrap()).collect(); 93 | 94 | assert_eq!(statuses, vec![200, 404, 418]); 95 | } 96 | 97 | #[test] 98 | fn test_live_post() { 99 | let host = "http2bin.org"; 100 | let client = Client::with_connector(CleartextConnector::new(host)).unwrap(); 101 | 102 | let res = client.post(b"/post", &[], b"Hello, World!".to_vec()).unwrap(); 103 | let res = res.recv().unwrap(); 104 | 105 | let body = str::from_utf8(&res.body).unwrap(); 106 | assert!(body.contains("Hello, World!")); 107 | } 108 | 109 | /// Tests that `with_connector` returns an none when the connector is unable to establish a new 110 | /// connection. 111 | #[test] 112 | fn test_error_on_connect_failure2() { 113 | let connector = CleartextConnector::new("unknown.host.name.lcl"); 114 | let client = Client::with_connector(connector); 115 | 116 | assert!(client.is_err()); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/http/client/tls.rs: -------------------------------------------------------------------------------- 1 | //! The module contains helpers for implementing TLS-based client connections. 2 | //! 3 | //! Available only when the `"tls"` crate feature is enabled. 4 | //! 5 | //! Depends on the `openssl` crate. 6 | //! 7 | //! # Example 8 | //! 9 | //! Establishing a new client connection using the `TlsConnector` and issuing a `GET` request. 10 | //! 11 | //! ```no_run 12 | //! // Remember to enable the "tls" feature for `solicit` 13 | //! use solicit::http::client::tls::TlsConnector; 14 | //! use solicit::client::SimpleClient; 15 | //! use std::str; 16 | //! 17 | //! // Connect to an HTTP/2 aware server 18 | //! let path = "/path/to/certs.pem"; 19 | //! let connector = TlsConnector::new("http2bin.org", &path); 20 | //! let mut client = SimpleClient::with_connector(connector).unwrap(); 21 | //! let response = client.get(b"/get", &[]).unwrap(); 22 | //! assert_eq!(response.stream_id, 1); 23 | //! assert_eq!(response.status_code().unwrap(), 200); 24 | //! // Dump the headers and the response body to stdout. 25 | //! // They are returned as raw bytes for the user to do as they please. 26 | //! // (Note: in general directly decoding assuming a utf8 encoding might not 27 | //! // always work -- this is meant as a simple example that shows that the 28 | //! // response is well formed.) 29 | //! for header in response.headers.iter() { 30 | //! println!("{}: {}", 31 | //! str::from_utf8(header.name()).unwrap(), 32 | //! str::from_utf8(header.value()).unwrap()); 33 | //! } 34 | //! println!("{}", str::from_utf8(&response.body).unwrap()); 35 | //! ``` 36 | 37 | use std::convert::AsRef; 38 | use std::net::TcpStream; 39 | use std::path::Path; 40 | use std::error; 41 | use std::fmt; 42 | use std::str; 43 | use std::io; 44 | use http::{HttpScheme, ALPN_PROTOCOLS}; 45 | 46 | use super::{ClientStream, write_preface, HttpConnect, HttpConnectError}; 47 | 48 | use openssl::ssl::{Ssl, SslStream, SslContext}; 49 | use openssl::ssl::{SSL_VERIFY_PEER, SSL_VERIFY_FAIL_IF_NO_PEER_CERT}; 50 | use openssl::ssl::SSL_OP_NO_COMPRESSION; 51 | use openssl::ssl::error::SslError; 52 | use openssl::ssl::SslMethod; 53 | 54 | /// A struct implementing the functionality of establishing a TLS-backed TCP stream 55 | /// that can be used by an HTTP/2 connection. Takes care to set all the TLS options 56 | /// to those allowed by the HTTP/2 spec, as well as of the protocol negotiation. 57 | /// 58 | /// # Example 59 | /// 60 | /// Issue a GET request over `https` using the `TlsConnector` 61 | /// 62 | /// ```no_run 63 | /// use solicit::http::client::tls::TlsConnector; 64 | /// use solicit::client::SimpleClient; 65 | /// use std::str; 66 | /// 67 | /// // Connect to an HTTP/2 aware server 68 | /// let path = "/path/to/certs.pem"; 69 | /// let connector = TlsConnector::new("http2bin.org", &path); 70 | /// let mut client = SimpleClient::with_connector(connector).unwrap(); 71 | /// let response = client.get(b"/get", &[]).unwrap(); 72 | /// assert_eq!(response.stream_id, 1); 73 | /// assert_eq!(response.status_code().unwrap(), 200); 74 | /// // Dump the headers and the response body to stdout. 75 | /// // They are returned as raw bytes for the user to do as they please. 76 | /// // (Note: in general directly decoding assuming a utf8 encoding might not 77 | /// // always work -- this is meant as a simple example that shows that the 78 | /// // response is well formed.) 79 | /// for header in response.headers.iter() { 80 | /// println!("{}: {}", 81 | /// str::from_utf8(header.name()).unwrap(), 82 | /// str::from_utf8(header.value()).unwrap()); 83 | /// } 84 | /// println!("{}", str::from_utf8(&response.body).unwrap()); 85 | /// ``` 86 | pub struct TlsConnector<'a, 'ctx> { 87 | pub host: &'a str, 88 | context: Http2TlsContext<'ctx>, 89 | } 90 | 91 | /// A private enum that represents the two options for configuring the 92 | /// `TlsConnector` 93 | enum Http2TlsContext<'a> { 94 | /// This means that the `TlsConnector` will use the referenced `SslContext` 95 | /// instance when creating a new `SslStream` 96 | Wrapped(&'a SslContext), 97 | /// This means that the `TlsConnector` will create a new context with the 98 | /// certificates file being found at the given path. 99 | CertPath(&'a Path), 100 | } 101 | 102 | /// An enum representing possible errors that can arise when trying to 103 | /// establish an HTTP/2 connection over TLS. 104 | pub enum TlsConnectError { 105 | /// The variant corresponds to the underlying raw TCP connection returning 106 | /// an error. 107 | IoError(io::Error), 108 | /// The variant corresponds to the TLS negotiation returning an error. 109 | SslError(SslError), 110 | /// The variant corresponds to the case when the TLS connection is 111 | /// established, but the application protocol that was negotiated didn't 112 | /// end up being HTTP/2. 113 | /// It wraps the established SSL stream in order to allow the client to 114 | /// decide what to do with it (and the application protocol that was 115 | /// chosen). 116 | Http2NotSupported(SslStream), 117 | } 118 | 119 | // Note: TcpStream does not implement `Debug` in 1.0.0, so deriving is not possible. 120 | impl fmt::Debug for TlsConnectError { 121 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 122 | // The enum variant... 123 | try!(write!(fmt, 124 | "TlsConnectError::{}", 125 | match *self { 126 | TlsConnectError::IoError(_) => "IoError", 127 | TlsConnectError::SslError(_) => "SslError", 128 | TlsConnectError::Http2NotSupported(_) => "Http2NotSupported", 129 | })); 130 | // ...and the wrapped value, except for when it's the stream. 131 | match *self { 132 | TlsConnectError::IoError(ref err) => try!(write!(fmt, "({:?})", err)), 133 | TlsConnectError::SslError(ref err) => try!(write!(fmt, "({:?})", err)), 134 | TlsConnectError::Http2NotSupported(_) => try!(write!(fmt, "(...)")), 135 | }; 136 | 137 | Ok(()) 138 | } 139 | } 140 | 141 | impl fmt::Display for TlsConnectError { 142 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 143 | write!(fmt, 144 | "TLS HTTP/2 connect error: {}", 145 | (self as &error::Error).description()) 146 | } 147 | } 148 | 149 | impl error::Error for TlsConnectError { 150 | fn description(&self) -> &str { 151 | match *self { 152 | TlsConnectError::IoError(ref err) => err.description(), 153 | TlsConnectError::SslError(ref err) => err.description(), 154 | TlsConnectError::Http2NotSupported(_) => "HTTP/2 not supported by the server", 155 | } 156 | } 157 | 158 | fn cause(&self) -> Option<&error::Error> { 159 | match *self { 160 | TlsConnectError::IoError(ref err) => Some(err), 161 | TlsConnectError::SslError(ref err) => Some(err), 162 | TlsConnectError::Http2NotSupported(_) => None, 163 | } 164 | } 165 | } 166 | 167 | impl From for TlsConnectError { 168 | fn from(err: io::Error) -> TlsConnectError { 169 | TlsConnectError::IoError(err) 170 | } 171 | } 172 | 173 | impl From for TlsConnectError { 174 | fn from(err: SslError) -> TlsConnectError { 175 | TlsConnectError::SslError(err) 176 | } 177 | } 178 | 179 | impl HttpConnectError for TlsConnectError {} 180 | 181 | impl<'a, 'ctx> TlsConnector<'a, 'ctx> { 182 | /// Creates a new `TlsConnector` that will create a new `SslContext` before 183 | /// trying to establish the TLS connection. The path to the CA file that the 184 | /// context will use needs to be provided. 185 | pub fn new>(host: &'a str, ca_file_path: &'ctx P) -> TlsConnector<'a, 'ctx> { 186 | TlsConnector { 187 | host: host, 188 | context: Http2TlsContext::CertPath(ca_file_path.as_ref()), 189 | } 190 | } 191 | 192 | /// Creates a new `TlsConnector` that will use the provided context to 193 | /// create the `SslStream` that will back the HTTP/2 connection. 194 | pub fn with_context(host: &'a str, context: &'ctx SslContext) -> TlsConnector<'a, 'ctx> { 195 | TlsConnector { 196 | host: host, 197 | context: Http2TlsContext::Wrapped(context), 198 | } 199 | } 200 | 201 | /// Builds up a default `SslContext` instance wth TLS settings that the 202 | /// HTTP/2 spec mandates. The path to the CA file needs to be provided. 203 | pub fn build_default_context(ca_file_path: &Path) -> Result { 204 | // HTTP/2 connections need to be on top of TLSv1.2 or newer. 205 | let mut context = try!(SslContext::new(SslMethod::Tlsv1_2)); 206 | 207 | // This makes the certificate required (only VERIFY_PEER would mean optional) 208 | context.set_verify(SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, None); 209 | try!(context.set_CA_file(ca_file_path)); 210 | // Compression is not allowed by the spec 211 | context.set_options(SSL_OP_NO_COMPRESSION); 212 | // The HTTP/2 protocol identifiers are constant at the library level... 213 | context.set_npn_protocols(ALPN_PROTOCOLS); 214 | 215 | Ok(context) 216 | } 217 | } 218 | 219 | impl<'a, 'ctx> HttpConnect for TlsConnector<'a, 'ctx> { 220 | type Stream = SslStream; 221 | type Err = TlsConnectError; 222 | 223 | fn connect(self) -> Result>, TlsConnectError> { 224 | // First, create a TCP connection to port 443 225 | let raw_tcp = try!(TcpStream::connect(&(self.host, 443))); 226 | // Now build the SSL instance, depending on which SSL context should be 227 | // used... 228 | let ssl = match self.context { 229 | Http2TlsContext::CertPath(path) => { 230 | let ctx = try!(TlsConnector::build_default_context(&path)); 231 | try!(Ssl::new(&ctx)) 232 | } 233 | Http2TlsContext::Wrapped(ctx) => try!(Ssl::new(ctx)), 234 | }; 235 | // SNI must be used 236 | try!(ssl.set_hostname(self.host)); 237 | 238 | // Wrap the Ssl instance into an `SslStream` 239 | let mut ssl_stream = try!(SslStream::new_from(ssl, raw_tcp)); 240 | // This connector only understands HTTP/2, so if that wasn't chosen in 241 | // NPN, we raise an error. 242 | let fail = match ssl_stream.get_selected_npn_protocol() { 243 | None => true, 244 | Some(proto) => { 245 | // Make sure that the protocol is one of the HTTP/2 protocols. 246 | debug!("Selected protocol -> {:?}", str::from_utf8(proto)); 247 | let found = ALPN_PROTOCOLS.iter().any(|&http2_proto| http2_proto == proto); 248 | 249 | // We fail if we don't find an HTTP/2 protcol match... 250 | !found 251 | } 252 | }; 253 | if fail { 254 | // We need the fail flag (instead of returning from one of the match 255 | // arms above because we need to move the `ssl_stream` and that is 256 | // not possible above (since it's borrowed at that point). 257 | return Err(TlsConnectError::Http2NotSupported(ssl_stream)); 258 | } 259 | 260 | // Now that the stream is correctly established, we write the client preface. 261 | try!(write_preface(&mut ssl_stream)); 262 | 263 | // All done. 264 | Ok(ClientStream(ssl_stream, HttpScheme::Https, self.host.into())) 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/http/frame/builder.rs: -------------------------------------------------------------------------------- 1 | //! Defines the `FrameBuilder` trait and some default implementations of the trait. 2 | 3 | use std::io; 4 | use http::frame::{FrameHeader, pack_header}; 5 | 6 | /// A trait that provides additional methods for serializing HTTP/2 frames. 7 | /// 8 | /// All methods have a default implementation in terms of the `io::Write` API, but types can 9 | /// provide specialized more efficient implementations if possible. This is effectively a 10 | /// workaround for specialization not existing yet in Rust. 11 | pub trait FrameBuilder: io::Write + io::Seek { 12 | /// Write the given frame header as the next octets (i.e. without moving the cursor to the 13 | /// beginning of the buffer). 14 | fn write_header(&mut self, header: FrameHeader) -> io::Result<()> { 15 | self.write_all(&pack_header(&header)) 16 | } 17 | 18 | /// Overwrite the previously written header, assuming it's the first byte sequence of the 19 | /// buffer. 20 | /// 21 | /// The default implementation seeks to the beginning of the buffer, writes the header, and 22 | /// then moves the cursor back to its previos position (i.e. offset from the beginning). 23 | fn overwrite_header(&mut self, header: FrameHeader) -> io::Result<()> { 24 | let current = try!(self.seek(io::SeekFrom::Current(0))); 25 | try!(self.seek(io::SeekFrom::Start(0))); 26 | try!(self.write_header(header)); 27 | try!(self.seek(io::SeekFrom::Start(current))); 28 | Ok(()) 29 | } 30 | 31 | /// Copy all available bytes from the given `io::Read` instance. 32 | /// 33 | /// This method allows poor man's specialization for types that can implement the copy more 34 | /// efficiently than the `io::copy` function does (i.e. without the intermediate read into a 35 | /// stack-allocated buffer). 36 | fn copy_bytes_from(&mut self, provider: &mut R) -> io::Result 37 | where Self: Sized 38 | { 39 | io::copy(provider, self) 40 | } 41 | 42 | /// Write the given number of padding octets. 43 | /// 44 | /// The default implementation invokes the underlying Writer's `write` method `padding_length` 45 | /// times. 46 | /// 47 | /// Other `FrameBuilder` implementations could implement it more efficiently (e.g. if it is 48 | /// known that the `FrameBuilder` is backed by a zeroed buffer, there's no need to write 49 | /// anything, only increment a cursor/offset). 50 | fn write_padding(&mut self, padding_length: u8) -> io::Result<()> { 51 | for _ in 0..padding_length { 52 | try!(self.write_all(&[0])); 53 | } 54 | Ok(()) 55 | } 56 | 57 | /// Write the given unsigned 32 bit integer to the underlying stream. The integer is written as 58 | /// four bytes in network endian style. 59 | fn write_u32(&mut self, num: u32) -> io::Result<()> { 60 | self.write_all(&[(((num >> 24) & 0x000000FF) as u8), 61 | (((num >> 16) & 0x000000FF) as u8), 62 | (((num >> 8) & 0x000000FF) as u8), 63 | (((num ) & 0x000000FF) as u8)]) 64 | } 65 | } 66 | 67 | impl FrameBuilder for io::Cursor> {} 68 | 69 | #[cfg(test)] 70 | mod tests { 71 | use super::FrameBuilder; 72 | use std::io::{self, Write}; 73 | use http::frame::pack_header; 74 | 75 | #[test] 76 | fn test_write_header_empty_buffer() { 77 | let mut buf = io::Cursor::new(Vec::new()); 78 | let header = (10, 0x1, 0x0, 3); 79 | let expected = pack_header(&header); 80 | 81 | buf.write_header(header).unwrap(); 82 | 83 | let frame = buf.into_inner(); 84 | assert_eq!(frame, expected); 85 | } 86 | 87 | #[test] 88 | fn test_write_header_and_payload_empty() { 89 | let mut buf = io::Cursor::new(Vec::new()); 90 | let header = (10, 0x1, 0x0, 3); 91 | let expected = { 92 | let mut buf = Vec::new(); 93 | buf.extend(pack_header(&header).to_vec()); 94 | buf.extend(vec![1, 2, 3, 4]); 95 | buf 96 | }; 97 | 98 | buf.write_header(header).unwrap(); 99 | buf.write_all(&[1, 2, 3, 4]).unwrap(); 100 | 101 | let frame = buf.into_inner(); 102 | assert_eq!(frame, expected); 103 | } 104 | 105 | #[test] 106 | fn test_rewrite_header_after_payload() { 107 | let mut buf = io::Cursor::new(Vec::new()); 108 | let original_header = (10, 0x1, 0x0, 3); 109 | let actual_header = (5, 0x0, 0x0, 5); 110 | let expected = { 111 | let mut buf = Vec::new(); 112 | buf.extend(pack_header(&actual_header).to_vec()); 113 | buf.extend(vec![1, 2, 3, 4]); 114 | buf 115 | }; 116 | 117 | // Sanity check for the test: the two headers must be different! 118 | assert!(original_header != actual_header); 119 | // First one header... 120 | buf.write_header(original_header).unwrap(); 121 | // Then some payload... 122 | buf.write_all(&[1, 2, 3]).unwrap(); 123 | // Now change the header! 124 | buf.overwrite_header(actual_header).unwrap(); 125 | // ...and add some more data to the end 126 | buf.write_all(&[4]).unwrap(); 127 | 128 | let frame = buf.into_inner(); 129 | assert_eq!(frame, expected); 130 | } 131 | 132 | #[test] 133 | fn test_write_padding() { 134 | let mut buf = io::Cursor::new(Vec::new()); 135 | buf.write_padding(5).unwrap(); 136 | 137 | assert_eq!(buf.into_inner(), vec![0; 5]); 138 | } 139 | 140 | #[test] 141 | fn test_write_u32() { 142 | fn get_written(num: u32) -> Vec { 143 | let mut buf = io::Cursor::new(Vec::new()); 144 | buf.write_u32(num).unwrap(); 145 | buf.into_inner() 146 | } 147 | 148 | assert_eq!(get_written(0x0), vec![0, 0, 0, 0]); 149 | assert_eq!(get_written(0x1), vec![0, 0, 0, 1]); 150 | assert_eq!(get_written(0x10), vec![0, 0, 0, 0x10]); 151 | assert_eq!(get_written(0x10AB00CC), vec![0x10, 0xAB, 0, 0xCC]); 152 | assert_eq!(get_written(0xFFFFFFFF), vec![0xFF, 0xFF, 0xFF, 0xFF]); 153 | assert_eq!(get_written(0xEFFFFFFF), vec![0xEF, 0xFF, 0xFF, 0xFF]); 154 | assert_eq!(get_written(0x7FFFFFFF), vec![0x7F, 0xFF, 0xFF, 0xFF]); 155 | assert_eq!(get_written(0xFFFFFF7F), vec![0xFF, 0xFF, 0xFF, 0x7F]); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/http/frame/data.rs: -------------------------------------------------------------------------------- 1 | //! The module contains the implementation of the `DATA` frame and associated flags. 2 | 3 | use std::io; 4 | use std::borrow::Cow; 5 | use http::StreamId; 6 | use http::frame::{FrameBuilder, FrameIR, Flag, Frame, FrameHeader, RawFrame, parse_padded_payload}; 7 | 8 | /// An enum representing the flags that a `DataFrame` can have. 9 | /// The integer representation associated to each variant is that flag's 10 | /// bitmask. 11 | /// 12 | /// HTTP/2 spec, section 6.1. 13 | #[derive(Clone)] 14 | #[derive(PartialEq)] 15 | #[derive(Debug)] 16 | #[derive(Copy)] 17 | pub enum DataFlag { 18 | EndStream = 0x1, 19 | Padded = 0x8, 20 | } 21 | 22 | impl Flag for DataFlag { 23 | #[inline] 24 | fn bitmask(&self) -> u8 { 25 | *self as u8 26 | } 27 | } 28 | 29 | /// A helper struct that allows the chunk to be either borrowed or owned. Used to provide the 30 | /// `From` implementations that allow us to implement generic methods that accept any type that can 31 | /// be converted into a `DataChunk` (given that the native `Cow` type does not have these 32 | /// implementations and we cannot add them). 33 | pub struct DataChunk<'a>(Cow<'a, [u8]>); 34 | impl<'a> From> for DataChunk<'a> { 35 | fn from(vec: Vec) -> DataChunk<'a> { 36 | DataChunk(Cow::Owned(vec)) 37 | } 38 | } 39 | impl<'a> From<&'a [u8]> for DataChunk<'a> { 40 | fn from(buf: &'a [u8]) -> DataChunk<'a> { 41 | DataChunk(Cow::Borrowed(buf)) 42 | } 43 | } 44 | 45 | /// A struct representing the DATA frames of HTTP/2, as defined in the HTTP/2 46 | /// spec, section 6.1. 47 | #[derive(PartialEq)] 48 | #[derive(Debug)] 49 | #[derive(Clone)] 50 | pub struct DataFrame<'a> { 51 | /// The data found in the frame as an opaque byte sequence. It never 52 | /// includes padding bytes. 53 | pub data: Cow<'a, [u8]>, 54 | /// Represents the flags currently set on the `DataFrame`, packed into a 55 | /// single byte. 56 | flags: u8, 57 | /// The ID of the stream with which the frame is associated. 58 | stream_id: StreamId, 59 | /// The length of the padding applied to the data. Since the spec defines 60 | /// that the padding length is at most an unsigned integer value, we also 61 | /// keep a `u8`, instead of a `usize`. 62 | padding_len: Option, 63 | } 64 | 65 | impl<'a> DataFrame<'a> { 66 | /// Creates a new empty `DataFrame`, associated to the stream with the 67 | /// given ID. 68 | pub fn new(stream_id: StreamId) -> DataFrame<'a> { 69 | DataFrame { 70 | stream_id: stream_id, 71 | // All flags unset by default 72 | flags: 0, 73 | // No data stored in the frame yet 74 | data: Cow::Borrowed(&[]), 75 | // No padding 76 | padding_len: None, 77 | } 78 | } 79 | 80 | /// Creates a new `DataFrame` with the given `DataChunk`. 81 | /// 82 | /// The chunk can be any type that can be converted into a `DataChunk` instance and, as such, 83 | /// can either pass ownership of the buffer to the DataFrame or provide a temporary borrow. 84 | pub fn with_data>>(stream_id: StreamId, data: D) -> DataFrame<'a> { 85 | DataFrame { 86 | stream_id: stream_id, 87 | flags: 0, 88 | data: data.into().0, 89 | padding_len: None, 90 | } 91 | } 92 | 93 | /// Returns `true` if the DATA frame is padded, otherwise false. 94 | pub fn is_padded(&self) -> bool { 95 | self.is_set(DataFlag::Padded) 96 | } 97 | 98 | /// Returns whther this frame ends the stream it is associated with. 99 | pub fn is_end_of_stream(&self) -> bool { 100 | self.is_set(DataFlag::EndStream) 101 | } 102 | 103 | /// Sets the number of bytes that should be used as padding for this 104 | /// frame. 105 | pub fn set_padding(&mut self, pad_len: u8) { 106 | self.set_flag(DataFlag::Padded); 107 | self.padding_len = Some(pad_len); 108 | } 109 | 110 | /// Returns the total length of the payload, taking into account possible 111 | /// padding. 112 | pub fn payload_len(&self) -> u32 { 113 | if self.is_padded() { 114 | 1 + (self.data.len() as u32) + (self.padding_len.unwrap_or(0) as u32) 115 | } else { 116 | // Downcasting here is all right, because the HTTP/2 frames cannot 117 | // have a length larger than a 32 bit unsigned integer. 118 | self.data.len() as u32 119 | } 120 | } 121 | 122 | /// Parses the given slice as a DATA frame's payload. Depending on the 123 | /// `padded` flag, it will treat the given bytes as a data frame with 124 | /// padding or without. 125 | /// 126 | /// # Returns 127 | /// 128 | /// A tuple wrapped in the `Some` variant, representing the true data and 129 | /// the original padding length. 130 | /// If there was no padding, returns `None` for the second tuple member. 131 | /// 132 | /// If the payload was invalid for a DATA frame, returns `None` 133 | fn parse_payload(payload: &[u8], padded: bool) -> Option<(&[u8], Option)> { 134 | let (data, pad_len) = if padded { 135 | match parse_padded_payload(payload) { 136 | Some((data, pad_len)) => (data, Some(pad_len)), 137 | None => return None, 138 | } 139 | } else { 140 | (payload, None) 141 | }; 142 | 143 | Some((data, pad_len)) 144 | } 145 | 146 | /// Sets the given flag for the frame. 147 | pub fn set_flag(&mut self, flag: DataFlag) { 148 | self.flags |= flag.bitmask(); 149 | } 150 | } 151 | 152 | impl<'a> Frame<'a> for DataFrame<'a> { 153 | type FlagType = DataFlag; 154 | 155 | /// Creates a new `DataFrame` from the given `RawFrame` (i.e. header and 156 | /// payload), if possible. Returns `None` if a valid `DataFrame` cannot be 157 | /// constructed from the given `RawFrame`. 158 | fn from_raw(raw_frame: &'a RawFrame<'a>) -> Option> { 159 | // Unpack the header 160 | let (len, frame_type, flags, stream_id) = raw_frame.header(); 161 | // Check that the frame type is correct for this frame implementation 162 | if frame_type != 0x0 { 163 | return None; 164 | } 165 | // Check that the length given in the header matches the payload 166 | // length; if not, something went wrong and we do not consider this a 167 | // valid frame. 168 | if (len as usize) != raw_frame.payload().len() { 169 | return None; 170 | } 171 | // A DATA frame cannot be associated to the connection itself. 172 | if stream_id == 0x0 { 173 | return None; 174 | } 175 | // No validation is required for the flags, since according to the spec, 176 | // unknown flags MUST be ignored. 177 | // Everything has been validated so far: try to extract the data from 178 | // the payload. 179 | let padded = (flags & DataFlag::Padded.bitmask()) != 0; 180 | match DataFrame::parse_payload(raw_frame.payload(), padded) { 181 | Some((data, Some(padding_len))) => { 182 | // The data got extracted (from a padded frame) 183 | Some(DataFrame { 184 | stream_id: stream_id, 185 | flags: flags, 186 | data: Cow::Borrowed(data), 187 | padding_len: Some(padding_len), 188 | }) 189 | } 190 | Some((data, None)) => { 191 | // The data got extracted (from a no-padding frame) 192 | Some(DataFrame { 193 | stream_id: stream_id, 194 | flags: flags, 195 | data: Cow::Borrowed(data), 196 | padding_len: None, 197 | }) 198 | } 199 | None => None, 200 | } 201 | } 202 | 203 | /// Tests if the given flag is set for the frame. 204 | fn is_set(&self, flag: DataFlag) -> bool { 205 | (self.flags & flag.bitmask()) != 0 206 | } 207 | 208 | /// Returns the `StreamId` of the stream to which the frame is associated. 209 | fn get_stream_id(&self) -> StreamId { 210 | self.stream_id 211 | } 212 | 213 | /// Returns a `FrameHeader` based on the current state of the frame. 214 | fn get_header(&self) -> FrameHeader { 215 | (self.payload_len(), 0x0, self.flags, self.stream_id) 216 | } 217 | } 218 | 219 | impl<'a> FrameIR for DataFrame<'a> { 220 | fn serialize_into(self, b: &mut B) -> io::Result<()> { 221 | try!(b.write_header(self.get_header())); 222 | if self.is_padded() { 223 | let pad_len = self.padding_len.unwrap_or(0); 224 | try!(b.write_all(&[pad_len])); 225 | try!(b.write_all(&self.data)); 226 | try!(b.write_padding(pad_len)); 227 | } else { 228 | try!(b.write_all(&self.data)); 229 | } 230 | Ok(()) 231 | } 232 | } 233 | 234 | #[cfg(test)] 235 | mod tests { 236 | use super::{DataFlag, DataFrame}; 237 | use http::frame::tests::build_padded_frame_payload; 238 | use http::tests::common::{raw_frame_from_parts, serialize_frame}; 239 | use http::frame::{pack_header, Frame}; 240 | 241 | /// Tests that the `DataFrame` struct correctly interprets a DATA frame 242 | /// with no padding set. 243 | #[test] 244 | fn test_data_frame_parse_no_padding() { 245 | let data = b"asdf"; 246 | let payload = data.to_vec(); 247 | // A header with the flag indicating no padding 248 | let header = (payload.len() as u32, 0u8, 0u8, 1u32); 249 | 250 | let raw = raw_frame_from_parts(header.clone(), payload.to_vec()); 251 | let frame: DataFrame = Frame::from_raw(&raw).unwrap(); 252 | 253 | // The frame correctly returns the data? 254 | assert_eq!(&frame.data[..], &data[..]); 255 | // ...and the headers? 256 | assert_eq!(frame.get_header(), header); 257 | } 258 | 259 | /// Tests that the `DataFrame` struct correctly knows when it represents the end of the 260 | /// corresponding stream. 261 | #[test] 262 | fn test_data_frame_is_end_of_stream() { 263 | let mut frame = DataFrame::new(1); 264 | assert!(!frame.is_end_of_stream()); 265 | frame.set_flag(DataFlag::EndStream); 266 | assert!(frame.is_end_of_stream()); 267 | } 268 | 269 | /// Tests that the `DataFrame` struct correctly interprets a DATA frame 270 | /// with a number of padding bytes set. 271 | #[test] 272 | fn test_data_frame_padded() { 273 | let data = b"asdf"; 274 | let payload = build_padded_frame_payload(data, 5); 275 | // A header with the flag indicating padding 276 | let header = (payload.len() as u32, 0u8, 8u8, 1u32); 277 | 278 | let raw = raw_frame_from_parts(header.clone(), payload.to_vec()); 279 | let frame: DataFrame = Frame::from_raw(&raw).unwrap(); 280 | 281 | // The frame correctly returns the data? 282 | assert_eq!(&frame.data[..], &data[..]); 283 | // ...and the headers? 284 | assert_eq!(frame.get_header(), header); 285 | } 286 | 287 | /// Tests that a DATA frame with a zero-length payload is still considered 288 | /// valid. 289 | /// 290 | /// There doesn't seem to be anything in the spec that would make it invalid. 291 | /// The spec says that frames are considered invalid if their size is too 292 | /// small to contain all the mandatory parts of the frame of a particular 293 | /// type. Since the DATA frame does not have any mandatory fields (of size 294 | /// greater than 1), a zero-len payload should be all right. 295 | #[test] 296 | fn test_data_frame_zero_len_payload() { 297 | let data = b""; 298 | let payload = data.to_vec(); 299 | // A header with the flag indicating no padding 300 | let header = (payload.len() as u32, 0u8, 0u8, 1u32); 301 | 302 | let raw = raw_frame_from_parts(header.clone(), payload.to_vec()); 303 | let frame: DataFrame = Frame::from_raw(&raw).unwrap(); 304 | 305 | // The frame correctly returns the data? 306 | assert_eq!(&frame.data[..], &data[..]); 307 | // ...and the headers? 308 | assert_eq!(frame.get_header(), header); 309 | } 310 | 311 | /// Tests that the `DataFrame` struct correctly handles the case where the 312 | /// padding is invalid: the size of the padding given is greater than or 313 | /// equal to the total size of the frame. 314 | #[test] 315 | fn test_data_frame_padding_invalid() { 316 | let payload = vec![5, b'a', b's', b'd', b'f']; 317 | // A header with the flag indicating padding 318 | let header = (payload.len() as u32, 0u8, 8u8, 1u32); 319 | 320 | let raw = raw_frame_from_parts(header, payload); 321 | let frame: Option = Frame::from_raw(&raw); 322 | 323 | // The frame was not even created since the raw bytes are invalid 324 | assert!(frame.is_none()) 325 | } 326 | 327 | /// Tests that if a frame that should be parsed has a stream ID of 0, it is 328 | /// not considered a valid DATA frame. 329 | #[test] 330 | fn test_data_frame_stream_zero() { 331 | let data = b"asdf"; 332 | let payload = data.to_vec(); 333 | // Stream 0 334 | let header = (payload.len() as u32, 0u8, 0u8, 0u32); 335 | 336 | let raw = raw_frame_from_parts(header, payload.to_vec()); 337 | let frame: Option = Frame::from_raw(&raw); 338 | 339 | // The frame is not valid. 340 | assert!(frame.is_none()); 341 | } 342 | 343 | /// Tests that the `DataFrame` struct correctly interprets a DATA frame 344 | /// with no padding and no data. 345 | #[test] 346 | fn test_data_frame_no_padding_empty() { 347 | let payload = []; 348 | let header = (payload.len() as u32, 0u8, 0u8, 1u32); 349 | 350 | let raw = raw_frame_from_parts(header.clone(), payload.to_vec()); 351 | let frame: DataFrame = Frame::from_raw(&raw).unwrap(); 352 | 353 | // The frame correctly returns the data -- i.e. an empty array? 354 | assert_eq!(&frame.data[..], &[][..]); 355 | // ...and the headers? 356 | assert_eq!(frame.get_header(), header); 357 | } 358 | 359 | /// Tests that the `DataFrame` struct correctly interprets a DATA frame 360 | /// with padding, but an empty payload. 361 | #[test] 362 | fn test_data_frame_padding_empty_payload() { 363 | let payload = vec![]; 364 | let header = (payload.len() as u32, 0u8, 8u8, 1u32); 365 | 366 | let raw = raw_frame_from_parts(header, payload); 367 | let frame: Option = Frame::from_raw(&raw); 368 | 369 | // In this case, we cannot receive a frame, since the payload did not 370 | // contain even the first byte, necessary to find the padding length. 371 | assert!(frame.is_none()); 372 | } 373 | 374 | /// Tests that the `DataFrame` struct correctly interprets a DATA frame 375 | /// with padding of size 0. 376 | #[test] 377 | fn test_data_frame_null_padding() { 378 | let data = b"test string"; 379 | let payload = build_padded_frame_payload(data, 0); 380 | // A header with the flag indicating padding 381 | let header = (payload.len() as u32, 0u8, 8u8, 1u32); 382 | 383 | let raw = raw_frame_from_parts(header.clone(), payload.to_vec()); 384 | let frame: DataFrame = Frame::from_raw(&raw).unwrap(); 385 | 386 | // The frame correctly returns the data? 387 | assert_eq!(&frame.data[..], &data[..]); 388 | // ...and the headers? 389 | assert_eq!(frame.get_header(), header); 390 | } 391 | 392 | /// Tests that the `DataFrame` struct correctly handles the situation 393 | /// where the header does not contain a frame type corresponding to the 394 | /// DATA frame type. 395 | #[test] 396 | fn test_data_frame_invalid_type() { 397 | let data = b"dummy"; 398 | let payload = build_padded_frame_payload(data, 0); 399 | // The header has an invalid type (0x1 instead of 0x0). 400 | let header = (payload.len() as u32, 1u8, 8u8, 1u32); 401 | 402 | let raw = raw_frame_from_parts(header, payload); 403 | let frame: Option = Frame::from_raw(&raw); 404 | 405 | assert!(frame.is_none()); 406 | } 407 | 408 | /// Tests that `DataFrame`s get correctly serialized when created with no 409 | /// padding and with no data. 410 | #[test] 411 | fn test_data_frame_serialize_no_padding_empty() { 412 | let frame = DataFrame::new(1); 413 | let expected = { 414 | let headers = pack_header(&(0, 0, 0, 1)); 415 | let mut res: Vec = Vec::new(); 416 | res.extend(headers.to_vec()); 417 | 418 | res 419 | }; 420 | 421 | let serialized = serialize_frame(&frame); 422 | 423 | assert_eq!(serialized, expected); 424 | } 425 | 426 | /// Tests that `DataFrame`s get correctly serialized when created with no 427 | /// padding and with some amount of data. 428 | #[test] 429 | fn test_data_frame_serialize_no_padding() { 430 | let data = vec![1, 2, 3, 4, 5, 100]; 431 | let frame = DataFrame::with_data(1, &data[..]); 432 | let expected = { 433 | let headers = pack_header(&(6, 0, 0, 1)); 434 | let mut res: Vec = Vec::new(); 435 | res.extend(headers.to_vec()); 436 | res.extend(data.clone()); 437 | 438 | res 439 | }; 440 | 441 | let serialized = serialize_frame(&frame); 442 | 443 | assert_eq!(serialized, expected); 444 | } 445 | 446 | /// Tests that `DataFrame`s get correctly serialized when created with 447 | /// some amount of padding and some data. 448 | #[test] 449 | fn test_data_frame_serialize_padding() { 450 | let data = vec![1, 2, 3, 4, 5, 100]; 451 | let mut frame = DataFrame::with_data(1, &data[..]); 452 | frame.set_padding(5); 453 | let expected = { 454 | let headers = pack_header(&(6 + 1 + 5, 0, 8, 1)); 455 | let mut res: Vec = Vec::new(); 456 | // Headers 457 | res.extend(headers.to_vec()); 458 | // Padding len 459 | res.push(5); 460 | // Data 461 | res.extend(data.clone()); 462 | // Actual padding 463 | for _ in 0..5 { 464 | res.push(0); 465 | } 466 | 467 | res 468 | }; 469 | 470 | let serialized = serialize_frame(&frame); 471 | 472 | assert_eq!(serialized, expected); 473 | } 474 | 475 | /// Tests that `DataFrame`s get correctly serialized when created with 476 | /// 0 padding. This is a distinct case from having *no padding*. 477 | #[test] 478 | fn test_data_frame_serialize_null_padding() { 479 | let data = vec![1, 2, 3, 4, 5, 100]; 480 | let cloned = data.clone(); 481 | let mut frame = DataFrame::with_data(1, data); 482 | frame.set_flag(DataFlag::Padded); 483 | let expected = { 484 | let headers = pack_header(&(6 + 1, 0, 8, 1)); 485 | let mut res: Vec = Vec::new(); 486 | // Headers 487 | res.extend(headers.to_vec()); 488 | // Padding len 489 | res.push(0); 490 | // Data 491 | res.extend(cloned); 492 | 493 | res 494 | }; 495 | 496 | let serialized = serialize_frame(&frame); 497 | 498 | assert_eq!(serialized, expected); 499 | } 500 | } 501 | -------------------------------------------------------------------------------- /src/http/frame/goaway.rs: -------------------------------------------------------------------------------- 1 | //! Implements the `GOAWAY` HTTP/2 frame. 2 | 3 | use std::io; 4 | 5 | use http::{ErrorCode, StreamId}; 6 | use http::frame::{Frame, FrameIR, FrameBuilder, FrameHeader, RawFrame, NoFlag, parse_stream_id}; 7 | 8 | /// The minimum size for the `GOAWAY` frame payload. 9 | /// It is 8 octets, as the last stream id and error code are required parts of the GOAWAY frame. 10 | pub const GOAWAY_MIN_FRAME_LEN: u32 = 8; 11 | /// The frame type of the `GOAWAY` frame. 12 | pub const GOAWAY_FRAME_TYPE: u8 = 0x7; 13 | 14 | /// The struct represents the `GOAWAY` HTTP/2 frame. 15 | #[derive(Clone, Debug, PartialEq)] 16 | pub struct GoawayFrame<'a> { 17 | last_stream_id: StreamId, 18 | raw_error_code: u32, 19 | debug_data: Option<&'a [u8]>, 20 | flags: u8, 21 | } 22 | 23 | impl<'a> GoawayFrame<'a> { 24 | /// Create a new `GOAWAY` frame with the given error code and no debug data. 25 | pub fn new(last_stream_id: StreamId, error_code: ErrorCode) -> Self { 26 | GoawayFrame { 27 | last_stream_id: last_stream_id, 28 | raw_error_code: error_code.into(), 29 | debug_data: None, 30 | flags: 0, 31 | } 32 | } 33 | 34 | /// Create a new `GOAWAY` frame with the given parts. 35 | pub fn with_debug_data(last_stream_id: StreamId, raw_error: u32, debug_data: &'a [u8]) -> Self { 36 | GoawayFrame { 37 | last_stream_id: last_stream_id, 38 | raw_error_code: raw_error, 39 | debug_data: Some(debug_data), 40 | flags: 0, 41 | } 42 | } 43 | 44 | /// Returns the interpreted error code of the frame. Any unknown error codes are mapped into 45 | /// the `InternalError` variant of the enum. 46 | pub fn error_code(&self) -> ErrorCode { 47 | self.raw_error_code.into() 48 | } 49 | 50 | /// Returns the original raw error code of the frame. If the code is unknown, it will not be 51 | /// changed. 52 | pub fn raw_error_code(&self) -> u32 { 53 | self.raw_error_code 54 | } 55 | 56 | /// Returns the associated last stream ID. 57 | pub fn last_stream_id(&self) -> StreamId { 58 | self.last_stream_id 59 | } 60 | 61 | /// Returns the debug data associated with the frame. 62 | pub fn debug_data(&self) -> Option<&[u8]> { 63 | self.debug_data 64 | } 65 | 66 | /// Returns the total length of the frame's payload, including any debug data. 67 | pub fn payload_len(&self) -> u32 { 68 | GOAWAY_MIN_FRAME_LEN + self.debug_data.map_or(0, |d| d.len() as u32) 69 | } 70 | } 71 | 72 | impl<'a> Frame<'a> for GoawayFrame<'a> { 73 | type FlagType = NoFlag; 74 | 75 | fn from_raw(raw_frame: &'a RawFrame<'a>) -> Option { 76 | let (payload_len, frame_type, flags, stream_id) = raw_frame.header(); 77 | if payload_len < GOAWAY_MIN_FRAME_LEN { 78 | return None; 79 | } 80 | if frame_type != GOAWAY_FRAME_TYPE { 81 | return None; 82 | } 83 | if stream_id != 0x0 { 84 | return None; 85 | } 86 | 87 | let last_stream_id = parse_stream_id(raw_frame.payload()); 88 | let error = unpack_octets_4!(raw_frame.payload(), 4, u32); 89 | let debug_data = if payload_len > GOAWAY_MIN_FRAME_LEN { 90 | Some(&raw_frame.payload()[GOAWAY_MIN_FRAME_LEN as usize..]) 91 | } else { 92 | None 93 | }; 94 | 95 | Some(GoawayFrame { 96 | last_stream_id: last_stream_id, 97 | raw_error_code: error, 98 | debug_data: debug_data, 99 | flags: flags, 100 | }) 101 | } 102 | 103 | fn is_set(&self, _: NoFlag) -> bool { 104 | false 105 | } 106 | fn get_stream_id(&self) -> StreamId { 107 | 0 108 | } 109 | fn get_header(&self) -> FrameHeader { 110 | (self.payload_len(), GOAWAY_FRAME_TYPE, self.flags, 0) 111 | } 112 | } 113 | 114 | impl<'a> FrameIR for GoawayFrame<'a> { 115 | fn serialize_into(self, builder: &mut B) -> io::Result<()> { 116 | try!(builder.write_header(self.get_header())); 117 | try!(builder.write_u32(self.last_stream_id)); 118 | try!(builder.write_u32(self.raw_error_code)); 119 | if let Some(buf) = self.debug_data { 120 | try!(builder.write_all(buf)); 121 | } 122 | Ok(()) 123 | } 124 | } 125 | 126 | #[cfg(test)] 127 | mod tests { 128 | use super::GoawayFrame; 129 | 130 | use http::tests::common::{serialize_frame, raw_frame_from_parts}; 131 | use http::ErrorCode; 132 | use http::frame::Frame; 133 | 134 | #[test] 135 | fn test_parse_valid_no_debug_data() { 136 | let raw = raw_frame_from_parts((8, 0x7, 0, 0), vec![0, 0, 0, 0, 0, 0, 0, 1]); 137 | let frame = GoawayFrame::from_raw(&raw).expect("Expected successful parse"); 138 | assert_eq!(frame.error_code(), ErrorCode::ProtocolError); 139 | assert_eq!(frame.last_stream_id(), 0); 140 | assert_eq!(frame.debug_data(), None); 141 | } 142 | 143 | #[test] 144 | fn test_parse_valid_no_debug_data_2() { 145 | let raw = raw_frame_from_parts((8, 0x7, 0, 0), vec![0, 0, 1, 0, 0, 0, 0, 1]); 146 | let frame = GoawayFrame::from_raw(&raw).expect("Expected successful parse"); 147 | assert_eq!(frame.error_code(), ErrorCode::ProtocolError); 148 | assert_eq!(frame.last_stream_id(), 0x00000100); 149 | assert_eq!(frame.debug_data(), None); 150 | } 151 | 152 | #[test] 153 | fn test_parse_valid_with_debug_data() { 154 | let raw = raw_frame_from_parts((12, 0x7, 0, 0), vec![0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4]); 155 | let frame = GoawayFrame::from_raw(&raw).expect("Expected successful parse"); 156 | assert_eq!(frame.error_code(), ErrorCode::ProtocolError); 157 | assert_eq!(frame.last_stream_id(), 0); 158 | assert_eq!(frame.debug_data(), Some(&[1, 2, 3, 4][..])); 159 | } 160 | 161 | #[test] 162 | fn test_parse_ignores_reserved_bit() { 163 | let raw = raw_frame_from_parts((8, 0x7, 0, 0), vec![0x80, 0, 0, 0, 0, 0, 0, 1]); 164 | let frame = GoawayFrame::from_raw(&raw).expect("Expected successful parse"); 165 | assert_eq!(frame.error_code(), ErrorCode::ProtocolError); 166 | assert_eq!(frame.last_stream_id(), 0); 167 | assert_eq!(frame.debug_data(), None); 168 | } 169 | 170 | #[test] 171 | fn test_parse_invalid_id() { 172 | let raw = raw_frame_from_parts((12, 0x1, 0, 0), vec![0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4]); 173 | assert!(GoawayFrame::from_raw(&raw).is_none(), "expected invalid id"); 174 | } 175 | 176 | #[test] 177 | fn test_parse_invalid_stream_id() { 178 | let raw = raw_frame_from_parts((8, 0x7, 0, 3), vec![0, 0, 0, 0, 0, 0, 0, 1]); 179 | assert!(GoawayFrame::from_raw(&raw).is_none(), 180 | "expected invalid stream id"); 181 | } 182 | 183 | #[test] 184 | fn test_parse_invalid_length() { 185 | // Too short! 186 | let raw = raw_frame_from_parts((7, 0x1, 0, 0), vec![0, 0, 0, 0, 0, 0, 1]); 187 | assert!(GoawayFrame::from_raw(&raw).is_none(), "expected too short"); 188 | } 189 | 190 | #[test] 191 | fn test_serialize_no_debug_data() { 192 | let frame = GoawayFrame::new(0, ErrorCode::ProtocolError); 193 | let expected: Vec = raw_frame_from_parts((8, 0x7, 0, 0), vec![0, 0, 0, 0, 0, 0, 0, 1]) 194 | .into(); 195 | let raw = serialize_frame(&frame); 196 | 197 | assert_eq!(expected, raw); 198 | } 199 | 200 | #[test] 201 | fn test_serialize_with_debug_data() { 202 | let frame = GoawayFrame::with_debug_data(0, ErrorCode::ProtocolError.into(), b"Hi!"); 203 | let expected: Vec = raw_frame_from_parts((11, 0x7, 0, 0), 204 | vec![0, 0, 0, 0, 0, 0, 0, 1, b'H', b'i', 205 | b'!']) 206 | .into(); 207 | let raw = serialize_frame(&frame); 208 | 209 | assert_eq!(expected, raw); 210 | } 211 | 212 | #[test] 213 | fn test_serialize_raw_error() { 214 | let frame = GoawayFrame::with_debug_data(1, 0x0001AA, &[]); 215 | let expected: Vec = raw_frame_from_parts((8, 0x7, 0, 0), 216 | vec![0, 0, 0, 1, 0, 0, 0x1, 0xAA]) 217 | .into(); 218 | let raw = serialize_frame(&frame); 219 | 220 | assert_eq!(expected, raw); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/http/frame/headers.rs: -------------------------------------------------------------------------------- 1 | //! The module contains the implementation of the `HEADERS` frame and associated flags. 2 | 3 | use std::io; 4 | use std::borrow::Cow; 5 | 6 | use http::StreamId; 7 | use http::frame::{FrameBuilder, FrameIR, Flag, Frame, FrameHeader, RawFrame, parse_padded_payload}; 8 | 9 | /// An enum representing the flags that a `HeadersFrame` can have. 10 | /// The integer representation associated to each variant is that flag's 11 | /// bitmask. 12 | /// 13 | /// HTTP/2 spec, section 6.2. 14 | #[derive(Clone)] 15 | #[derive(PartialEq)] 16 | #[derive(Debug)] 17 | #[derive(Copy)] 18 | pub enum HeadersFlag { 19 | EndStream = 0x1, 20 | EndHeaders = 0x4, 21 | Padded = 0x8, 22 | Priority = 0x20, 23 | } 24 | 25 | impl Flag for HeadersFlag { 26 | #[inline] 27 | fn bitmask(&self) -> u8 { 28 | *self as u8 29 | } 30 | } 31 | 32 | /// The struct represents the dependency information that can be attached to 33 | /// a stream and sent within a HEADERS frame (one with the Priority flag set). 34 | #[derive(PartialEq)] 35 | #[derive(Debug)] 36 | #[derive(Clone)] 37 | pub struct StreamDependency { 38 | /// The ID of the stream that a particular stream depends on 39 | pub stream_id: StreamId, 40 | /// The weight for the stream. The value exposed (and set) here is always 41 | /// in the range [0, 255], instead of [1, 256] \(as defined in section 5.3.2.) 42 | /// so that the value fits into a `u8`. 43 | pub weight: u8, 44 | /// A flag indicating whether the stream dependency is exclusive. 45 | pub is_exclusive: bool, 46 | } 47 | 48 | impl StreamDependency { 49 | /// Creates a new `StreamDependency` with the given stream ID, weight, and 50 | /// exclusivity. 51 | pub fn new(stream_id: StreamId, weight: u8, is_exclusive: bool) -> StreamDependency { 52 | StreamDependency { 53 | stream_id: stream_id, 54 | weight: weight, 55 | is_exclusive: is_exclusive, 56 | } 57 | } 58 | 59 | /// Parses the first 5 bytes in the buffer as a `StreamDependency`. 60 | /// (Each 5-byte sequence is always decodable into a stream dependency 61 | /// structure). 62 | /// 63 | /// # Panics 64 | /// 65 | /// If the given buffer has less than 5 elements, the method will panic. 66 | pub fn parse(buf: &[u8]) -> StreamDependency { 67 | // The most significant bit of the first byte is the "E" bit indicating 68 | // whether the dependency is exclusive. 69 | let is_exclusive = buf[0] & 0x80 != 0; 70 | let stream_id = { 71 | // Parse the first 4 bytes into a u32... 72 | let mut id = unpack_octets_4!(buf, 0, u32); 73 | // ...clear the first bit since the stream id is only 31 bits. 74 | id &= !(1 << 31); 75 | id 76 | }; 77 | 78 | StreamDependency { 79 | stream_id: stream_id, 80 | weight: buf[4], 81 | is_exclusive: is_exclusive, 82 | } 83 | } 84 | 85 | /// Serializes the `StreamDependency` into a 5-byte buffer representing the 86 | /// dependency description, as described in section 6.2. of the HTTP/2 87 | /// spec: 88 | /// 89 | /// ```notest 90 | /// 0 1 2 3 91 | /// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 92 | /// +-+-------------+-----------------------------------------------+ 93 | /// |E| Stream Dependency (31) | 94 | /// +-+-------------+-----------------------------------------------+ 95 | /// | Weight (8) | 96 | /// +-+-------------+-----------------------------------------------+ 97 | /// ``` 98 | /// 99 | /// Where "E" is set if the dependency is exclusive. 100 | pub fn serialize(&self) -> [u8; 5] { 101 | let e_bit = if self.is_exclusive { 102 | 1 << 7 103 | } else { 104 | 0 105 | }; 106 | [(((self.stream_id >> 24) & 0x000000FF) as u8) | e_bit, 107 | (((self.stream_id >> 16) & 0x000000FF) as u8), 108 | (((self.stream_id >> 8) & 0x000000FF) as u8), 109 | (((self.stream_id ) & 0x000000FF) as u8), 110 | self.weight] 111 | } 112 | } 113 | 114 | /// A struct representing the HEADERS frames of HTTP/2, as defined in the 115 | /// HTTP/2 spec, section 6.2. 116 | #[derive(PartialEq)] 117 | #[derive(Debug)] 118 | #[derive(Clone)] 119 | pub struct HeadersFrame<'a> { 120 | /// The header fragment bytes stored within the frame. 121 | header_fragment: Cow<'a, [u8]>, 122 | /// The ID of the stream with which this frame is associated 123 | pub stream_id: StreamId, 124 | /// The stream dependency information, if any. 125 | pub stream_dep: Option, 126 | /// The length of the padding, if any. 127 | pub padding_len: Option, 128 | /// The set of flags for the frame, packed into a single byte. 129 | flags: u8, 130 | } 131 | 132 | impl<'a> HeadersFrame<'a> { 133 | /// Creates a new `HeadersFrame` with the given header fragment and stream 134 | /// ID. No padding, no stream dependency, and no flags are set. 135 | pub fn new(fragment: Vec, stream_id: StreamId) -> HeadersFrame<'a> { 136 | HeadersFrame { 137 | header_fragment: Cow::Owned(fragment), 138 | stream_id: stream_id, 139 | stream_dep: None, 140 | padding_len: None, 141 | flags: 0, 142 | } 143 | } 144 | 145 | /// Creates a new `HeadersFrame` with the given header fragment, stream ID 146 | /// and stream dependency information. No padding and no flags are set. 147 | pub fn with_dependency(fragment: Vec, 148 | stream_id: StreamId, 149 | stream_dep: StreamDependency) 150 | -> HeadersFrame<'a> { 151 | HeadersFrame { 152 | header_fragment: Cow::Owned(fragment), 153 | stream_id: stream_id, 154 | stream_dep: Some(stream_dep), 155 | padding_len: None, 156 | flags: HeadersFlag::Priority.bitmask(), 157 | } 158 | } 159 | 160 | /// Returns whether this frame ends the headers. If not, there MUST be a 161 | /// number of follow up CONTINUATION frames that send the rest of the 162 | /// header data. 163 | pub fn is_headers_end(&self) -> bool { 164 | self.is_set(HeadersFlag::EndHeaders) 165 | } 166 | 167 | /// Returns whther this frame ends the stream it is associated with. 168 | pub fn is_end_of_stream(&self) -> bool { 169 | self.is_set(HeadersFlag::EndStream) 170 | } 171 | 172 | /// Sets the padding length for the frame, as well as the corresponding 173 | /// Padded flag. 174 | pub fn set_padding(&mut self, padding_len: u8) { 175 | self.padding_len = Some(padding_len); 176 | self.set_flag(HeadersFlag::Padded); 177 | } 178 | 179 | /// Returns the length of the payload of the current frame, including any 180 | /// possible padding in the number of bytes. 181 | fn payload_len(&self) -> u32 { 182 | let padding = if self.is_set(HeadersFlag::Padded) { 183 | 1 + self.padding_len.unwrap_or(0) as u32 184 | } else { 185 | 0 186 | }; 187 | let priority = if self.is_set(HeadersFlag::Priority) { 188 | 5 189 | } else { 190 | 0 191 | }; 192 | 193 | self.header_fragment.len() as u32 + priority + padding 194 | } 195 | 196 | pub fn header_fragment(&self) -> &[u8] { 197 | &self.header_fragment 198 | } 199 | 200 | /// Sets the given flag for the frame. 201 | pub fn set_flag(&mut self, flag: HeadersFlag) { 202 | self.flags |= flag.bitmask(); 203 | } 204 | } 205 | 206 | impl<'a> Frame<'a> for HeadersFrame<'a> { 207 | /// The type that represents the flags that the particular `Frame` can take. 208 | /// This makes sure that only valid `Flag`s are used with each `Frame`. 209 | type FlagType = HeadersFlag; 210 | 211 | /// Creates a new `HeadersFrame` with the given `RawFrame` (i.e. header and 212 | /// payload), if possible. 213 | /// 214 | /// # Returns 215 | /// 216 | /// `None` if a valid `HeadersFrame` cannot be constructed from the given 217 | /// `RawFrame`. The stream ID *must not* be 0. 218 | /// 219 | /// Otherwise, returns a newly constructed `HeadersFrame`. 220 | fn from_raw(raw_frame: &'a RawFrame) -> Option> { 221 | // Unpack the header 222 | let (len, frame_type, flags, stream_id) = raw_frame.header(); 223 | // Check that the frame type is correct for this frame implementation 224 | if frame_type != 0x1 { 225 | return None; 226 | } 227 | // Check that the length given in the header matches the payload 228 | // length; if not, something went wrong and we do not consider this a 229 | // valid frame. 230 | if (len as usize) != raw_frame.payload().len() { 231 | return None; 232 | } 233 | // Check that the HEADERS frame is not associated to stream 0 234 | if stream_id == 0 { 235 | return None; 236 | } 237 | 238 | // First, we get a slice containing the actual payload, depending on if 239 | // the frame is padded. 240 | let padded = (flags & HeadersFlag::Padded.bitmask()) != 0; 241 | let (actual, pad_len) = if padded { 242 | match parse_padded_payload(&raw_frame.payload()) { 243 | Some((data, pad_len)) => (data, Some(pad_len)), 244 | None => return None, 245 | } 246 | } else { 247 | (raw_frame.payload(), None) 248 | }; 249 | 250 | // From the actual payload we extract the stream dependency info, if 251 | // the appropriate flag is set. 252 | let priority = (flags & HeadersFlag::Priority.bitmask()) != 0; 253 | let (data, stream_dep) = if priority { 254 | (&actual[5..], Some(StreamDependency::parse(&actual[..5]))) 255 | } else { 256 | (actual, None) 257 | }; 258 | 259 | Some(HeadersFrame { 260 | header_fragment: Cow::Borrowed(data), 261 | stream_id: stream_id, 262 | stream_dep: stream_dep, 263 | padding_len: pad_len, 264 | flags: flags, 265 | }) 266 | } 267 | 268 | /// Tests if the given flag is set for the frame. 269 | fn is_set(&self, flag: HeadersFlag) -> bool { 270 | (self.flags & flag.bitmask()) != 0 271 | } 272 | 273 | /// Returns the `StreamId` of the stream to which the frame is associated. 274 | /// 275 | /// A `SettingsFrame` always has to be associated to stream `0`. 276 | fn get_stream_id(&self) -> StreamId { 277 | self.stream_id 278 | } 279 | 280 | /// Returns a `FrameHeader` based on the current state of the `Frame`. 281 | fn get_header(&self) -> FrameHeader { 282 | (self.payload_len(), 0x1, self.flags, self.stream_id) 283 | } 284 | } 285 | 286 | impl<'a> FrameIR for HeadersFrame<'a> { 287 | fn serialize_into(self, b: &mut B) -> io::Result<()> { 288 | try!(b.write_header(self.get_header())); 289 | let padded = self.is_set(HeadersFlag::Padded); 290 | if padded { 291 | try!(b.write_all(&[self.padding_len.unwrap_or(0)])); 292 | } 293 | // The stream dependency fields follow, if the priority flag is set 294 | if self.is_set(HeadersFlag::Priority) { 295 | let dep_buf = match self.stream_dep { 296 | Some(ref dep) => dep.serialize(), 297 | None => panic!("Priority flag set, but no dependency information given"), 298 | }; 299 | try!(b.write_all(&dep_buf)); 300 | } 301 | // Now the actual headers fragment 302 | try!(b.write_all(&self.header_fragment)); 303 | // Finally, add the trailing padding, if required 304 | if padded { 305 | try!(b.write_padding(self.padding_len.unwrap_or(0))); 306 | } 307 | 308 | Ok(()) 309 | } 310 | } 311 | 312 | #[cfg(test)] 313 | mod tests { 314 | use super::{HeadersFrame, HeadersFlag, StreamDependency}; 315 | use http::frame::tests::build_padded_frame_payload; 316 | use http::tests::common::{raw_frame_from_parts, serialize_frame}; 317 | use http::frame::{pack_header, Frame}; 318 | 319 | /// Tests that a stream dependency structure can be correctly parsed by the 320 | /// `StreamDependency::parse` method. 321 | #[test] 322 | fn test_parse_stream_dependency() { 323 | { 324 | let buf = [0, 0, 0, 1, 5]; 325 | 326 | let dep = StreamDependency::parse(&buf); 327 | 328 | assert_eq!(dep.stream_id, 1); 329 | assert_eq!(dep.weight, 5); 330 | // This one was not exclusive! 331 | assert!(!dep.is_exclusive) 332 | } 333 | { 334 | // Most significant bit set => is exclusive! 335 | let buf = [128, 0, 0, 1, 5]; 336 | 337 | let dep = StreamDependency::parse(&buf); 338 | 339 | assert_eq!(dep.stream_id, 1); 340 | assert_eq!(dep.weight, 5); 341 | // This one was indeed exclusive! 342 | assert!(dep.is_exclusive) 343 | } 344 | { 345 | // Most significant bit set => is exclusive! 346 | let buf = [255, 255, 255, 255, 5]; 347 | 348 | let dep = StreamDependency::parse(&buf); 349 | 350 | assert_eq!(dep.stream_id, (1 << 31) - 1); 351 | assert_eq!(dep.weight, 5); 352 | // This one was indeed exclusive! 353 | assert!(dep.is_exclusive); 354 | } 355 | { 356 | let buf = [127, 255, 255, 255, 5]; 357 | 358 | let dep = StreamDependency::parse(&buf); 359 | 360 | assert_eq!(dep.stream_id, (1 << 31) - 1); 361 | assert_eq!(dep.weight, 5); 362 | // This one was not exclusive! 363 | assert!(!dep.is_exclusive); 364 | } 365 | } 366 | 367 | /// Tests that a stream dependency structure can be correctly serialized by 368 | /// the `StreamDependency::serialize` method. 369 | #[test] 370 | fn test_serialize_stream_dependency() { 371 | { 372 | let buf = [0, 0, 0, 1, 5]; 373 | let dep = StreamDependency::new(1, 5, false); 374 | 375 | assert_eq!(buf, dep.serialize()); 376 | } 377 | { 378 | // Most significant bit set => is exclusive! 379 | let buf = [128, 0, 0, 1, 5]; 380 | let dep = StreamDependency::new(1, 5, true); 381 | 382 | assert_eq!(buf, dep.serialize()); 383 | } 384 | { 385 | // Most significant bit set => is exclusive! 386 | let buf = [255, 255, 255, 255, 5]; 387 | let dep = StreamDependency::new((1 << 31) - 1, 5, true); 388 | 389 | assert_eq!(buf, dep.serialize()); 390 | } 391 | { 392 | let buf = [127, 255, 255, 255, 5]; 393 | let dep = StreamDependency::new((1 << 31) - 1, 5, false); 394 | 395 | assert_eq!(buf, dep.serialize()); 396 | } 397 | } 398 | 399 | /// Tests that a simple HEADERS frame is correctly parsed. The frame does 400 | /// not contain any padding nor priority information. 401 | #[test] 402 | fn test_headers_frame_parse_simple() { 403 | let data = b"123"; 404 | let payload = data.to_vec(); 405 | let header = (payload.len() as u32, 0x1, 0, 1); 406 | 407 | let raw = raw_frame_from_parts(header.clone(), payload.to_vec()); 408 | let frame: HeadersFrame = Frame::from_raw(&raw).unwrap(); 409 | 410 | assert_eq!(frame.header_fragment(), &data[..]); 411 | assert_eq!(frame.flags, 0); 412 | assert_eq!(frame.get_stream_id(), 1); 413 | assert!(frame.stream_dep.is_none()); 414 | assert!(frame.padding_len.is_none()); 415 | } 416 | 417 | /// Tests that a HEADERS frame with padding is correctly parsed. 418 | #[test] 419 | fn test_headers_frame_parse_with_padding() { 420 | let data = b"123"; 421 | let payload = build_padded_frame_payload(data, 6); 422 | let header = (payload.len() as u32, 0x1, 0x08, 1); 423 | 424 | let raw = raw_frame_from_parts(header.clone(), payload.to_vec()); 425 | let frame: HeadersFrame = Frame::from_raw(&raw).unwrap(); 426 | 427 | assert_eq!(frame.header_fragment(), &data[..]); 428 | assert_eq!(frame.flags, 8); 429 | assert_eq!(frame.get_stream_id(), 1); 430 | assert!(frame.stream_dep.is_none()); 431 | assert_eq!(frame.padding_len.unwrap(), 6); 432 | } 433 | 434 | /// Tests that a HEADERS frame with the priority flag (and necessary fields) 435 | /// is correctly parsed. 436 | #[test] 437 | fn test_headers_frame_parse_with_priority() { 438 | let data = b"123"; 439 | let dep = StreamDependency::new(0, 5, true); 440 | let payload = { 441 | let mut buf: Vec = Vec::new(); 442 | buf.extend(dep.serialize().to_vec().into_iter()); 443 | buf.extend(data.to_vec().into_iter()); 444 | 445 | buf 446 | }; 447 | let header = (payload.len() as u32, 0x1, 0x20, 1); 448 | 449 | let raw = raw_frame_from_parts(header.clone(), payload.to_vec()); 450 | let frame: HeadersFrame = Frame::from_raw(&raw).unwrap(); 451 | 452 | assert_eq!(frame.header_fragment(), &data[..]); 453 | assert_eq!(frame.flags, 0x20); 454 | assert_eq!(frame.get_stream_id(), 1); 455 | assert_eq!(frame.stream_dep.unwrap(), dep); 456 | assert!(frame.padding_len.is_none()); 457 | } 458 | 459 | /// Tests that a HEADERS frame with both padding and priority gets 460 | /// correctly parsed. 461 | #[test] 462 | fn test_headers_frame_parse_padding_and_priority() { 463 | let data = b"123"; 464 | let dep = StreamDependency::new(0, 5, true); 465 | let full = { 466 | let mut buf: Vec = Vec::new(); 467 | buf.extend(dep.serialize().to_vec().into_iter()); 468 | buf.extend(data.to_vec().into_iter()); 469 | 470 | buf 471 | }; 472 | let payload = build_padded_frame_payload(&full, 4); 473 | let header = (payload.len() as u32, 0x1, 0x20 | 0x8, 1); 474 | 475 | let raw = raw_frame_from_parts(header.clone(), payload.to_vec()); 476 | let frame: HeadersFrame = Frame::from_raw(&raw).unwrap(); 477 | 478 | assert_eq!(frame.header_fragment(), &data[..]); 479 | assert_eq!(frame.flags, 0x20 | 0x8); 480 | assert_eq!(frame.get_stream_id(), 1); 481 | assert_eq!(frame.stream_dep.unwrap(), dep); 482 | assert_eq!(frame.padding_len.unwrap(), 4); 483 | } 484 | 485 | /// Tests that a HEADERS with stream ID 0 is considered invalid. 486 | #[test] 487 | fn test_headers_frame_parse_invalid_stream_id() { 488 | let data = b"123"; 489 | let payload = data.to_vec(); 490 | let header = (payload.len() as u32, 0x1, 0, 0); 491 | 492 | let raw = raw_frame_from_parts(header, payload); 493 | let frame: Option = Frame::from_raw(&raw); 494 | 495 | assert!(frame.is_none()); 496 | } 497 | 498 | /// Tests that the `HeadersFrame::parse` method considers any frame with 499 | /// a frame ID other than 1 in the frame header invalid. 500 | #[test] 501 | fn test_headers_frame_parse_invalid_type() { 502 | let data = b"123"; 503 | let payload = data.to_vec(); 504 | let header = (payload.len() as u32, 0x2, 0, 1); 505 | 506 | let raw = raw_frame_from_parts(header, payload); 507 | let frame: Option = Frame::from_raw(&raw); 508 | 509 | assert!(frame.is_none()); 510 | } 511 | 512 | /// Tests that a simple HEADERS frame (no padding, no priority) gets 513 | /// correctly serialized. 514 | #[test] 515 | fn test_headers_frame_serialize_simple() { 516 | let data = b"123"; 517 | let payload = data.to_vec(); 518 | let header = (payload.len() as u32, 0x1, 0, 1); 519 | let expected = { 520 | let headers = pack_header(&header); 521 | let mut res: Vec = Vec::new(); 522 | res.extend(headers.to_vec().into_iter()); 523 | res.extend(payload.into_iter()); 524 | 525 | res 526 | }; 527 | let frame = HeadersFrame::new(data.to_vec(), 1); 528 | 529 | let actual = serialize_frame(&frame); 530 | 531 | assert_eq!(expected, actual); 532 | } 533 | 534 | /// Tests that a HEADERS frame with padding is correctly serialized. 535 | #[test] 536 | fn test_headers_frame_serialize_with_padding() { 537 | let data = b"123"; 538 | let payload = build_padded_frame_payload(data, 6); 539 | let header = (payload.len() as u32, 0x1, 0x08, 1); 540 | let expected = { 541 | let headers = pack_header(&header); 542 | let mut res: Vec = Vec::new(); 543 | res.extend(headers.to_vec().into_iter()); 544 | res.extend(payload.into_iter()); 545 | 546 | res 547 | }; 548 | let mut frame = HeadersFrame::new(data.to_vec(), 1); 549 | frame.set_padding(6); 550 | 551 | let actual = serialize_frame(&frame); 552 | 553 | assert_eq!(expected, actual); 554 | } 555 | 556 | /// Tests that a HEADERS frame with priority gets correctly serialized. 557 | #[test] 558 | fn test_headers_frame_serialize_with_priority() { 559 | let data = b"123"; 560 | let dep = StreamDependency::new(0, 5, true); 561 | let payload = { 562 | let mut buf: Vec = Vec::new(); 563 | buf.extend(dep.serialize().to_vec().into_iter()); 564 | buf.extend(data.to_vec().into_iter()); 565 | 566 | buf 567 | }; 568 | let header = (payload.len() as u32, 0x1, 0x20, 1); 569 | let expected = { 570 | let headers = pack_header(&header); 571 | let mut res: Vec = Vec::new(); 572 | res.extend(headers.to_vec().into_iter()); 573 | res.extend(payload.into_iter()); 574 | 575 | res 576 | }; 577 | let frame = HeadersFrame::with_dependency(data.to_vec(), 1, dep.clone()); 578 | 579 | let actual = serialize_frame(&frame); 580 | 581 | assert_eq!(expected, actual); 582 | } 583 | 584 | /// Tests that a HEADERS frame with both padding and a priority gets correctly 585 | /// serialized. 586 | #[test] 587 | fn test_headers_frame_serialize_padding_and_priority() { 588 | let data = b"123"; 589 | let dep = StreamDependency::new(0, 5, true); 590 | let full = { 591 | let mut buf: Vec = Vec::new(); 592 | buf.extend(dep.serialize().to_vec().into_iter()); 593 | buf.extend(data.to_vec().into_iter()); 594 | 595 | buf 596 | }; 597 | let payload = build_padded_frame_payload(&full, 4); 598 | let header = (payload.len() as u32, 0x1, 0x20 | 0x8, 1); 599 | let expected = { 600 | let headers = pack_header(&header); 601 | let mut res: Vec = Vec::new(); 602 | res.extend(headers.to_vec().into_iter()); 603 | res.extend(payload.into_iter()); 604 | 605 | res 606 | }; 607 | let mut frame = HeadersFrame::with_dependency(data.to_vec(), 1, dep.clone()); 608 | frame.set_padding(4); 609 | 610 | let actual = serialize_frame(&frame); 611 | 612 | assert_eq!(expected, actual); 613 | } 614 | 615 | /// Tests that the `HeadersFrame::is_headers_end` method returns the correct 616 | /// value depending on the `EndHeaders` flag being set or not. 617 | #[test] 618 | fn test_headers_frame_is_headers_end() { 619 | let mut frame = HeadersFrame::new(vec![], 1); 620 | assert!(!frame.is_headers_end()); 621 | 622 | frame.set_flag(HeadersFlag::EndHeaders); 623 | assert!(frame.is_headers_end()); 624 | } 625 | } 626 | -------------------------------------------------------------------------------- /src/http/frame/mod.rs: -------------------------------------------------------------------------------- 1 | //! The module contains the implementation of HTTP/2 frames. 2 | 3 | use std::io; 4 | use std::mem; 5 | use std::borrow::Cow; 6 | 7 | use http::StreamId; 8 | 9 | /// A helper macro that unpacks a sequence of 4 bytes found in the buffer with 10 | /// the given identifier, starting at the given offset, into the given integer 11 | /// type. Obviously, the integer type should be able to support at least 4 12 | /// bytes. 13 | /// 14 | /// # Examples 15 | /// 16 | /// ```rust 17 | /// let buf: [u8; 4] = [0, 0, 0, 1]; 18 | /// assert_eq!(1u32, unpack_octets_4!(buf, 0, u32)); 19 | /// ``` 20 | #[macro_escape] 21 | macro_rules! unpack_octets_4 { 22 | ($buf:expr, $offset:expr, $tip:ty) => ( 23 | (($buf[$offset + 0] as $tip) << 24) | 24 | (($buf[$offset + 1] as $tip) << 16) | 25 | (($buf[$offset + 2] as $tip) << 8) | 26 | (($buf[$offset + 3] as $tip) << 0) 27 | ); 28 | } 29 | 30 | /// Parse the next 4 octets in the given buffer, assuming they represent an HTTP/2 stream ID. 31 | /// This means that the most significant bit of the first octet is ignored and the rest interpreted 32 | /// as a network-endian 31-bit integer. 33 | #[inline] 34 | fn parse_stream_id(buf: &[u8]) -> u32 { 35 | let unpacked = unpack_octets_4!(buf, 0, u32); 36 | // Now clear the most significant bit, as that is reserved and MUST be ignored when received. 37 | unpacked & !0x80000000 38 | } 39 | 40 | pub const FRAME_HEADER_LEN: usize = 9; 41 | 42 | pub mod builder; 43 | pub mod data; 44 | pub mod headers; 45 | pub mod rst_stream; 46 | pub mod settings; 47 | pub mod goaway; 48 | pub mod ping; 49 | pub mod window_update; 50 | 51 | pub use self::builder::FrameBuilder; 52 | 53 | /// Rexports related to the `DATA` frame. 54 | pub use self::data::{DataFlag, DataFrame}; 55 | /// Rexports related to the `HEADERS` frame. 56 | pub use self::headers::{HeadersFlag, HeadersFrame}; 57 | pub use self::rst_stream::RstStreamFrame; 58 | /// Rexports related to the `SETTINGS` frame. 59 | pub use self::settings::{SettingsFlag, SettingsFrame, HttpSetting}; 60 | pub use self::goaway::GoawayFrame; 61 | pub use self::ping::PingFrame; 62 | pub use self::window_update::WindowUpdateFrame; 63 | 64 | /// An alias for the 9-byte buffer that each HTTP/2 frame header must be stored 65 | /// in. 66 | pub type FrameHeaderBuffer = [u8; 9]; 67 | /// An alias for the 4-tuple representing the components of each HTTP/2 frame 68 | /// header. 69 | pub type FrameHeader = (u32, u8, u8, u32); 70 | 71 | /// Deconstructs a `FrameHeader` into its corresponding 4 components, 72 | /// represented as a 4-tuple: `(length, frame_type, flags, stream_id)`. 73 | /// 74 | /// The frame `type` and `flags` components are returned as their original 75 | /// octet representation, rather than reinterpreted. 76 | pub fn unpack_header(header: &FrameHeaderBuffer) -> FrameHeader { 77 | let length: u32 = ((header[0] as u32) << 16) | ((header[1] as u32) << 8) | 78 | (header[2] as u32); 79 | let frame_type = header[3]; 80 | let flags = header[4]; 81 | let stream_id = parse_stream_id(&header[5..]); 82 | 83 | (length, frame_type, flags, stream_id) 84 | } 85 | 86 | /// Constructs a buffer of 9 bytes that represents the given `FrameHeader`. 87 | pub fn pack_header(header: &FrameHeader) -> FrameHeaderBuffer { 88 | let &(length, frame_type, flags, stream_id) = header; 89 | 90 | [(((length >> 16) & 0x000000FF) as u8), 91 | (((length >> 8) & 0x000000FF) as u8), 92 | (((length ) & 0x000000FF) as u8), 93 | frame_type, 94 | flags, 95 | (((stream_id >> 24) & 0x000000FF) as u8), 96 | (((stream_id >> 16) & 0x000000FF) as u8), 97 | (((stream_id >> 8) & 0x000000FF) as u8), 98 | (((stream_id ) & 0x000000FF) as u8)] 99 | } 100 | 101 | /// A helper function that parses the given payload, considering it padded. 102 | /// 103 | /// This means that the first byte is the length of the padding with that many 104 | /// 0 bytes expected to follow the actual payload. 105 | /// 106 | /// # Returns 107 | /// 108 | /// A slice of the given payload where the actual one is found and the length 109 | /// of the padding. 110 | /// 111 | /// If the padded payload is invalid (e.g. the length of the padding is equal 112 | /// to the total length), returns `None`. 113 | fn parse_padded_payload(payload: &[u8]) -> Option<(&[u8], u8)> { 114 | if payload.len() == 0 { 115 | // We make sure not to index the payload before we're sure how 116 | // large the buffer is. 117 | // If this is the case, the frame is invalid as no padding 118 | // length can be extracted, even though the frame should be 119 | // padded. 120 | return None; 121 | } 122 | let pad_len = payload[0] as usize; 123 | if pad_len >= payload.len() { 124 | // This is invalid: the padding length MUST be less than the 125 | // total frame size. 126 | return None; 127 | } 128 | 129 | Some((&payload[1..payload.len() - pad_len], pad_len as u8)) 130 | } 131 | 132 | /// A trait that types that are an intermediate representation of HTTP/2 frames should implement. 133 | /// It allows us to generically serialize any intermediate representation into an on-the-wire 134 | /// representation. 135 | pub trait FrameIR { 136 | /// Write out the on-the-wire representation of the frame into the given `FrameBuilder`. 137 | fn serialize_into(self, builder: &mut B) -> io::Result<()>; 138 | } 139 | 140 | /// A trait that all HTTP/2 frame header flags need to implement. 141 | pub trait Flag { 142 | /// Returns a bit mask that represents the flag. 143 | fn bitmask(&self) -> u8; 144 | } 145 | 146 | /// A helper struct that can be used by all frames that do not define any flags. 147 | pub struct NoFlag; 148 | impl Flag for NoFlag { 149 | fn bitmask(&self) -> u8 { 150 | 0 151 | } 152 | } 153 | 154 | /// A trait that all HTTP/2 frame structs need to implement. 155 | pub trait Frame<'a>: Sized { 156 | /// The type that represents the flags that the particular `Frame` can take. 157 | /// This makes sure that only valid `Flag`s are used with each `Frame`. 158 | type FlagType: Flag; 159 | 160 | /// Creates a new `Frame` from the given `RawFrame` (i.e. header and 161 | /// payload), if possible. 162 | /// 163 | /// # Returns 164 | /// 165 | /// `None` if a valid `Frame` cannot be constructed from the given 166 | /// `RawFrame`. Some reasons why this may happen is a wrong frame type in 167 | /// the header, a body that cannot be decoded according to the particular 168 | /// frame's rules, etc. 169 | /// 170 | /// Otherwise, returns a newly constructed `Frame`. 171 | fn from_raw(raw_frame: &'a RawFrame<'a>) -> Option; 172 | 173 | /// Tests if the given flag is set for the frame. 174 | fn is_set(&self, flag: Self::FlagType) -> bool; 175 | /// Returns the `StreamId` of the stream to which the frame is associated 176 | fn get_stream_id(&self) -> StreamId; 177 | /// Returns a `FrameHeader` based on the current state of the `Frame`. 178 | fn get_header(&self) -> FrameHeader; 179 | } 180 | 181 | /// A struct that defines the format of the raw HTTP/2 frame, i.e. the frame 182 | /// as it is read from the wire. 183 | /// 184 | /// This format is defined in section 4.1. of the HTTP/2 spec. 185 | /// 186 | /// The `RawFrame` struct simply stores the raw components of an HTTP/2 frame: 187 | /// its header and the payload as a sequence of bytes. 188 | /// 189 | /// It does not try to interpret the payload bytes, nor do any validation in 190 | /// terms of its validity based on the frame type given in the header. 191 | /// It is simply a wrapper around the two parts of an HTTP/2 frame. 192 | #[derive(PartialEq)] 193 | #[derive(Debug)] 194 | #[derive(Clone)] 195 | pub struct RawFrame<'a> { 196 | /// The raw frame representation, including both the raw header representation 197 | /// (in the first 9 bytes), followed by the raw payload representation. 198 | raw_content: Cow<'a, [u8]>, 199 | } 200 | 201 | impl<'a> RawFrame<'a> { 202 | /// Parses a `RawFrame` from the bytes starting at the beginning of the given buffer. 203 | /// 204 | /// Returns the `None` variant when it is not possible to parse a raw frame from the buffer 205 | /// (due to there not being enough bytes in the buffer). If the `RawFrame` is successfully 206 | /// parsed it returns the frame, borrowing a part of the original buffer. Therefore, this 207 | /// method makes no copies, nor does it perform any extra allocations. 208 | /// 209 | /// # Examples 210 | /// 211 | /// ```rust 212 | /// use solicit::http::frame::RawFrame; 213 | /// 214 | /// let buf = b"123"; 215 | /// // Not enough bytes for even the header of the frame 216 | /// assert!(RawFrame::parse(&buf[..]).is_none()); 217 | /// ``` 218 | /// 219 | /// ```rust 220 | /// use solicit::http::frame::RawFrame; 221 | /// 222 | /// let buf = vec![0, 0, 1, 0, 0, 0, 0, 0, 0]; 223 | /// // Full header, but not enough bytes for the payload 224 | /// assert!(RawFrame::parse(&buf[..]).is_none()); 225 | /// ``` 226 | /// 227 | /// ```rust 228 | /// use solicit::http::frame::RawFrame; 229 | /// 230 | /// let buf = vec![0, 0, 1, 0, 0, 0, 0, 0, 0, 1]; 231 | /// // A full frame is extracted, even if in this case the frame itself is not valid (a DATA 232 | /// // frame associated to stream 0 is not valid in HTTP/2!). This, however, is not the 233 | /// // responsibility of the RawFrame. 234 | /// let frame = RawFrame::parse(&buf[..]).unwrap(); 235 | /// assert_eq!(frame.as_ref(), &buf[..]); 236 | /// ``` 237 | pub fn parse(buf: &'a [u8]) -> Option> { 238 | // TODO(mlalic): This might allow an extra parameter that specifies the maximum frame 239 | // payload length? 240 | if buf.len() < 9 { 241 | return None; 242 | } 243 | let header = unpack_header(unsafe { 244 | assert!(buf.len() >= 9); 245 | // We just asserted that this transmute is safe. 246 | mem::transmute(buf.as_ptr()) 247 | }); 248 | 249 | let payload_len = header.0 as usize; 250 | if buf[9..].len() < payload_len { 251 | return None; 252 | } 253 | 254 | let raw = &buf[..9 + payload_len]; 255 | Some(raw.into()) 256 | } 257 | 258 | /// Returns the total length of the `RawFrame`, including both headers, as well as the entire 259 | /// payload. 260 | #[inline] 261 | pub fn len(&self) -> usize { 262 | self.raw_content.len() 263 | } 264 | 265 | /// Returns a `Vec` of bytes representing the serialized (on-the-wire) 266 | /// representation of this raw frame. 267 | pub fn serialize(&self) -> Vec { 268 | self.raw_content.clone().into_owned() 269 | } 270 | 271 | /// Returns a `FrameHeader` instance corresponding to the headers of the 272 | /// `RawFrame`. 273 | pub fn header(&self) -> FrameHeader { 274 | unpack_header(unsafe { 275 | assert!(self.raw_content.len() >= 9); 276 | // We just asserted that this transmute is safe. 277 | mem::transmute(self.raw_content.as_ptr()) 278 | }) 279 | } 280 | 281 | /// Returns a slice representing the payload of the `RawFrame`. 282 | pub fn payload(&self) -> &[u8] { 283 | &self.raw_content[9..] 284 | } 285 | } 286 | 287 | impl<'a> Into> for RawFrame<'a> { 288 | fn into(self) -> Vec { 289 | self.raw_content.into_owned() 290 | } 291 | } 292 | impl<'a> AsRef<[u8]> for RawFrame<'a> { 293 | fn as_ref(&self) -> &[u8] { 294 | self.raw_content.as_ref() 295 | } 296 | } 297 | /// Provide a conversion from a `Vec`. 298 | /// 299 | /// This conversion is unchecked and could cause the resulting `RawFrame` to be an 300 | /// invalid HTTP/2 frame. 301 | impl<'a> From> for RawFrame<'a> { 302 | fn from(raw: Vec) -> RawFrame<'a> { 303 | RawFrame { raw_content: Cow::Owned(raw) } 304 | } 305 | } 306 | impl<'a> From<&'a [u8]> for RawFrame<'a> { 307 | fn from(raw: &'a [u8]) -> RawFrame<'a> { 308 | RawFrame { raw_content: Cow::Borrowed(raw) } 309 | } 310 | } 311 | 312 | /// `RawFrame`s can be serialized to an on-the-wire format. 313 | impl<'a> FrameIR for RawFrame<'a> { 314 | fn serialize_into(self, b: &mut B) -> io::Result<()> { 315 | try!(b.write_header(self.header())); 316 | b.write_all(self.payload()) 317 | } 318 | } 319 | 320 | #[cfg(test)] 321 | mod tests { 322 | use super::{unpack_header, pack_header, RawFrame, FrameIR}; 323 | use std::io; 324 | 325 | /// Tests that the `unpack_header` function correctly returns the 326 | /// components of HTTP/2 frame headers. 327 | #[test] 328 | fn test_unpack_header() { 329 | { 330 | let header = [0; 9]; 331 | assert_eq!((0, 0, 0, 0), unpack_header(&header)); 332 | } 333 | { 334 | let header = [0, 0, 1, 2, 3, 0, 0, 0, 4]; 335 | assert_eq!((1, 2, 3, 4), unpack_header(&header)); 336 | } 337 | { 338 | let header = [0, 0, 1, 200, 100, 0, 0, 0, 4]; 339 | assert_eq!((1, 200, 100, 4), unpack_header(&header)); 340 | } 341 | { 342 | let header = [0, 0, 1, 0, 0, 0, 0, 0, 0]; 343 | assert_eq!((1, 0, 0, 0), unpack_header(&header)); 344 | } 345 | { 346 | let header = [0, 1, 0, 0, 0, 0, 0, 0, 0]; 347 | assert_eq!((256, 0, 0, 0), unpack_header(&header)); 348 | } 349 | { 350 | let header = [1, 0, 0, 0, 0, 0, 0, 0, 0]; 351 | assert_eq!((256 * 256, 0, 0, 0), unpack_header(&header)); 352 | } 353 | { 354 | let header = [0, 0, 0, 0, 0, 0, 0, 0, 1]; 355 | assert_eq!((0, 0, 0, 1), unpack_header(&header)); 356 | } 357 | { 358 | let header = [0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 1]; 359 | assert_eq!(((1 << 24) - 1, 0, 0, 1), unpack_header(&header)); 360 | } 361 | { 362 | let header = [0xFF, 0xFF, 0xFF, 0, 0, 1, 1, 1, 1]; 363 | assert_eq!(((1 << 24) - 1, 0, 0, 1 + (1 << 8) + (1 << 16) + (1 << 24)), 364 | unpack_header(&header)); 365 | } 366 | { 367 | // Ignores reserved bit within the stream id (the most significant bit) 368 | let header = [0, 0, 1, 0, 0, 0x80, 0, 0, 1]; 369 | assert_eq!((1, 0, 0, 1), unpack_header(&header)); 370 | } 371 | } 372 | 373 | /// Tests that the `pack_header` function correctly returns the buffer 374 | /// corresponding to components of HTTP/2 frame headers. 375 | #[test] 376 | fn test_pack_header() { 377 | { 378 | let header = [0; 9]; 379 | assert_eq!(pack_header(&(0, 0, 0, 0)), header); 380 | } 381 | { 382 | let header = [0, 0, 1, 2, 3, 0, 0, 0, 4]; 383 | assert_eq!(pack_header(&(1, 2, 3, 4)), header); 384 | } 385 | { 386 | let header = [0, 0, 1, 200, 100, 0, 0, 0, 4]; 387 | assert_eq!(pack_header(&(1, 200, 100, 4)), header); 388 | } 389 | { 390 | let header = [0, 0, 1, 0, 0, 0, 0, 0, 0]; 391 | assert_eq!(pack_header(&(1, 0, 0, 0)), header); 392 | } 393 | { 394 | let header = [0, 1, 0, 0, 0, 0, 0, 0, 0]; 395 | assert_eq!(pack_header(&(256, 0, 0, 0)), header); 396 | } 397 | { 398 | let header = [1, 0, 0, 0, 0, 0, 0, 0, 0]; 399 | assert_eq!(pack_header(&(256 * 256, 0, 0, 0)), header); 400 | } 401 | { 402 | let header = [0, 0, 0, 0, 0, 0, 0, 0, 1]; 403 | assert_eq!(pack_header(&(0, 0, 0, 1)), header); 404 | } 405 | { 406 | let header = [0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 1]; 407 | assert_eq!(pack_header(&((1 << 24) - 1, 0, 0, 1)), header); 408 | } 409 | { 410 | let header = [0xFF, 0xFF, 0xFF, 0, 0, 1, 1, 1, 1]; 411 | let header_components = ((1 << 24) - 1, 0, 0, 1 + (1 << 8) + (1 << 16) + (1 << 24)); 412 | assert_eq!(pack_header(&header_components), header); 413 | } 414 | } 415 | 416 | /// Builds a `Vec` containing the given data as a padded HTTP/2 frame. 417 | /// 418 | /// It first places the length of the padding, followed by the data, 419 | /// followed by `pad_len` zero bytes. 420 | pub fn build_padded_frame_payload(data: &[u8], pad_len: u8) -> Vec { 421 | let sz = 1 + data.len() + pad_len as usize; 422 | let mut payload: Vec = Vec::with_capacity(sz); 423 | payload.push(pad_len); 424 | payload.extend(data.to_vec().into_iter()); 425 | for _ in 0..pad_len { 426 | payload.push(0); 427 | } 428 | 429 | payload 430 | } 431 | 432 | /// Tests that constructing a `RawFrame` from a `Vec` by using the `From>` 433 | /// trait implementation works as expected. 434 | #[test] 435 | fn test_raw_frame_from_vec_buffer_unchecked() { 436 | // Correct frame 437 | { 438 | let data = b"123"; 439 | let header = (data.len() as u32, 0x1, 0, 1); 440 | let buf = { 441 | let mut buf = Vec::new(); 442 | buf.extend(pack_header(&header).to_vec().into_iter()); 443 | buf.extend(data.to_vec().into_iter()); 444 | buf 445 | }; 446 | let buf_clone = buf.clone(); 447 | 448 | let raw = RawFrame::from(buf); 449 | 450 | assert_eq!(raw.header(), header); 451 | assert_eq!(raw.payload(), data); 452 | assert_eq!(raw.serialize(), buf_clone); 453 | } 454 | // Correct frame with trailing data 455 | { 456 | let data = b"123"; 457 | let header = (data.len() as u32, 0x1, 0, 1); 458 | let buf = { 459 | let mut buf = Vec::new(); 460 | buf.extend(pack_header(&header).to_vec().into_iter()); 461 | buf.extend(data.to_vec().into_iter()); 462 | buf.extend(b"12345".to_vec().into_iter()); 463 | buf 464 | }; 465 | let buf_clone = buf.clone(); 466 | 467 | let raw = RawFrame::from(buf); 468 | 469 | assert_eq!(raw.header(), header); 470 | assert_eq!(raw.payload(), b"12312345"); 471 | assert_eq!(raw.serialize(), buf_clone); 472 | } 473 | // Missing payload chunk 474 | { 475 | let data = b"123"; 476 | let header = (data.len() as u32, 0x1, 0, 1); 477 | let buf = { 478 | let mut buf = Vec::new(); 479 | buf.extend(pack_header(&header).to_vec().into_iter()); 480 | buf.extend(data[..2].to_vec().into_iter()); 481 | buf 482 | }; 483 | let buf_clone = buf.clone(); 484 | 485 | let raw = RawFrame::from(buf); 486 | 487 | assert_eq!(raw.header(), header); 488 | assert_eq!(raw.payload(), b"12"); 489 | assert_eq!(raw.serialize(), buf_clone); 490 | } 491 | // Missing header chunk 492 | { 493 | let header = (0, 0x1, 0, 1); 494 | let buf = { 495 | let mut buf = Vec::new(); 496 | buf.extend(pack_header(&header)[..5].to_vec().into_iter()); 497 | buf 498 | }; 499 | let buf_clone = buf.clone(); 500 | 501 | let raw = RawFrame::from(buf); 502 | 503 | assert_eq!(raw.serialize(), buf_clone); 504 | } 505 | // Completely empty buffer 506 | { 507 | assert_eq!(RawFrame::from(vec![]).serialize(), &[]); 508 | } 509 | } 510 | 511 | /// Tests that a borrowed slice can be converted into a `RawFrame` due to the implementation of 512 | /// the `From<&'a [u8]>` trait. 513 | #[test] 514 | fn test_from_slice() { 515 | let buf = &b""[..]; 516 | let frame = RawFrame::from(buf); 517 | assert_eq!(frame.as_ref(), buf); 518 | } 519 | 520 | /// Tests that the `RawFrame::serialize` method correctly serializes a 521 | /// `RawFrame`. 522 | #[test] 523 | fn test_raw_frame_serialize() { 524 | let data = b"123"; 525 | let header = (data.len() as u32, 0x1, 0, 1); 526 | let buf = { 527 | let mut buf = Vec::new(); 528 | buf.extend(pack_header(&header).to_vec().into_iter()); 529 | buf.extend(data.to_vec().into_iter()); 530 | buf 531 | }; 532 | let raw: RawFrame = buf.clone().into(); 533 | 534 | assert_eq!(raw.serialize(), buf); 535 | } 536 | 537 | /// Tests that converting a `RawFrame` into a `Vec` works correctly. 538 | #[test] 539 | fn test_raw_frame_into_vec() { 540 | let data = b"123"; 541 | let header = (data.len() as u32, 0x1, 0, 1); 542 | let buf = { 543 | let mut buf = Vec::new(); 544 | buf.extend(pack_header(&header).to_vec().into_iter()); 545 | buf.extend(data.to_vec().into_iter()); 546 | buf 547 | }; 548 | let raw: RawFrame = buf.clone().into(); 549 | 550 | let serialized = raw.serialize(); 551 | let vec: Vec<_> = raw.into(); 552 | // The vector is equivalent to the original buffer? 553 | assert_eq!(vec, buf); 554 | // The vector and the serialized representation are also equivalent 555 | assert_eq!(vec, serialized); 556 | } 557 | 558 | /// Tests that `RawFrame`s are correctly serialized to an on-the-wire format, when considered a 559 | /// `FrameIR` implementation. 560 | #[test] 561 | fn test_raw_frame_as_frame_ir() { 562 | let data = b"123"; 563 | let header = (data.len() as u32, 0x1, 0, 1); 564 | let buf = { 565 | let mut buf = Vec::new(); 566 | buf.extend(pack_header(&header).to_vec().into_iter()); 567 | buf.extend(data.to_vec().into_iter()); 568 | buf 569 | }; 570 | let raw: RawFrame = buf.clone().into(); 571 | 572 | let mut serialized = io::Cursor::new(Vec::new()); 573 | raw.serialize_into(&mut serialized).unwrap(); 574 | 575 | assert_eq!(serialized.into_inner(), buf); 576 | } 577 | 578 | /// Tests the `len` method of the `RawFrame`. 579 | #[test] 580 | fn test_raw_frame_len() { 581 | { 582 | // Not enough bytes for even the header of the frame 583 | let buf = b"123"; 584 | let frame = RawFrame::from(&buf[..]); 585 | assert_eq!(buf.len(), frame.len()); 586 | } 587 | { 588 | // Full header, but not enough bytes for the payload 589 | let buf = vec![0, 0, 1, 0, 0, 0, 0, 0, 0]; 590 | let frame = RawFrame::from(&buf[..]); 591 | assert_eq!(buf.len(), frame.len()); 592 | } 593 | { 594 | let buf = vec![0, 0, 1, 0, 0, 0, 0, 0, 0, 1]; 595 | let frame = RawFrame::from(&buf[..]); 596 | assert_eq!(buf.len(), frame.len()); 597 | } 598 | } 599 | } 600 | -------------------------------------------------------------------------------- /src/http/frame/ping.rs: -------------------------------------------------------------------------------- 1 | //! Implements the `PING` HTTP/2 frame. 2 | 3 | use std::io; 4 | 5 | use http::StreamId; 6 | use http::frame::{ 7 | Frame, 8 | FrameIR, 9 | FrameBuilder, 10 | FrameHeader, 11 | RawFrame, 12 | Flag, 13 | }; 14 | 15 | /// Ping frames are always 8 bytes 16 | pub const PING_FRAME_LEN: u32 = 8; 17 | /// The frame type of the `PING` frame. 18 | pub const PING_FRAME_TYPE: u8 = 0x6; 19 | 20 | pub struct PingFlag; 21 | impl Flag for PingFlag { 22 | fn bitmask(&self) -> u8 { 23 | 0x1 24 | } 25 | } 26 | 27 | /// The struct represents the `PINg` HTTP/2 frame. 28 | #[derive(Clone, Debug, PartialEq)] 29 | pub struct PingFrame { 30 | opaque_data: u64, 31 | flags: u8, 32 | } 33 | 34 | impl PingFrame { 35 | /// Create a new `PING` frame 36 | pub fn new() -> Self { 37 | PingFrame { 38 | opaque_data: 0, 39 | flags: 0, 40 | } 41 | } 42 | 43 | /// Create a new PING frame with ACK set 44 | pub fn new_ack(opaque_data: u64) -> Self { 45 | PingFrame { 46 | opaque_data: opaque_data, 47 | flags: 1, 48 | } 49 | } 50 | 51 | /// Create a new `PING` frame with the given opaque_data 52 | pub fn with_data(opaque_data: u64) -> Self { 53 | PingFrame { 54 | opaque_data: opaque_data, 55 | flags: 0, 56 | } 57 | } 58 | 59 | pub fn is_ack(&self) -> bool { 60 | self.is_set(PingFlag) 61 | } 62 | 63 | pub fn opaque_data(&self) -> u64 { 64 | self.opaque_data 65 | } 66 | } 67 | 68 | impl<'a> Frame<'a> for PingFrame { 69 | type FlagType = PingFlag; 70 | 71 | fn from_raw(raw_frame: &'a RawFrame<'a>) -> Option { 72 | let (payload_len, frame_type, flags, stream_id) = raw_frame.header(); 73 | if payload_len != PING_FRAME_LEN { 74 | return None; 75 | } 76 | if frame_type != PING_FRAME_TYPE { 77 | return None; 78 | } 79 | if stream_id != 0x0 { 80 | return None; 81 | } 82 | 83 | let data = unpack_octets_4!(raw_frame.payload(), 0, u64) << 32 | 84 | unpack_octets_4!(raw_frame.payload(), 4, u64); 85 | 86 | Some(PingFrame { 87 | opaque_data: data, 88 | flags: flags, 89 | }) 90 | } 91 | 92 | fn is_set(&self, flag: PingFlag) -> bool { 93 | (flag.bitmask() & self.flags) != 0 94 | } 95 | 96 | fn get_stream_id(&self) -> StreamId { 97 | 0 98 | } 99 | 100 | fn get_header(&self) -> FrameHeader { 101 | (PING_FRAME_LEN, PING_FRAME_TYPE, self.flags, 0) 102 | } 103 | } 104 | 105 | impl<'a> FrameIR for PingFrame { 106 | fn serialize_into(self, builder: &mut B) -> io::Result<()> { 107 | try!(builder.write_header(self.get_header())); 108 | try!(builder.write_u32((self.opaque_data >> 32) as u32)); 109 | try!(builder.write_u32(self.opaque_data as u32)); 110 | Ok(()) 111 | } 112 | } 113 | 114 | #[cfg(test)] 115 | mod tests { 116 | use super::PingFrame; 117 | 118 | use http::tests::common::{serialize_frame, raw_frame_from_parts}; 119 | use http::frame::Frame; 120 | 121 | #[test] 122 | fn test_parse_not_ack() { 123 | let raw = raw_frame_from_parts((8, 0x6, 0, 0), vec![0, 0, 0, 0, 0, 0, 0, 0]); 124 | let frame = PingFrame::from_raw(&raw).expect("Expected successful parse"); 125 | assert_eq!(frame.is_ack(), false); 126 | assert_eq!(frame.opaque_data(), 0); 127 | } 128 | 129 | #[test] 130 | fn test_parse_ack() { 131 | let raw = raw_frame_from_parts((8, 0x6, 1, 0), vec![0, 0, 0, 0, 0, 0, 0, 0]); 132 | let frame = PingFrame::from_raw(&raw).expect("Expected successful parse"); 133 | assert_eq!(frame.is_ack(), true); 134 | assert_eq!(frame.opaque_data(), 0); 135 | } 136 | 137 | #[test] 138 | fn test_parse_opaque_data() { 139 | let raw = raw_frame_from_parts((8, 0x6, 1, 0), vec![1, 2, 3, 4, 5, 6, 7, 8]); 140 | let frame = PingFrame::from_raw(&raw).expect("Expected successful parse"); 141 | assert_eq!(frame.is_ack(), true); 142 | assert_eq!(frame.opaque_data(), 0x0102030405060708); 143 | } 144 | 145 | #[test] 146 | fn test_serialize() { 147 | let frame = PingFrame::new_ack(0); 148 | let expected: Vec = raw_frame_from_parts( 149 | (8, 0x6, 1, 0), 150 | vec![0, 0, 0, 0, 0, 0, 0, 0]).into(); 151 | 152 | let raw = serialize_frame(&frame); 153 | 154 | assert_eq!(expected, raw); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/http/frame/rst_stream.rs: -------------------------------------------------------------------------------- 1 | //! The module contains the implementation of the `RST_STREAM` frame. 2 | use std::io; 3 | 4 | use http::{ErrorCode, StreamId}; 5 | use http::frame::{Frame, FrameIR, FrameBuilder, FrameHeader, RawFrame, NoFlag}; 6 | 7 | /// The total allowed size for the `RST_STREAM` frame payload. 8 | pub const RST_STREAM_FRAME_LEN: u32 = 4; 9 | /// The frame type of the `RST_STREAM` frame. 10 | pub const RST_STREAM_FRAME_TYPE: u8 = 0x3; 11 | 12 | /// The struct represents the `RST_STREAM` HTTP/2 frame. 13 | #[derive(Clone, Debug, PartialEq)] 14 | pub struct RstStreamFrame { 15 | raw_error_code: u32, 16 | stream_id: StreamId, 17 | flags: u8, 18 | } 19 | 20 | impl RstStreamFrame { 21 | /// Constructs a new `RstStreamFrame` with the given `ErrorCode`. 22 | pub fn new(stream_id: StreamId, error_code: ErrorCode) -> RstStreamFrame { 23 | RstStreamFrame { 24 | raw_error_code: error_code.into(), 25 | stream_id: stream_id, 26 | flags: 0, 27 | } 28 | } 29 | 30 | /// Constructs a new `RstStreamFrame` that will use the given `raw_error_code` for its payload. 31 | pub fn with_raw_error_code(stream_id: StreamId, raw_error_code: u32) -> RstStreamFrame { 32 | RstStreamFrame { 33 | raw_error_code: raw_error_code, 34 | stream_id: stream_id, 35 | flags: 0, 36 | } 37 | } 38 | 39 | /// Returns the interpreted error code of the frame. Any unknown error codes are mapped into 40 | /// the `InternalError` variant of the enum. 41 | pub fn error_code(&self) -> ErrorCode { 42 | self.raw_error_code.into() 43 | } 44 | 45 | /// Returns the original raw error code of the frame. If the code is unknown, it will not be 46 | /// changed. 47 | pub fn raw_error_code(&self) -> u32 { 48 | self.raw_error_code 49 | } 50 | } 51 | 52 | impl<'a> Frame<'a> for RstStreamFrame { 53 | type FlagType = NoFlag; 54 | 55 | fn from_raw(raw_frame: &'a RawFrame<'a>) -> Option { 56 | let (payload_len, frame_type, flags, stream_id) = raw_frame.header(); 57 | if payload_len != RST_STREAM_FRAME_LEN { 58 | return None; 59 | } 60 | if frame_type != RST_STREAM_FRAME_TYPE { 61 | return None; 62 | } 63 | if stream_id == 0x0 { 64 | return None; 65 | } 66 | 67 | let error = unpack_octets_4!(raw_frame.payload(), 0, u32); 68 | 69 | Some(RstStreamFrame { 70 | raw_error_code: error, 71 | stream_id: stream_id, 72 | flags: flags, 73 | }) 74 | } 75 | 76 | fn is_set(&self, _: NoFlag) -> bool { 77 | false 78 | } 79 | fn get_stream_id(&self) -> StreamId { 80 | self.stream_id 81 | } 82 | fn get_header(&self) -> FrameHeader { 83 | (RST_STREAM_FRAME_LEN, 84 | RST_STREAM_FRAME_TYPE, 85 | self.flags, 86 | self.stream_id) 87 | } 88 | } 89 | 90 | impl FrameIR for RstStreamFrame { 91 | fn serialize_into(self, builder: &mut B) -> io::Result<()> { 92 | try!(builder.write_header(self.get_header())); 93 | try!(builder.write_u32(self.raw_error_code)); 94 | Ok(()) 95 | } 96 | } 97 | 98 | #[cfg(test)] 99 | mod tests { 100 | use super::RstStreamFrame; 101 | 102 | use http::tests::common::serialize_frame; 103 | use http::ErrorCode; 104 | use http::frame::{pack_header, FrameHeader, Frame}; 105 | 106 | /// A helper function that creates a new Vec containing the serialized representation of the 107 | /// given `FrameHeader` followed by the raw provided payload. 108 | fn prepare_frame_bytes(header: FrameHeader, payload: Vec) -> Vec { 109 | let mut buf = Vec::new(); 110 | buf.extend(pack_header(&header).to_vec()); 111 | buf.extend(payload); 112 | buf 113 | } 114 | 115 | #[test] 116 | fn test_parse_valid() { 117 | let raw = prepare_frame_bytes((4, 0x3, 0, 1), vec![0, 0, 0, 1]); 118 | let rst = RstStreamFrame::from_raw(&raw.into()).expect("Valid frame expected"); 119 | assert_eq!(rst.error_code(), ErrorCode::ProtocolError); 120 | assert_eq!(rst.get_stream_id(), 1); 121 | } 122 | 123 | #[test] 124 | fn test_parse_valid_with_unknown_flags() { 125 | let raw = prepare_frame_bytes((4, 0x3, 0x80, 1), vec![0, 0, 0, 1]); 126 | let rst = RstStreamFrame::from_raw(&raw.into()).expect("Valid frame expected"); 127 | assert_eq!(rst.error_code(), ErrorCode::ProtocolError); 128 | assert_eq!(rst.get_stream_id(), 1); 129 | // The raw flag set is correctly reported from the header, but the parsed frame itself does 130 | // not know how to interpret them. 131 | assert_eq!(rst.get_header().2, 0x80); 132 | } 133 | 134 | #[test] 135 | fn test_parse_unknown_error_code() { 136 | let raw = prepare_frame_bytes((4, 0x3, 0x80, 1), vec![1, 0, 0, 1]); 137 | let rst = RstStreamFrame::from_raw(&raw.into()).expect("Valid frame expected"); 138 | // Unknown error codes are considered equivalent to an internal error. 139 | assert_eq!(rst.error_code(), ErrorCode::InternalError); 140 | // ...but the frame still surfaces the original raw code, so that clients can handle that, 141 | // if they so choose. 142 | assert_eq!(rst.raw_error_code(), 0x01000001); 143 | } 144 | 145 | #[test] 146 | fn test_parse_invalid_stream_id() { 147 | let raw = prepare_frame_bytes((4, 0x3, 0x80, 0), vec![0, 0, 0, 1]); 148 | assert!(RstStreamFrame::from_raw(&raw.into()).is_none()); 149 | } 150 | 151 | #[test] 152 | fn test_parse_invalid_payload_size() { 153 | let raw = prepare_frame_bytes((5, 0x3, 0x00, 2), vec![0, 0, 0, 1, 0]); 154 | assert!(RstStreamFrame::from_raw(&raw.into()).is_none()); 155 | } 156 | 157 | #[test] 158 | fn test_parse_invalid_id() { 159 | let raw = prepare_frame_bytes((4, 0x1, 0x00, 2), vec![0, 0, 0, 1, 0]); 160 | assert!(RstStreamFrame::from_raw(&raw.into()).is_none()); 161 | } 162 | 163 | #[test] 164 | fn test_serialize_protocol_error() { 165 | let frame = RstStreamFrame::new(1, ErrorCode::ProtocolError); 166 | let raw = serialize_frame(&frame); 167 | assert_eq!(raw, prepare_frame_bytes((4, 0x3, 0, 1), vec![0, 0, 0, 1])); 168 | } 169 | 170 | #[test] 171 | fn test_serialize_stream_closed() { 172 | let frame = RstStreamFrame::new(2, ErrorCode::StreamClosed); 173 | let raw = serialize_frame(&frame); 174 | assert_eq!(raw, prepare_frame_bytes((4, 0x3, 0, 2), vec![0, 0, 0, 0x5])); 175 | } 176 | 177 | #[test] 178 | fn test_serialize_raw_error_code() { 179 | let frame = RstStreamFrame::with_raw_error_code(3, 1024); 180 | let raw = serialize_frame(&frame); 181 | assert_eq!(raw, 182 | prepare_frame_bytes((4, 0x3, 0, 3), vec![0, 0, 0x04, 0])); 183 | } 184 | 185 | #[test] 186 | fn test_partial_eq() { 187 | let frame1 = RstStreamFrame::with_raw_error_code(3, 1); 188 | let frame2 = RstStreamFrame::new(3, ErrorCode::ProtocolError); 189 | assert_eq!(frame1, frame2); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/http/frame/window_update.rs: -------------------------------------------------------------------------------- 1 | //! Implements the `WINDOW_UPDATE` HTTP/2 frame. 2 | 3 | use std::io; 4 | 5 | use http::StreamId; 6 | use http::frame::{Frame, FrameIR, FrameBuilder, FrameHeader, RawFrame, NoFlag}; 7 | 8 | /// The minimum size for the `WINDOW_UPDATE` frame payload. 9 | pub const WINDOW_UPDATE_FRAME_LEN: u32 = 4; 10 | /// The frame type of the `WINDOW_UPDATE` frame. 11 | pub const WINDOW_UPDATE_FRAME_TYPE: u8 = 0x8; 12 | 13 | /// The struct represents the `WINDOW_UPDATE` HTTP/2 frame. 14 | #[derive(Clone, Debug, PartialEq)] 15 | pub struct WindowUpdateFrame { 16 | stream_id: StreamId, 17 | increment: u32, 18 | flags: u8, 19 | } 20 | 21 | impl WindowUpdateFrame { 22 | /// Creates a new `WindowUpdateFrame` that will increment the connection-level window by the 23 | /// given increment. 24 | pub fn for_connection(increment: u32) -> WindowUpdateFrame { 25 | WindowUpdateFrame { 26 | stream_id: 0, 27 | increment: increment, 28 | flags: 0, 29 | } 30 | } 31 | 32 | /// Creates a new `WindowUpdateFrame` that will increment the given stream's window by the 33 | /// given increment. 34 | pub fn for_stream(stream_id: StreamId, increment: u32) -> WindowUpdateFrame { 35 | WindowUpdateFrame { 36 | stream_id: stream_id, 37 | increment: increment, 38 | flags: 0, 39 | } 40 | } 41 | 42 | /// Returns the window increment indicated by the frame. 43 | pub fn increment(&self) -> u32 { 44 | self.increment 45 | } 46 | } 47 | 48 | impl<'a> Frame<'a> for WindowUpdateFrame { 49 | type FlagType = NoFlag; 50 | 51 | fn from_raw(raw_frame: &'a RawFrame<'a>) -> Option { 52 | let (payload_len, frame_type, flags, stream_id) = raw_frame.header(); 53 | if payload_len != WINDOW_UPDATE_FRAME_LEN { 54 | return None; 55 | } 56 | if frame_type != WINDOW_UPDATE_FRAME_TYPE { 57 | return None; 58 | } 59 | 60 | let num = unpack_octets_4!(raw_frame.payload(), 0, u32); 61 | // Clear the reserved most-significant bit 62 | let increment = num & !0x80000000; 63 | 64 | Some(WindowUpdateFrame { 65 | stream_id: stream_id, 66 | increment: increment, 67 | flags: flags, 68 | }) 69 | } 70 | 71 | fn is_set(&self, _: NoFlag) -> bool { 72 | false 73 | } 74 | fn get_stream_id(&self) -> StreamId { 75 | self.stream_id 76 | } 77 | fn get_header(&self) -> FrameHeader { 78 | (WINDOW_UPDATE_FRAME_LEN, 79 | WINDOW_UPDATE_FRAME_TYPE, 80 | self.flags, 81 | self.get_stream_id()) 82 | } 83 | } 84 | 85 | impl FrameIR for WindowUpdateFrame { 86 | fn serialize_into(self, builder: &mut B) -> io::Result<()> { 87 | try!(builder.write_header(self.get_header())); 88 | try!(builder.write_u32(self.increment)); 89 | Ok(()) 90 | } 91 | } 92 | 93 | #[cfg(test)] 94 | mod tests { 95 | use super::WindowUpdateFrame; 96 | 97 | use http::tests::common::{serialize_frame, raw_frame_from_parts}; 98 | use http::frame::Frame; 99 | 100 | #[test] 101 | fn test_parse_valid_connection_level() { 102 | let raw = raw_frame_from_parts((4, 0x8, 0, 0), vec![0, 0, 0, 1]); 103 | let frame = WindowUpdateFrame::from_raw(&raw).expect("expected valid WINDOW_UPDATE"); 104 | assert_eq!(frame.increment(), 1); 105 | assert_eq!(frame.get_stream_id(), 0); 106 | } 107 | 108 | #[test] 109 | fn test_parse_valid_max_increment() { 110 | let raw = raw_frame_from_parts((4, 0x8, 0, 0), vec![0xff, 0xff, 0xff, 0xff]); 111 | let frame = WindowUpdateFrame::from_raw(&raw).expect("valid WINDOW_UPDATE"); 112 | // Automatically ignores the reserved bit... 113 | assert_eq!(frame.increment(), 0x7FFFFFFF); 114 | } 115 | 116 | #[test] 117 | fn test_parse_valid_stream_level() { 118 | let raw = raw_frame_from_parts((4, 0x8, 0, 1), vec![0, 0, 0, 1]); 119 | let frame = WindowUpdateFrame::from_raw(&raw).expect("expected valid WINDOW_UPDATE"); 120 | assert_eq!(frame.increment(), 1); 121 | assert_eq!(frame.get_stream_id(), 1); 122 | } 123 | 124 | /// The frame leaves it up to the higher levels to indicate the appropriate error if the 125 | /// increment is invalid. 126 | #[test] 127 | fn test_parse_increment_zero() { 128 | let raw = raw_frame_from_parts((4, 0x8, 0, 1), vec![0, 0, 0, 0]); 129 | let frame = WindowUpdateFrame::from_raw(&raw).expect("expected valid WINDOW_UPDATE"); 130 | assert_eq!(frame.increment(), 0); 131 | assert_eq!(frame.get_stream_id(), 1); 132 | } 133 | 134 | #[test] 135 | fn test_serialize_connection_level() { 136 | let frame = WindowUpdateFrame::for_connection(10); 137 | let expected: Vec = raw_frame_from_parts((4, 0x8, 0, 0), vec![0, 0, 0, 10]).into(); 138 | let serialized = serialize_frame(&frame); 139 | 140 | assert_eq!(expected, serialized); 141 | } 142 | 143 | #[test] 144 | fn test_serialize_stream_level() { 145 | let frame = WindowUpdateFrame::for_stream(1, 10); 146 | let expected: Vec = raw_frame_from_parts((4, 0x8, 0, 1), vec![0, 0, 0, 10]).into(); 147 | let serialized = serialize_frame(&frame); 148 | 149 | assert_eq!(expected, serialized); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/http/priority.rs: -------------------------------------------------------------------------------- 1 | //! The module exposes an API for defining data prioritization strategies. 2 | //! 3 | //! Types that implement the `DataPrioritizer` trait can be used to provide new data for an 4 | //! `HttpConnection` to send to its peer. Neither the `HttpConnection` nor the `DataPrioritizer` 5 | //! have control over exactly *when* the data is sent. This is left up to the particular client 6 | //! implementations to trigger. 7 | 8 | use http::{HttpResult, HttpError}; 9 | use http::connection::{DataChunk, EndStream}; 10 | use http::session::{SessionState, StreamDataChunk, StreamDataError, Stream}; 11 | 12 | /// A trait that types that want to provide data to an HTTP/2 connection need to implement. 13 | pub trait DataPrioritizer { 14 | /// Returns the next `DataChunk` that should be sent on the HTTP/2 connection. `None` indicates 15 | /// that currently there was no data that could be sent at that point. 16 | fn get_next_chunk(&mut self) -> HttpResult>; 17 | } 18 | 19 | /// An implementation of the `DataPrioritizer` trait that is based on finding the first stream from 20 | /// the given `SessionState` instance that can send data and returning this chunk. 21 | /// 22 | /// For all means and purposes, the order of data chunks that the prioritizer returns is undefined 23 | /// and should not be relied on. 24 | pub struct SimplePrioritizer<'a, 'b, State> 25 | where State: SessionState + 'a 26 | { 27 | /// The session state from which the streams' data will be taken 28 | state: &'a mut State, 29 | /// The buffer into which the prioritizer can place the stream data chunk 30 | buf: &'b mut [u8], 31 | } 32 | 33 | impl<'a, 'b, State> SimplePrioritizer<'a, 'b, State> 34 | where State: SessionState + 'a 35 | { 36 | /// Creates a new `SimplePrioritizer` that will use the given state to find stream data that 37 | /// should be sent and use the given buffer to hold the data of the returned chunk. 38 | pub fn new(state: &'a mut State, buf: &'b mut [u8]) -> SimplePrioritizer<'a, 'b, State> { 39 | SimplePrioritizer { 40 | state: state, 41 | buf: buf, 42 | } 43 | } 44 | } 45 | 46 | impl<'a, 'b, State> DataPrioritizer for SimplePrioritizer<'a, 'b, State> 47 | where State: SessionState + 'a 48 | { 49 | fn get_next_chunk(&mut self) -> HttpResult> { 50 | // Returns the data of the first stream that has data to be written. 51 | for (stream_id, stream) in self.state.iter().filter(|&(_, ref s)| !s.is_closed_local()) { 52 | let res = stream.get_data_chunk(self.buf); 53 | match res { 54 | Ok(StreamDataChunk::Last(total)) => { 55 | return Ok(Some(DataChunk::new_borrowed(&self.buf[..total], 56 | *stream_id, 57 | EndStream::Yes))); 58 | } 59 | Ok(StreamDataChunk::Chunk(total)) => { 60 | return Ok(Some(DataChunk::new_borrowed(&self.buf[..total], 61 | *stream_id, 62 | EndStream::No))); 63 | } 64 | Ok(StreamDataChunk::Unavailable) => { 65 | // Stream is still open, but currently has no data that could be sent. 66 | // Pass... 67 | } 68 | Err(StreamDataError::Closed) => { 69 | // Transition the stream state to be locally closed, so we don't attempt to 70 | // write any more data on this stream. 71 | stream.close_local(); 72 | // Find a stream with data to actually write to... 73 | } 74 | Err(StreamDataError::Other(e)) => { 75 | // Any other error is fatal! 76 | return Err(HttpError::Other(e)); 77 | } 78 | }; 79 | } 80 | // Nothing can be sent if we reach here -- no streams have data that can be sent. 81 | Ok(None) 82 | } 83 | } 84 | 85 | #[cfg(test)] 86 | mod tests { 87 | use super::{DataPrioritizer, SimplePrioritizer}; 88 | use http::session::{DefaultSessionState, SessionState}; 89 | use http::session::Client as ClientMarker; 90 | 91 | use http::tests::common::TestStream; 92 | 93 | #[test] 94 | fn test_simple_prioritizer() { 95 | fn prepare_state() -> DefaultSessionState { 96 | DefaultSessionState::::new() 97 | } 98 | 99 | { 100 | // No streams in the session 101 | let mut buf = [0; 5]; 102 | let mut state = prepare_state(); 103 | let mut prioritizer = SimplePrioritizer::new(&mut state, &mut buf); 104 | 105 | let chunk = prioritizer.get_next_chunk().unwrap(); 106 | 107 | assert!(chunk.is_none()); 108 | } 109 | { 110 | // One stream, one chunk 111 | let mut buf = [0; 5]; 112 | let mut state = prepare_state(); 113 | let mut stream = TestStream::new(); 114 | stream.set_outgoing(vec![1, 2, 3]); 115 | state.insert_outgoing(stream); 116 | let mut prioritizer = SimplePrioritizer::new(&mut state, &mut buf); 117 | 118 | { 119 | let chunk = prioritizer.get_next_chunk().unwrap().unwrap(); 120 | assert_eq!(chunk.data, vec![1, 2, 3]); 121 | } 122 | 123 | // Now we have no more data? 124 | assert!(prioritizer.get_next_chunk().unwrap().is_none()); 125 | } 126 | { 127 | // One stream, two chunks 128 | let mut buf = [0; 2]; 129 | let mut state = prepare_state(); 130 | let mut stream = TestStream::new(); 131 | stream.set_outgoing(vec![1, 2, 3]); 132 | state.insert_outgoing(stream); 133 | let mut prioritizer = SimplePrioritizer::new(&mut state, &mut buf); 134 | 135 | { 136 | let chunk = prioritizer.get_next_chunk().unwrap().unwrap(); 137 | assert_eq!(chunk.data, vec![1, 2]); 138 | } 139 | { 140 | let chunk = prioritizer.get_next_chunk().unwrap().unwrap(); 141 | assert_eq!(chunk.data, vec![3]); 142 | } 143 | 144 | // Now we have no more data? 145 | assert!(prioritizer.get_next_chunk().unwrap().is_none()); 146 | } 147 | { 148 | // Multiple streams 149 | let mut buf = [0; 10]; 150 | let mut state = prepare_state(); 151 | for _ in 0..3 { 152 | let mut stream = TestStream::new(); 153 | stream.set_outgoing(vec![1, 2, 3]); 154 | state.insert_outgoing(stream); 155 | } 156 | 157 | // In total, we get 3 frames; we don't know anything about the order of the streams, 158 | // though. 159 | for _ in 0..3 { 160 | { 161 | let mut prioritizer = SimplePrioritizer::new(&mut state, &mut buf); 162 | let chunk = prioritizer.get_next_chunk().unwrap().unwrap(); 163 | assert_eq!(chunk.data, vec![1, 2, 3]); 164 | } 165 | // Zero out the buffer to make sure we don't get false results due to the previous 166 | // data being the same 167 | for b in buf.iter_mut() { 168 | *b = 0; 169 | } 170 | } 171 | 172 | // Now we have no more data? 173 | let mut prioritizer = SimplePrioritizer::new(&mut state, &mut buf); 174 | assert!(prioritizer.get_next_chunk().unwrap().is_none()); 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/http/server.rs: -------------------------------------------------------------------------------- 1 | //! The module contains a number of reusable components for implementing the server side of an 2 | //! HTTP/2 connection. 3 | 4 | use http::{StreamId, Header, HttpResult, HttpScheme, ErrorCode}; 5 | use http::frame::{HttpSetting, PingFrame}; 6 | use http::connection::{SendFrame, ReceiveFrame, HttpConnection, EndStream, SendStatus}; 7 | use http::session::{Session, SessionState, Stream, DefaultStream, DefaultSessionState}; 8 | use http::session::Server as ServerMarker; 9 | use http::priority::SimplePrioritizer; 10 | 11 | /// The `ServerSession` requires an instance of a type that implements this trait in order to 12 | /// create a new `Stream` instance once it detects that a client has initiated a new stream. The 13 | /// factory should take care to provide an appropriate `Stream` implementation that will be able to 14 | /// handle reading the request and generating the response, according to the needs of the 15 | /// underlying application. 16 | pub trait StreamFactory { 17 | type Stream: Stream; 18 | /// Create a new `Stream` with the given ID. 19 | fn create(&mut self, id: StreamId) -> Self::Stream; 20 | } 21 | 22 | /// An implementation of the `Session` trait for a server-side HTTP/2 connection. 23 | pub struct ServerSession<'a, State, F, S> 24 | where State: SessionState + 'a, 25 | S: SendFrame + 'a, 26 | F: StreamFactory + 'a 27 | { 28 | state: &'a mut State, 29 | factory: &'a mut F, 30 | sender: &'a mut S, 31 | } 32 | 33 | impl<'a, State, F, S> ServerSession<'a, State, F, S> 34 | where State: SessionState + 'a, 35 | S: SendFrame + 'a, 36 | F: StreamFactory + 'a 37 | { 38 | #[inline] 39 | pub fn new(state: &'a mut State, 40 | factory: &'a mut F, 41 | sender: &'a mut S) 42 | -> ServerSession<'a, State, F, S> { 43 | ServerSession { 44 | state: state, 45 | factory: factory, 46 | sender: sender, 47 | } 48 | } 49 | } 50 | 51 | impl<'a, State, F, S> Session for ServerSession<'a, State, F, S> 52 | where State: SessionState + 'a, 53 | S: SendFrame + 'a, 54 | F: StreamFactory + 'a 55 | { 56 | fn new_data_chunk(&mut self, 57 | stream_id: StreamId, 58 | data: &[u8], 59 | _: &mut HttpConnection) 60 | -> HttpResult<()> { 61 | debug!("Data chunk for stream {}", stream_id); 62 | let mut stream = match self.state.get_stream_mut(stream_id) { 63 | None => { 64 | debug!("Received a frame for an unknown stream!"); 65 | return Ok(()); 66 | } 67 | Some(stream) => stream, 68 | }; 69 | // Now let the stream handle the data chunk 70 | stream.new_data_chunk(data); 71 | Ok(()) 72 | } 73 | 74 | fn new_headers<'n, 'v>(&mut self, 75 | stream_id: StreamId, 76 | headers: Vec>, 77 | _conn: &mut HttpConnection) 78 | -> HttpResult<()> { 79 | debug!("Headers for stream {}", stream_id); 80 | if let Some(stream) = self.state.get_stream_mut(stream_id) { 81 | // This'd correspond to having received trailers... 82 | stream.set_headers(headers); 83 | return Ok(()); 84 | }; 85 | // New stream initiated by the client 86 | let mut stream = self.factory.create(stream_id); 87 | stream.set_headers(headers); 88 | // TODO(mlalic): Once the `Session` trait is able to signal connection failure, handle 89 | // the error case here and return the corresponding protocol error. 90 | let _ = self.state.insert_incoming(stream_id, stream); 91 | Ok(()) 92 | } 93 | 94 | fn end_of_stream(&mut self, stream_id: StreamId, _: &mut HttpConnection) -> HttpResult<()> { 95 | debug!("End of stream {}", stream_id); 96 | let mut stream = match self.state.get_stream_mut(stream_id) { 97 | None => { 98 | debug!("Received a frame for an unknown stream!"); 99 | return Ok(()); 100 | } 101 | Some(stream) => stream, 102 | }; 103 | stream.close_remote(); 104 | Ok(()) 105 | } 106 | 107 | fn rst_stream(&mut self, 108 | stream_id: StreamId, 109 | error_code: ErrorCode, 110 | _: &mut HttpConnection) 111 | -> HttpResult<()> { 112 | debug!("RST_STREAM id={:?}, error={:?}", stream_id, error_code); 113 | self.state.get_stream_mut(stream_id).map(|stream| stream.on_rst_stream(error_code)); 114 | Ok(()) 115 | } 116 | 117 | fn new_settings(&mut self, 118 | _settings: Vec, 119 | conn: &mut HttpConnection) 120 | -> HttpResult<()> { 121 | debug!("Sending a SETTINGS ack"); 122 | conn.sender(self.sender).send_settings_ack() 123 | } 124 | 125 | fn on_ping(&mut self, ping: &PingFrame, conn: &mut HttpConnection) -> HttpResult<()> { 126 | debug!("Sending a PING ack"); 127 | conn.sender(self.sender).send_ping_ack(ping.opaque_data()) 128 | } 129 | 130 | fn on_pong(&mut self, _ping: &PingFrame, _conn: &mut HttpConnection) -> HttpResult<()> { 131 | debug!("Received a PING ack"); 132 | Ok(()) 133 | } 134 | } 135 | 136 | /// The struct provides a more convenient API for server-related functionality of an HTTP/2 137 | /// connection, such as sending a response back to the client. 138 | pub struct ServerConnection> 139 | where State: SessionState, 140 | F: StreamFactory 141 | { 142 | /// The underlying `HttpConnection` that will be used for any HTTP/2 143 | /// communication. 144 | conn: HttpConnection, 145 | /// The state of the session associated to this client connection. Maintains the status of the 146 | /// connection streams. 147 | pub state: State, 148 | /// Creates `Stream` instances for client-initiated streams. This allows the client of the 149 | /// `ServerConnection` to implement custom handling of a newly initiated stream. 150 | factory: F, 151 | } 152 | 153 | impl ServerConnection 154 | where State: SessionState, 155 | F: StreamFactory 156 | { 157 | /// Creates a new `ServerConnection` that will use the given `HttpConnection` for its 158 | /// underlying HTTP/2 communication. The `state` and `factory` represent, respectively, the 159 | /// initial state of the connection and an instance of the `StreamFactory` type (allowing the 160 | /// client to handle newly created streams). 161 | pub fn with_connection(conn: HttpConnection, 162 | state: State, 163 | factory: F) 164 | -> ServerConnection { 165 | ServerConnection { 166 | conn: conn, 167 | state: state, 168 | factory: factory, 169 | } 170 | } 171 | 172 | /// Returns the scheme of the underlying `HttpConnection`. 173 | #[inline] 174 | pub fn scheme(&self) -> HttpScheme { 175 | self.conn.scheme 176 | } 177 | 178 | /// Send the current settings associated to the `ServerConnection` to the client. 179 | pub fn send_settings(&mut self, sender: &mut S) -> HttpResult<()> { 180 | // TODO: `HttpConnection` should provide a better API for sending settings. 181 | self.conn.sender(sender).send_settings_ack() 182 | } 183 | 184 | /// Handles the next frame on the given `ReceiveFrame` instance and expects it to be a 185 | /// (non-ACK) SETTINGS frame. Returns an error if not. 186 | pub fn expect_settings(&mut self, 187 | rx: &mut Recv, 188 | tx: &mut Sender) 189 | -> HttpResult<()> { 190 | let mut session = ServerSession::new(&mut self.state, &mut self.factory, tx); 191 | self.conn.expect_settings(rx, &mut session) 192 | } 193 | 194 | /// Fully handles the next frame provided by the given `ReceiveFrame` instance. 195 | /// Handling the frame can cause the session state of the `ServerConnection` to update. 196 | #[inline] 197 | pub fn handle_next_frame(&mut self, 198 | rx: &mut Recv, 199 | tx: &mut Sender) 200 | -> HttpResult<()> { 201 | let mut session = ServerSession::new(&mut self.state, &mut self.factory, tx); 202 | self.conn.handle_next_frame(rx, &mut session) 203 | } 204 | 205 | /// Starts a response on the stream with the given ID by sending the given headers. 206 | /// 207 | /// The body of the response is assumed to be provided by the `Stream` instance stored within 208 | /// the connection's state. (The body does not have to be ready when this method is called, as 209 | /// long as the `Stream` instance knows how to provide it to the connection later on.) 210 | #[inline] 211 | pub fn start_response<'n, 'v, S: SendFrame>(&mut self, 212 | headers: Vec>, 213 | stream_id: StreamId, 214 | end_stream: EndStream, 215 | sender: &mut S) 216 | -> HttpResult<()> { 217 | self.conn.sender(sender).send_headers(headers, stream_id, end_stream) 218 | } 219 | 220 | /// Queues a new DATA frame onto the underlying `SendFrame`. 221 | /// 222 | /// Currently, no prioritization of streams is taken into account and which stream's data is 223 | /// queued cannot be relied on. 224 | pub fn send_next_data(&mut self, sender: &mut S) -> HttpResult { 225 | debug!("Sending next data..."); 226 | // A default "maximum" chunk size of 8 KiB is set on all data frames. 227 | const MAX_CHUNK_SIZE: usize = 8 * 1024; 228 | let mut buf = [0; MAX_CHUNK_SIZE]; 229 | 230 | // TODO: Additionally account for the flow control windows. 231 | let mut prioritizer = SimplePrioritizer::new(&mut self.state, &mut buf); 232 | 233 | self.conn.sender(sender).send_next_data(&mut prioritizer) 234 | } 235 | } 236 | 237 | #[cfg(test)] 238 | mod tests { 239 | use super::ServerSession; 240 | 241 | use http::tests::common::{TestStream, TestStreamFactory, build_mock_http_conn, MockSendFrame}; 242 | 243 | use http::{Header, ErrorCode, HttpError}; 244 | use http::session::{DefaultSessionState, SessionState, Stream, Session}; 245 | use http::session::Server as ServerMarker; 246 | 247 | /// Tests that the `ServerSession` correctly manages the stream state. 248 | #[test] 249 | fn test_server_session() { 250 | let mut state = DefaultSessionState::::new(); 251 | let mut conn = build_mock_http_conn(); 252 | let mut sender = MockSendFrame::new(); 253 | 254 | // Receiving new headers results in a new stream being created 255 | let headers = vec![Header::new(b":method".to_vec(), b"GET".to_vec())]; 256 | { 257 | let mut factory = TestStreamFactory; 258 | let mut session = ServerSession::new(&mut state, &mut factory, &mut sender); 259 | session.new_headers(1, headers.clone(), &mut conn).unwrap(); 260 | } 261 | assert!(state.get_stream_ref(1).is_some()); 262 | assert_eq!(state.get_stream_ref(1).unwrap().headers.clone().unwrap(), 263 | headers); 264 | // Now some data arrives on the stream... 265 | { 266 | let mut factory = TestStreamFactory; 267 | let mut session = ServerSession::new(&mut state, &mut factory, &mut sender); 268 | session.new_data_chunk(1, &[1, 2, 3], &mut conn).unwrap(); 269 | } 270 | // ...works. 271 | assert_eq!(state.get_stream_ref(1).unwrap().body, vec![1, 2, 3]); 272 | // Some more data... 273 | { 274 | let mut factory = TestStreamFactory; 275 | let mut session = ServerSession::new(&mut state, &mut factory, &mut sender); 276 | session.new_data_chunk(1, &[4], &mut conn).unwrap(); 277 | } 278 | // ...all good. 279 | assert_eq!(state.get_stream_ref(1).unwrap().body, vec![1, 2, 3, 4]); 280 | // Add another stream in the mix 281 | { 282 | let mut factory = TestStreamFactory; 283 | let mut session = ServerSession::new(&mut state, &mut factory, &mut sender); 284 | session.new_headers(3, headers.clone(), &mut conn).unwrap(); 285 | session.new_data_chunk(3, &[100], &mut conn).unwrap(); 286 | } 287 | assert!(state.get_stream_ref(3).is_some()); 288 | assert_eq!(state.get_stream_ref(3).unwrap().headers.clone().unwrap(), 289 | headers); 290 | assert_eq!(state.get_stream_ref(3).unwrap().body, vec![100]); 291 | { 292 | // Finally, the stream 1 ends... 293 | let mut factory = TestStreamFactory; 294 | let mut session = ServerSession::new(&mut state, &mut factory, &mut sender); 295 | session.end_of_stream(1, &mut conn).unwrap(); 296 | } 297 | // ...and gets closed. 298 | assert!(state.get_stream_ref(1).unwrap().is_closed_remote()); 299 | // but not the other one. 300 | assert!(!state.get_stream_ref(3).unwrap().is_closed_remote()); 301 | } 302 | 303 | #[test] 304 | fn test_server_session_rst_stream() { 305 | let mut state = DefaultSessionState::::new(); 306 | let mut conn = build_mock_http_conn(); 307 | let mut sender = MockSendFrame::new(); 308 | state.insert_incoming(1, TestStream::new()).unwrap(); 309 | state.insert_incoming(3, TestStream::new()).unwrap(); 310 | state.insert_incoming(5, TestStream::new()).unwrap(); 311 | { 312 | let mut factory = TestStreamFactory; 313 | let mut session = ServerSession::new(&mut state, &mut factory, &mut sender); 314 | session.rst_stream(3, ErrorCode::Cancel, &mut conn).unwrap(); 315 | } 316 | assert!(state.get_stream_ref(1).map(|stream| stream.errors.len() == 0).unwrap()); 317 | assert!(state.get_stream_ref(3) 318 | .map(|stream| { 319 | stream.errors.len() == 1 && stream.errors[0] == ErrorCode::Cancel 320 | }) 321 | .unwrap()); 322 | assert!(state.get_stream_ref(5).map(|stream| stream.errors.len() == 0).unwrap()); 323 | } 324 | 325 | /// When the server session is told to goaway by the client, we signal an error to the client 326 | /// code, surfacing the underlying reason. 327 | #[test] 328 | fn test_server_session_on_goaway() { 329 | let mut state = DefaultSessionState::::new(); 330 | let mut conn = build_mock_http_conn(); 331 | let mut sender = MockSendFrame::new(); 332 | let res = { 333 | let mut factory = TestStreamFactory; 334 | let mut session = ServerSession::new(&mut state, &mut factory, &mut sender); 335 | session.on_goaway(0, ErrorCode::ProtocolError, None, &mut conn) 336 | }; 337 | if let Err(HttpError::PeerConnectionError(err)) = res { 338 | assert_eq!(err.error_code(), ErrorCode::ProtocolError); 339 | assert_eq!(err.debug_data(), None); 340 | } else { 341 | panic!("Expected a PeerConnectionError"); 342 | } 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /src/http/tests/common.rs: -------------------------------------------------------------------------------- 1 | //! The module contains some common utilities for `solicit::http` tests. 2 | 3 | use std::io; 4 | use std::rc::Rc; 5 | use std::cell::{RefCell, Cell}; 6 | use std::borrow::Cow; 7 | use std::io::{Cursor, Read, Write}; 8 | 9 | use http::{HttpResult, HttpScheme, StreamId, Header, OwnedHeader, ErrorCode}; 10 | use http::frame::{RawFrame, FrameIR, FrameHeader, pack_header, HttpSetting, PingFrame}; 11 | use http::session::{Session, DefaultSessionState, SessionState, Stream, StreamState, 12 | StreamDataChunk, StreamDataError}; 13 | use http::session::Client as ClientMarker; 14 | use http::priority::DataPrioritizer; 15 | use http::transport::TransportStream; 16 | use http::connection::{SendFrame, ReceiveFrame, HttpFrame, HttpConnection, EndStream, DataChunk}; 17 | use http::client::ClientConnection; 18 | use http::server::StreamFactory; 19 | 20 | /// Creates a new `RawFrame` from two separate parts: the header and the payload. 21 | /// Useful for tests that need to create frames, since they can easily specify the header and the 22 | /// payload separately and use this function to stitch them together into a `RawFrame`. 23 | pub fn raw_frame_from_parts<'a>(header: FrameHeader, payload: Vec) -> RawFrame<'a> { 24 | let mut buf = Vec::new(); 25 | assert_eq!(9, buf.write(&pack_header(&header)[..]).unwrap()); 26 | assert_eq!(payload.len(), buf.write(&payload).unwrap()); 27 | buf.into() 28 | } 29 | 30 | /// Serializes the given frame into a newly allocated vector (without consuming the frame). 31 | pub fn serialize_frame(frame: &F) -> Vec { 32 | let mut buf = io::Cursor::new(Vec::new()); 33 | frame.clone().serialize_into(&mut buf).ok().expect("Expected the serialization to succeed"); 34 | buf.into_inner() 35 | } 36 | 37 | /// A mock `SendFrame` implementation that simply saves all frames that it is to send to a `Vec`. 38 | pub struct MockSendFrame { 39 | pub sent: Vec>, 40 | } 41 | 42 | impl MockSendFrame { 43 | pub fn new() -> MockSendFrame { 44 | MockSendFrame { sent: Vec::new() } 45 | } 46 | } 47 | 48 | impl SendFrame for MockSendFrame { 49 | fn send_frame(&mut self, frame: F) -> HttpResult<()> { 50 | let mut buf = io::Cursor::new(Vec::new()); 51 | frame.serialize_into(&mut buf).unwrap(); 52 | let raw = buf.into_inner().into(); 53 | self.sent.push(raw); 54 | Ok(()) 55 | } 56 | } 57 | 58 | /// A mock `ReceiveFrame` implementation that simply serves the frames from a `Vec`. 59 | pub struct MockReceiveFrame<'a> { 60 | pub recv_list: Vec>, 61 | } 62 | 63 | impl<'a> MockReceiveFrame<'a> { 64 | pub fn new(recv_list: Vec>) -> MockReceiveFrame<'a> { 65 | MockReceiveFrame { recv_list: recv_list } 66 | } 67 | } 68 | 69 | impl<'a> ReceiveFrame for MockReceiveFrame<'a> { 70 | fn recv_frame(&mut self) -> HttpResult { 71 | if self.recv_list.len() != 0 { 72 | Ok(self.recv_list.remove(0)) 73 | } else { 74 | Err(io::Error::new(io::ErrorKind::Other, "End of Frame List").into()) 75 | } 76 | } 77 | } 78 | 79 | pub type MockHttpConnection = HttpConnection; 80 | 81 | /// A helper function that creates an `HttpConnection` with the `MockSendFrame` and the 82 | /// `MockReceiveFrame` as its underlying frame handlers. 83 | pub fn build_mock_http_conn() -> MockHttpConnection { 84 | HttpConnection::new(HttpScheme::Http) 85 | } 86 | 87 | /// A helper stub implementation of a `TransportStream`. 88 | /// 89 | /// When read from this stream, it spits out bytes from a predefined `Vec` 90 | /// in the original given order. Once those are exhausted, it returns an EOF. 91 | /// 92 | /// When writng to the stream, the bytes are aggregated to internal buffer. 93 | /// The contents of the buffer can be accessed using the `get_writted` 94 | /// method. 95 | /// 96 | /// It is possible to "close" the stream (both ends at once) so that 97 | /// aftwerwards any read or write attempt returns an `io::Error`; 98 | #[derive(Clone)] 99 | pub struct StubTransportStream { 100 | reader: Rc>>>, 101 | writer: Rc>>>, 102 | closed: Rc>, 103 | } 104 | 105 | impl StubTransportStream { 106 | /// Initializes the stream with the given byte vector representing 107 | /// the bytes that will be read from the stream. 108 | pub fn with_stub_content(stub: &[u8]) -> StubTransportStream { 109 | StubTransportStream { 110 | reader: Rc::new(RefCell::new(Cursor::new(stub.to_vec()))), 111 | writer: Rc::new(RefCell::new(Cursor::new(Vec::new()))), 112 | closed: Rc::new(Cell::new(false)), 113 | } 114 | } 115 | 116 | /// Returns a slice representing the bytes already written to the 117 | /// stream. 118 | pub fn get_written(&self) -> Vec { 119 | self.writer.borrow().get_ref().to_vec() 120 | } 121 | } 122 | 123 | impl io::Read for StubTransportStream { 124 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 125 | if self.closed.get() { 126 | Err(io::Error::new(io::ErrorKind::Other, "Closed")) 127 | } else { 128 | self.reader.borrow_mut().read(buf) 129 | } 130 | } 131 | } 132 | 133 | impl io::Write for StubTransportStream { 134 | fn write(&mut self, buf: &[u8]) -> io::Result { 135 | if self.closed.get() { 136 | Err(io::Error::new(io::ErrorKind::Other, "Closed")) 137 | } else { 138 | self.writer.borrow_mut().write(buf) 139 | } 140 | } 141 | 142 | fn flush(&mut self) -> io::Result<()> { 143 | self.writer.borrow_mut().flush() 144 | } 145 | } 146 | 147 | impl TransportStream for StubTransportStream { 148 | fn try_split(&self) -> Result { 149 | Ok(self.clone()) 150 | } 151 | 152 | /// Closes the stream, making any read or write operation return an 153 | /// `io::Error` from there on out. 154 | fn close(&mut self) -> io::Result<()> { 155 | self.closed.set(true); 156 | Ok(()) 157 | } 158 | } 159 | 160 | /// A helper function that builds a buffer of bytes from the given `Vec` of 161 | /// `HttpFrame`s, by serializing them in the given order. 162 | pub fn build_stub_from_frames(frames: &Vec) -> Vec { 163 | let mut buf: Vec = Vec::new(); 164 | for frame in frames.iter() { 165 | let serialized = match *frame { 166 | HttpFrame::DataFrame(ref frame) => serialize_frame(frame), 167 | HttpFrame::HeadersFrame(ref frame) => serialize_frame(frame), 168 | HttpFrame::RstStreamFrame(ref frame) => serialize_frame(frame), 169 | HttpFrame::SettingsFrame(ref frame) => serialize_frame(frame), 170 | HttpFrame::PingFrame(ref frame) => serialize_frame(frame), 171 | HttpFrame::GoawayFrame(ref frame) => serialize_frame(frame), 172 | HttpFrame::WindowUpdateFrame(ref frame) => serialize_frame(frame), 173 | HttpFrame::UnknownFrame(ref frame) => serialize_frame(frame), 174 | }; 175 | buf.extend(serialized.into_iter()); 176 | } 177 | 178 | buf 179 | } 180 | 181 | /// A test that makes sure that the `StubTransportStream` exhibits 182 | /// properties that a "real" `TransportStream` would too. 183 | #[test] 184 | fn sanity_check_stub_stream() { 185 | // `read` returns 0 at the "end of file"? 186 | { 187 | let mut stream = StubTransportStream::with_stub_content(&vec![]); 188 | let mut buf = [0u8; 5]; 189 | assert_eq!(stream.read(&mut buf).unwrap(), 0); 190 | assert_eq!(stream.read(&mut buf).unwrap(), 0); 191 | } 192 | // A closed stream always returns an io::Error 193 | { 194 | let mut stream = StubTransportStream::with_stub_content(&vec![]); 195 | stream.close().unwrap(); 196 | assert!(stream.write(&[1]).is_err()); 197 | assert!(stream.read(&mut [0; 5]).is_err()); 198 | } 199 | // A stream can be split 200 | { 201 | let mut stream = StubTransportStream::with_stub_content(&vec![3, 4]); 202 | let mut other = stream.try_split().unwrap(); 203 | // Write something using both of them 204 | stream.write(&[1]).unwrap(); 205 | other.write(&[2]).unwrap(); 206 | assert_eq!(&[1, 2], &stream.get_written()[..]); 207 | assert_eq!(&[1, 2], &other.get_written()[..]); 208 | // Try reading independently... 209 | let mut buf = [0]; 210 | stream.read(&mut buf).unwrap(); 211 | assert_eq!(&[3], &buf); 212 | other.read(&mut buf).unwrap(); 213 | assert_eq!(&[4], &buf); 214 | } 215 | // Closing one handle of the stream closes all handles 216 | { 217 | let mut stream = StubTransportStream::with_stub_content(&vec![3, 4]); 218 | let mut other = stream.try_split().unwrap(); 219 | other.close().unwrap(); 220 | assert!(stream.write(&[1]).is_err()); 221 | assert!(stream.read(&mut [0; 5]).is_err()); 222 | } 223 | } 224 | 225 | /// A helper struct implementing the `Session` trait, intended for testing 226 | /// purposes. 227 | /// 228 | /// It is basically a poor man's mock, providing us the ability to check 229 | /// how many times the particular callbacks were called (although not the 230 | /// order in which they were called). 231 | /// 232 | /// Additionally, when created with `new_verify` it is possible to provide 233 | /// a list of headers and data chunks and make the session verify that it 234 | /// them from the connection in the exactly given order (i.e. relative 235 | /// order of chunks and headers; there is no way to check the order between 236 | /// chunks and headers for now). 237 | pub struct TestSession { 238 | pub silent: bool, 239 | /// List of expected headers -- in the order that they are expected 240 | pub headers: Vec>, 241 | /// List of expected data chunks -- in the order that they are expected 242 | pub chunks: Vec>, 243 | /// The current number of header calls. 244 | pub curr_header: usize, 245 | /// The current number of data chunk calls. 246 | pub curr_chunk: usize, 247 | /// The current number of `rst_stream` calls. 248 | pub rst_streams: Vec, 249 | /// All the goaway error codes received. 250 | pub goaways: Vec, 251 | /// All the ping data received 252 | pub pings: Vec, 253 | /// All the ping ack data received 254 | pub pongs: Vec, 255 | } 256 | 257 | impl TestSession { 258 | /// Returns a new `TestSession` that only counts how many times the 259 | /// callback methods were invoked. 260 | pub fn new() -> TestSession { 261 | TestSession { 262 | silent: true, 263 | headers: Vec::new(), 264 | chunks: Vec::new(), 265 | curr_header: 0, 266 | curr_chunk: 0, 267 | rst_streams: Vec::new(), 268 | goaways: Vec::new(), 269 | pings: Vec::new(), 270 | pongs: Vec::new(), 271 | } 272 | } 273 | 274 | /// Returns a new `TestSession` that veriies that the headers received 275 | /// in the callbacks are equal to those in the given headers `Vec` and 276 | /// that they come in exactly the given order. Does the same for chunks. 277 | pub fn new_verify(headers: Vec>, chunks: Vec>) -> TestSession { 278 | TestSession { 279 | silent: false, 280 | headers: headers, 281 | chunks: chunks, 282 | curr_header: 0, 283 | curr_chunk: 0, 284 | rst_streams: Vec::new(), 285 | goaways: Vec::new(), 286 | pings: Vec::new(), 287 | pongs: Vec::new(), 288 | } 289 | } 290 | } 291 | 292 | impl Session for TestSession { 293 | fn new_data_chunk(&mut self, 294 | _: StreamId, 295 | data: &[u8], 296 | _: &mut HttpConnection) 297 | -> HttpResult<()> { 298 | if !self.silent { 299 | assert_eq!(&self.chunks[self.curr_chunk], &data); 300 | } 301 | self.curr_chunk += 1; 302 | Ok(()) 303 | } 304 | 305 | fn new_headers<'n, 'v>(&mut self, 306 | _: StreamId, 307 | headers: Vec>, 308 | _: &mut HttpConnection) 309 | -> HttpResult<()> { 310 | if !self.silent { 311 | assert_eq!(self.headers[self.curr_header], headers); 312 | } 313 | self.curr_header += 1; 314 | Ok(()) 315 | } 316 | 317 | fn end_of_stream(&mut self, _: StreamId, _: &mut HttpConnection) -> HttpResult<()> { 318 | Ok(()) 319 | } 320 | 321 | fn rst_stream(&mut self, 322 | stream_id: StreamId, 323 | _: ErrorCode, 324 | _: &mut HttpConnection) 325 | -> HttpResult<()> { 326 | self.rst_streams.push(stream_id); 327 | Ok(()) 328 | } 329 | 330 | fn new_settings(&mut self, 331 | _settings: Vec, 332 | _conn: &mut HttpConnection) 333 | -> HttpResult<()> { 334 | Ok(()) 335 | } 336 | 337 | fn on_goaway(&mut self, 338 | _: StreamId, 339 | error_code: ErrorCode, 340 | _: Option<&[u8]>, 341 | _: &mut HttpConnection) 342 | -> HttpResult<()> { 343 | self.goaways.push(error_code); 344 | Ok(()) 345 | } 346 | 347 | fn on_ping(&mut self, ping: &PingFrame, _conn: &mut HttpConnection) -> HttpResult<()> { 348 | self.pings.push(ping.opaque_data()); 349 | Ok(()) 350 | } 351 | 352 | fn on_pong(&mut self, ping: &PingFrame, _conn: &mut HttpConnection) -> HttpResult<()> { 353 | self.pongs.push(ping.opaque_data()); 354 | Ok(()) 355 | } 356 | } 357 | 358 | /// A stream that can be used for testing purposes. 359 | pub struct TestStream { 360 | pub body: Vec, 361 | pub headers: Option>, 362 | pub state: StreamState, 363 | pub outgoing: Option>>, 364 | pub errors: Vec, 365 | } 366 | 367 | impl TestStream { 368 | pub fn new() -> TestStream { 369 | TestStream { 370 | body: Vec::new(), 371 | headers: None, 372 | state: StreamState::Open, 373 | outgoing: None, 374 | errors: Vec::new(), 375 | } 376 | } 377 | 378 | #[inline] 379 | pub fn set_outgoing(&mut self, outgoing: Vec) { 380 | self.outgoing = Some(Cursor::new(outgoing)); 381 | } 382 | } 383 | 384 | impl Stream for TestStream { 385 | fn new_data_chunk(&mut self, data: &[u8]) { 386 | self.body.extend(data.to_vec()); 387 | } 388 | fn set_headers<'n, 'v>(&mut self, headers: Vec>) { 389 | self.headers = Some(headers.into_iter() 390 | .map(|h| { 391 | let owned: OwnedHeader = h.into(); 392 | owned.into() 393 | }) 394 | .collect()); 395 | } 396 | fn set_state(&mut self, state: StreamState) { 397 | self.state = state; 398 | } 399 | 400 | fn on_rst_stream(&mut self, error: ErrorCode) { 401 | self.errors.push(error); 402 | self.close(); 403 | } 404 | fn get_data_chunk(&mut self, buf: &mut [u8]) -> Result { 405 | if self.is_closed_local() { 406 | return Err(StreamDataError::Closed); 407 | } 408 | let chunk = match self.outgoing.as_mut() { 409 | // No data associated to the stream, but it's open => nothing available for writing 410 | None => StreamDataChunk::Unavailable, 411 | Some(d) => { 412 | // For the `Vec`-backed reader, this should never fail, so unwrapping is 413 | // fine. 414 | let read = d.read(buf).unwrap(); 415 | if (d.position() as usize) == d.get_ref().len() { 416 | StreamDataChunk::Last(read) 417 | } else { 418 | StreamDataChunk::Chunk(read) 419 | } 420 | } 421 | }; 422 | // Transition the stream state to locally closed if we've extracted the final data chunk. 423 | match chunk { 424 | StreamDataChunk::Last(_) => self.close_local(), 425 | _ => {} 426 | }; 427 | 428 | Ok(chunk) 429 | } 430 | 431 | fn state(&self) -> StreamState { 432 | self.state 433 | } 434 | } 435 | 436 | pub struct TestStreamFactory; 437 | impl StreamFactory for TestStreamFactory { 438 | type Stream = TestStream; 439 | fn create(&mut self, _id: StreamId) -> TestStream { 440 | TestStream::new() 441 | } 442 | } 443 | 444 | /// A `DataPrioritizer` implementation that returns data chunks from a predefined buffer given to 445 | /// it at construct time (always on stream ID 1). 446 | pub struct StubDataPrioritizer { 447 | pub chunks: Vec>, 448 | } 449 | 450 | impl StubDataPrioritizer { 451 | pub fn new(chunks: Vec>) -> StubDataPrioritizer { 452 | StubDataPrioritizer { chunks: chunks } 453 | } 454 | } 455 | 456 | impl DataPrioritizer for StubDataPrioritizer { 457 | fn get_next_chunk(&mut self) -> HttpResult> { 458 | if self.chunks.len() == 0 { 459 | return Ok(None); 460 | } 461 | let chunk = self.chunks.remove(0); 462 | Ok(Some(DataChunk { 463 | stream_id: 1, 464 | data: Cow::Owned(chunk), 465 | end_stream: EndStream::No, 466 | })) 467 | } 468 | } 469 | 470 | /// A type alias for a `ClientConnection` with mock replacements for its dependent types. 471 | pub type MockClientConnection = ClientConnection>; 472 | 473 | /// Returns a `ClientConnection` suitable for use in tests. 474 | #[inline] 475 | pub fn build_mock_client_conn() -> MockClientConnection { 476 | ClientConnection::with_connection(build_mock_http_conn(), 477 | DefaultSessionState::::new()) 478 | } 479 | -------------------------------------------------------------------------------- /src/http/tests/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | pub mod common; 3 | 4 | /// Tests for the structs defined in the root of the `solicit::http` module. 5 | #[cfg(test)] 6 | mod root_tests { 7 | use http::{Response, HttpError, HttpScheme, ErrorCode, ConnectionError}; 8 | use std::error::Error; 9 | 10 | /// Tests that the `Response` struct correctly parses a status code from 11 | /// its headers list. 12 | #[test] 13 | fn test_parse_status_code_response() { 14 | { 15 | // Only status => Ok 16 | let resp = Response::new(1, vec![(b":status".to_vec(), b"200".to_vec())], vec![]); 17 | assert_eq!(resp.status_code().ok().unwrap(), 200); 18 | } 19 | { 20 | // Extra headers => still works 21 | let resp = Response::new(1, 22 | vec![(b":status".to_vec(), b"200".to_vec()), 23 | (b"key".to_vec(), b"val".to_vec())], 24 | vec![]); 25 | assert_eq!(resp.status_code().ok().unwrap(), 200); 26 | } 27 | { 28 | // Status is not the first header => malformed 29 | let resp = Response::new(1, 30 | vec![(b"key".to_vec(), b"val".to_vec()), 31 | (b":status".to_vec(), b"200".to_vec())], 32 | vec![]); 33 | assert_eq!(resp.status_code().err().unwrap(), 34 | HttpError::MalformedResponse); 35 | } 36 | { 37 | // No headers at all => Malformed 38 | let resp = Response::new(1, vec![], vec![]); 39 | assert_eq!(resp.status_code().err().unwrap(), 40 | HttpError::MalformedResponse); 41 | } 42 | } 43 | 44 | #[test] 45 | fn test_connection_error_no_debug_data() { 46 | let err = ConnectionError::new(ErrorCode::ProtocolError); 47 | assert_eq!(err.error_code(), ErrorCode::ProtocolError); 48 | assert!(err.debug_data().is_none()); 49 | assert!(err.debug_str().is_none()); 50 | assert_eq!(err.description(), "ProtocolError"); 51 | } 52 | 53 | #[test] 54 | fn test_connection_error_raw_debug_data() { 55 | let err = ConnectionError::with_debug_data(ErrorCode::ProtocolError, vec![0x80]); 56 | assert_eq!(err.error_code(), ErrorCode::ProtocolError); 57 | assert_eq!(err.debug_data().unwrap(), &[0x80][..]); 58 | assert!(err.debug_str().is_none()); 59 | assert_eq!(err.description(), "ProtocolError"); 60 | } 61 | 62 | #[test] 63 | fn test_connection_error_str_debug_data() { 64 | let err = ConnectionError::with_debug_data(ErrorCode::ProtocolError, b"Test".to_vec()); 65 | assert_eq!(err.error_code(), ErrorCode::ProtocolError); 66 | assert_eq!(err.debug_data().unwrap(), b"Test"); 67 | assert_eq!(err.debug_str().unwrap(), "Test"); 68 | assert_eq!(err.description(), "Test"); 69 | } 70 | 71 | /// Tests that the `HttpScheme` enum returns the correct scheme strings for 72 | /// the two variants. 73 | #[test] 74 | fn test_scheme_string() { 75 | assert_eq!(HttpScheme::Http.as_bytes(), b"http"); 76 | assert_eq!(HttpScheme::Https.as_bytes(), b"https"); 77 | } 78 | 79 | /// Make sure that the `HttpError` is both `Sync` and `Send` 80 | #[test] 81 | fn _assert_error_is_sync_send() { 82 | fn _is_sync_send() {} 83 | _is_sync_send::(); 84 | } 85 | } 86 | 87 | #[cfg(test)] 88 | mod test_header { 89 | use http::{Header, OwnedHeader}; 90 | use std::borrow::Cow; 91 | 92 | fn _assert_is_static(_: Header<'static, 'static>) {} 93 | 94 | #[test] 95 | fn test_owned_to_header_is_static_lifetime() { 96 | let owned = (vec![1u8], vec![2u8]); 97 | _assert_is_static(owned.into()); 98 | } 99 | 100 | #[test] 101 | fn test_header_from_static_slices_lifetime() { 102 | let header = Header::new(b":method", b"GET"); 103 | _assert_is_static(header); 104 | } 105 | 106 | #[test] 107 | fn test_header_to_owned_header() { 108 | let header = Header::new(b":method", b"GET"); 109 | let (name, value): OwnedHeader = header.into(); 110 | 111 | assert_eq!(name, b":method".to_vec()); 112 | assert_eq!(value, b"GET".to_vec()); 113 | } 114 | 115 | #[test] 116 | fn test_partial_eq_of_headers() { 117 | let fully_static = Header::new(b":method", b"GET"); 118 | let static_name = Header::new(b":method", b"GET".to_vec()); 119 | let other = Header::new(b":path", b"/"); 120 | 121 | assert!(fully_static == static_name); 122 | assert!(fully_static != other); 123 | assert!(static_name != other); 124 | } 125 | 126 | #[test] 127 | fn test_partial_eq_to_owned_header() { 128 | let fully_static = Header::new(b":method", b"GET"); 129 | let owned: OwnedHeader = fully_static.clone().into(); 130 | 131 | assert!(fully_static == owned); 132 | } 133 | 134 | #[test] 135 | fn test_clone_keeps_borrows() { 136 | let header = Header::new(b":method", b"GET"); 137 | let clone = header.clone(); 138 | 139 | match clone.name { 140 | Cow::Owned(_) => panic!("Expected a borrowed name"), 141 | _ => {} 142 | }; 143 | match clone.value { 144 | Cow::Owned(_) => panic!("Expected a borrowed value"), 145 | _ => {} 146 | }; 147 | } 148 | 149 | #[test] 150 | fn test_debug() { 151 | assert_eq!( 152 | "Header { name: b\":method\", value: b\"GET\" }", 153 | format!("{:?}", Header::new(b":method", b"GET"))); 154 | assert_eq!( 155 | "Header { name: b\":method\", value: b\"\\xcd\" }", 156 | format!("{:?}", Header::new(b":method", b"\xcd"))); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/http/transport.rs: -------------------------------------------------------------------------------- 1 | //! The module contains implementations of the transport layer functionality 2 | //! that HTTP/2 requires. It exposes APIs that allow the HTTP/2 connection to 3 | //! use the transport layer without requiring it to know which exact 4 | //! implementation they are using (e.g. a clear-text TCP connection, a TLS 5 | //! protected connection, or even a mock implementation). 6 | //! 7 | //! The types provided here are purely for convenience in being able to easily 8 | //! plug in the native Rust socket IO primitives into the HTTP/2 connection API 9 | //! without having to write too much boilerplate around them. 10 | 11 | use std::io; 12 | use std::io::{Read, Write}; 13 | use std::net::TcpStream; 14 | use std::net::Shutdown; 15 | 16 | use http::HttpResult; 17 | use http::frame::{FrameIR, RawFrame, unpack_header}; 18 | use http::connection::{SendFrame, ReceiveFrame, HttpFrame}; 19 | 20 | /// A trait that any struct that wants to provide the transport layer for 21 | /// HTTP/2 needs to implement. 22 | /// 23 | /// It provides default implementations for some convenience methods, backed 24 | /// by the `Read` and `Write` implementations. 25 | pub trait TransportStream: Read + Write + Sized { 26 | /// A convenience method that performs as many `read` calls on the 27 | /// underlying `Read` implementation as it takes to fill the given buffer. 28 | /// 29 | /// The implementation simply calls the `read` in a loop until the 30 | /// buffer is filled or an aparent end of file is reached, upon which 31 | /// an error is returned. 32 | /// 33 | /// However, no particular care is taken to limit the number of loop 34 | /// iterations and it could theoretically be possible to end up reading 35 | /// a single byte at a time into a large buffer, taking a long time to 36 | /// return. 37 | /// 38 | /// Any errors raised by the underlying `Read` implementations are 39 | /// propagated. 40 | /// 41 | /// When an error is raised, the given buffer is only partially filled, 42 | /// but there is no way to know how many bytes were actually written to 43 | /// the underlying buffer, which means that, effectively, all read bytes 44 | /// are lost on any error. 45 | fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { 46 | let mut total = 0; 47 | while total < buf.len() { 48 | let read = try!(self.read(&mut buf[total..])); 49 | if read == 0 { 50 | // We consider this an unexpected end of file and return an 51 | // error since we were unable to read the minimum amount of 52 | // bytes. 53 | return Err(io::Error::new(io::ErrorKind::Other, "Not enough bytes")); 54 | } 55 | total += read; 56 | } 57 | 58 | Ok(()) 59 | } 60 | 61 | /// Attempts to split the `TransportStream` instance into a new independently 62 | /// owned handle to the same underlying stream. 63 | fn try_split(&self) -> Result; 64 | 65 | /// Attempts to shutdown both ends of the transport stream. 66 | /// 67 | /// If successful, all handles to the stream created by the `try_split` operation will start 68 | /// receiving an error for any IO operations. 69 | fn close(&mut self) -> Result<(), io::Error>; 70 | } 71 | 72 | impl TransportStream for TcpStream { 73 | fn try_split(&self) -> Result { 74 | self.try_clone() 75 | } 76 | 77 | fn close(&mut self) -> Result<(), io::Error> { 78 | self.shutdown(Shutdown::Both) 79 | } 80 | } 81 | 82 | impl SendFrame for T 83 | where T: TransportStream 84 | { 85 | fn send_frame(&mut self, frame: F) -> HttpResult<()> { 86 | let mut buf = io::Cursor::new(Vec::with_capacity(1024)); 87 | try!(frame.serialize_into(&mut buf)); 88 | try!(self.write_all(buf.get_ref())); 89 | Ok(()) 90 | } 91 | } 92 | 93 | /// The struct is a an implementation of the `ReceiveFrame` trait that wraps an existing 94 | /// `TransportStream` and uses it to provide HTTP/2 frames, when asked for one, by reading from the 95 | /// stream. 96 | /// The implementation always allocates a new buffer on the heap for every incoming frame. 97 | pub struct TransportReceiveFrame<'a, TS> 98 | where TS: TransportStream + 'a 99 | { 100 | ts: &'a mut TS, 101 | raw_frame: Option>, 102 | } 103 | 104 | impl<'a, TS> TransportReceiveFrame<'a, TS> 105 | where TS: TransportStream 106 | { 107 | /// Create a new `TransportReceiveFrame` that will use the given `TransportStream` for reading 108 | /// the frame. 109 | pub fn new(ts: &'a mut TS) -> TransportReceiveFrame<'a, TS> { 110 | TransportReceiveFrame { 111 | ts: ts, 112 | raw_frame: None, 113 | } 114 | } 115 | } 116 | 117 | impl<'a, TS> ReceiveFrame for TransportReceiveFrame<'a, TS> 118 | where TS: TransportStream 119 | { 120 | fn recv_frame(&mut self) -> HttpResult { 121 | let raw_header = { 122 | let mut buf = [0; 9]; 123 | try!(TransportStream::read_exact(self.ts, &mut buf)); 124 | buf 125 | }; 126 | let header = unpack_header(&raw_header); 127 | trace!("Received frame header {:?}", header); 128 | 129 | let total_len = 9 + header.0 as usize; 130 | // Now prepare the buffer that will hold the entire frame. 131 | let mut full_frame = Vec::with_capacity(total_len); 132 | // First copy the header into the buffer... 133 | try!(io::copy(&mut &raw_header[..], &mut full_frame)); 134 | // Now expand it to its full size... 135 | unsafe { 136 | full_frame.set_len(total_len); 137 | } 138 | // ...and have the stream read into the payload section the exact number of bytes that the 139 | // header indicated. 140 | try!(TransportStream::read_exact(self.ts, &mut full_frame[9..])); 141 | 142 | self.raw_frame = Some(RawFrame::from(full_frame)); 143 | // TODO: The reason behind being unable to decode the frame should be 144 | // extracted to allow an appropriate connection-level action to be 145 | // taken (e.g. responding with a PROTOCOL_ERROR). 146 | HttpFrame::from_raw(self.raw_frame.as_ref().unwrap()) 147 | } 148 | } 149 | 150 | #[cfg(feature="tls")] 151 | use openssl::ssl::SslStream; 152 | #[cfg(feature="tls")] 153 | impl TransportStream for SslStream { 154 | fn try_split(&self) -> Result, io::Error> { 155 | self.try_clone() 156 | } 157 | 158 | fn close(&mut self) -> Result<(), io::Error> { 159 | self.get_ref().shutdown(Shutdown::Both) 160 | } 161 | } 162 | 163 | #[cfg(test)] 164 | mod tests { 165 | use super::{TransportStream, TransportReceiveFrame}; 166 | 167 | use http::tests::common::{serialize_frame, build_stub_from_frames, StubTransportStream}; 168 | use http::HttpError; 169 | use http::connection::{HttpFrame, SendFrame, ReceiveFrame}; 170 | use http::frame::{RawFrame, DataFrame, HeadersFrame, pack_header}; 171 | 172 | /// A helper function that sends the given frame using the provided `sender` and also returns 173 | /// the raw serialization of the frame. 174 | fn send_frame(sender: &mut S, frame: HttpFrame) -> Vec { 175 | match frame { 176 | HttpFrame::DataFrame(frame) => { 177 | let ret = serialize_frame(&frame); 178 | sender.send_frame(frame).unwrap(); 179 | ret 180 | } 181 | HttpFrame::HeadersFrame(frame) => { 182 | let ret = serialize_frame(&frame); 183 | sender.send_frame(frame).unwrap(); 184 | ret 185 | } 186 | HttpFrame::RstStreamFrame(frame) => { 187 | let ret = serialize_frame(&frame); 188 | sender.send_frame(frame).unwrap(); 189 | ret 190 | } 191 | HttpFrame::SettingsFrame(frame) => { 192 | let ret = serialize_frame(&frame); 193 | sender.send_frame(frame).unwrap(); 194 | ret 195 | }, 196 | HttpFrame::PingFrame(frame) => { 197 | let ret = serialize_frame(&frame); 198 | sender.send_frame(frame).unwrap(); 199 | ret 200 | }, 201 | HttpFrame::GoawayFrame(frame) => { 202 | let ret = serialize_frame(&frame); 203 | sender.send_frame(frame).unwrap(); 204 | ret 205 | } 206 | HttpFrame::WindowUpdateFrame(frame) => { 207 | let ret = serialize_frame(&frame); 208 | sender.send_frame(frame).unwrap(); 209 | ret 210 | } 211 | HttpFrame::UnknownFrame(frame) => { 212 | let ret = serialize_frame(&frame); 213 | let raw: RawFrame = frame.into(); 214 | sender.send_frame(raw).unwrap(); 215 | ret 216 | } 217 | } 218 | } 219 | 220 | /// Tests the implementation of the `SendFrame` for `TransportStream`s when 221 | /// writing individual frames. 222 | #[test] 223 | fn test_send_frame_for_transport_stream_individual() { 224 | let frames: Vec = vec![ 225 | HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 1)), 226 | HttpFrame::DataFrame(DataFrame::new(1)), 227 | HttpFrame::DataFrame(DataFrame::new(3)), 228 | HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 3)), 229 | HttpFrame::UnknownFrame(From::from(RawFrame::from(vec![0; 9]))), 230 | ]; 231 | for frame in frames.into_iter() { 232 | let mut stream = StubTransportStream::with_stub_content(&[]); 233 | let frame_serialized = send_frame(&mut stream, frame); 234 | assert_eq!(stream.get_written(), frame_serialized); 235 | } 236 | } 237 | 238 | /// Tests the implementation of the `SendFrame` for `TransportStream`s. 239 | #[test] 240 | fn test_send_frame_for_transport_stream() { 241 | let frames: Vec = vec![ 242 | HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 1)), 243 | HttpFrame::DataFrame(DataFrame::new(1)), 244 | HttpFrame::DataFrame(DataFrame::new(3)), 245 | HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 3)), 246 | HttpFrame::UnknownFrame(From::from(RawFrame::from(vec![0; 9]))), 247 | ]; 248 | let mut stream = StubTransportStream::with_stub_content(&[]); 249 | let mut previous = 0; 250 | for frame in frames.into_iter() { 251 | let frame_serialized = send_frame(&mut stream, frame); 252 | let written = stream.get_written(); 253 | assert_eq!(&written[previous..], &frame_serialized[..]); 254 | previous = written.len(); 255 | } 256 | } 257 | 258 | /// Tests that trying to send a frame on a closed transport stream results in an error. 259 | /// (i.e. an error returned by the underlying `io::Write` is propagated). 260 | #[test] 261 | fn test_send_frame_closed_stream() { 262 | let mut stream = StubTransportStream::with_stub_content(&vec![]); 263 | stream.close().unwrap(); 264 | 265 | let res = stream.send_frame(HeadersFrame::new(vec![], 1)); 266 | 267 | assert!(res.is_err()); 268 | } 269 | 270 | /// Tests that the implementation of `ReceiveFrame` for `TransportReceiveFrame` types 271 | /// works correctly. 272 | #[test] 273 | fn test_recv_frame_for_transport_stream() { 274 | let unknown_frame = RawFrame::from({ 275 | let mut buf: Vec = Vec::new(); 276 | // Frame type 10 with a payload of length 1 on stream 1 277 | let header = (1u32, 10u8, 0u8, 1u32); 278 | buf.extend(pack_header(&header).to_vec().into_iter()); 279 | buf.push(1); 280 | buf 281 | }); 282 | let frames: Vec = vec![ 283 | HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 1)), 284 | HttpFrame::DataFrame(DataFrame::new(1)), 285 | HttpFrame::DataFrame(DataFrame::new(3)), 286 | HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 3)), 287 | HttpFrame::UnknownFrame(From::from(unknown_frame)), 288 | ]; 289 | let mut stream = StubTransportStream::with_stub_content(&build_stub_from_frames(&frames)); 290 | 291 | // Necessary to coax the borrow-checker to accept a new mutable borrow of stream in every 292 | // iteration of the loop below... 293 | fn assert_equal<'a>(orig: HttpFrame<'a>, next: HttpFrame<'a>) { 294 | assert_eq!(orig, next); 295 | } 296 | let mut receiver = TransportReceiveFrame::new(&mut stream); 297 | for frame in frames.into_iter() { 298 | assert_equal(frame, receiver.recv_frame().unwrap()); 299 | } 300 | // Attempting to read after EOF yields an error 301 | assert!(receiver.recv_frame().is_err()); 302 | } 303 | 304 | /// Tests that the implementation of `ReceiveFrame` for `TransportReceiveFrame` types 305 | /// works correctly when faced with an incomplete frame. 306 | #[test] 307 | fn test_recv_frame_for_transport_stream_incomplete_frame() { 308 | let frame = DataFrame::with_data(1, vec![1, 2, 3]); 309 | let serialized: Vec = serialize_frame(&frame); 310 | 311 | { 312 | // Incomplete header 313 | let mut stream = StubTransportStream::with_stub_content(&serialized[..5]); 314 | let mut receiver = TransportReceiveFrame::new(&mut stream); 315 | 316 | assert!(receiver.recv_frame().is_err()); 317 | } 318 | { 319 | // Incomplete data 320 | let mut stream = StubTransportStream::with_stub_content(&serialized[..10]); 321 | let mut receiver = TransportReceiveFrame::new(&mut stream); 322 | 323 | assert!(receiver.recv_frame().is_err()); 324 | } 325 | } 326 | 327 | /// Tests that when an invalid, yet syntactically correct, frame is read from the stream, 328 | /// a corresponding error is returned. 329 | #[test] 330 | fn test_recv_frame_invalid() { 331 | // A DATA header which is attached to stream 0 332 | let serialized = serialize_frame(&HeadersFrame::new(vec![], 0)); 333 | let mut stream = StubTransportStream::with_stub_content(&serialized); 334 | let mut receiver = TransportReceiveFrame::new(&mut stream); 335 | 336 | assert_eq!(receiver.recv_frame().err().unwrap(), 337 | HttpError::InvalidFrame); 338 | } 339 | 340 | } 341 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc(html_root_url="https://mlalic.github.io/solicit/")] 2 | 3 | #[macro_use] 4 | extern crate log; 5 | extern crate hpack; 6 | #[cfg(feature="tls")] 7 | extern crate openssl; 8 | 9 | pub mod http; 10 | pub mod client; 11 | pub mod server; 12 | 13 | mod tests {} 14 | -------------------------------------------------------------------------------- /src/server/mod.rs: -------------------------------------------------------------------------------- 1 | //! The module contains a simple HTTP/2 server implementation. 2 | 3 | use http::{Response, StaticResponse, HttpResult, HttpError, HttpScheme, StreamId, Header}; 4 | use http::transport::{TransportStream, TransportReceiveFrame}; 5 | use http::connection::{HttpConnection, EndStream, SendStatus}; 6 | use http::session::{DefaultSessionState, SessionState, Stream, DefaultStream}; 7 | use http::session::Server as ServerMarker; 8 | use http::server::{ServerConnection, StreamFactory}; 9 | 10 | /// The struct represents a fully received request. 11 | pub struct ServerRequest<'a, 'n, 'v> 12 | where 'n: 'a, 13 | 'v: 'a 14 | { 15 | pub stream_id: StreamId, 16 | pub headers: &'a [Header<'n, 'v>], 17 | pub body: &'a [u8], 18 | } 19 | 20 | /// A simple implementation of the `http::server::StreamFactory` trait that creates new 21 | /// `DefaultStream` instances. 22 | struct SimpleFactory; 23 | impl StreamFactory for SimpleFactory { 24 | type Stream = DefaultStream; 25 | fn create(&mut self, id: StreamId) -> DefaultStream { 26 | DefaultStream::with_id(id) 27 | } 28 | } 29 | 30 | /// The struct implements a simple HTTP/2 server that allows users to register a request handler (a 31 | /// callback taking a `ServerRequest` and returning a `Response`) which is run on all received 32 | /// requests. 33 | /// 34 | /// The `handle_next` method needs to be called regularly in order to have the server process 35 | /// received frames, as well as send out the responses. 36 | /// 37 | /// This is an exceedingly simple implementation of an HTTP/2 server and is mostly an example of 38 | /// how the `solicit::http` API can be used to make one. 39 | /// 40 | /// # Examples 41 | /// 42 | /// ```no_run 43 | /// extern crate solicit; 44 | /// use std::str; 45 | /// use std::net::{TcpListener, TcpStream}; 46 | /// use std::thread; 47 | /// 48 | /// use solicit::server::SimpleServer; 49 | /// 50 | /// use solicit::http::{Response, Header}; 51 | /// 52 | /// fn main() { 53 | /// fn handle_client(stream: TcpStream) { 54 | /// let mut server = SimpleServer::new(stream, |req| { 55 | /// println!("Received request:"); 56 | /// for header in req.headers.iter() { 57 | /// println!(" {}: {}", 58 | /// str::from_utf8(header.name()).unwrap(), 59 | /// str::from_utf8(header.value()).unwrap()); 60 | /// } 61 | /// println!("Body:\n{}", str::from_utf8(&req.body).unwrap()); 62 | /// 63 | /// // Return a dummy response for every request 64 | /// Response { 65 | /// headers: vec![ 66 | /// Header::new(b":status", b"200"), 67 | /// Header::new(b"x-solicit".to_vec(), b"Hello, World!".to_vec()), 68 | /// ], 69 | /// body: vec![65], 70 | /// stream_id: req.stream_id, 71 | /// } 72 | /// }).unwrap(); 73 | /// while let Ok(_) = server.handle_next() {} 74 | /// println!("Server done (client disconnected)"); 75 | /// } 76 | /// 77 | /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); 78 | /// for stream in listener.incoming() { 79 | /// let stream = stream.unwrap(); 80 | /// thread::spawn(move || { 81 | /// handle_client(stream) 82 | /// }); 83 | /// } 84 | /// } 85 | /// ``` 86 | pub struct SimpleServer 87 | where TS: TransportStream, 88 | H: FnMut(ServerRequest) -> Response<'static, 'static> 89 | { 90 | conn: ServerConnection, 91 | receiver: TS, 92 | sender: TS, 93 | handler: H, 94 | } 95 | 96 | impl SimpleServer 97 | where TS: TransportStream, 98 | H: FnMut(ServerRequest) -> Response<'static, 'static> 99 | { 100 | /// Creates a new `SimpleServer` that will use the given `TransportStream` to communicate to 101 | /// the client. Assumes that the stream is fully uninitialized -- no preface sent or read yet. 102 | pub fn new(mut stream: TS, handler: H) -> HttpResult> { 103 | // First assert that the preface is received 104 | let mut preface = [0; 24]; 105 | TransportStream::read_exact(&mut stream, &mut preface).unwrap(); 106 | if &preface != b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" { 107 | return Err(HttpError::UnableToConnect); 108 | } 109 | 110 | let conn = HttpConnection::new(HttpScheme::Http); 111 | let state = DefaultSessionState::::new(); 112 | let conn = ServerConnection::with_connection(conn, state, SimpleFactory); 113 | let mut server = SimpleServer { 114 | conn: conn, 115 | receiver: try!(stream.try_split()), 116 | sender: stream, 117 | handler: handler, 118 | }; 119 | 120 | // Initialize the connection -- send own settings and process the peer's 121 | try!(server.conn.send_settings(&mut server.sender)); 122 | try!(server.conn.expect_settings(&mut TransportReceiveFrame::new(&mut server.receiver), 123 | &mut server.sender)); 124 | 125 | // Set up done 126 | Ok(server) 127 | } 128 | 129 | /// Handles the next incoming frame, blocking to receive it if nothing is available on the 130 | /// underlying stream. 131 | /// 132 | /// Handling the frame can trigger the handler callback. Any responses returned by the handler 133 | /// are immediately flushed out to the client (blocking the call until it's done). 134 | pub fn handle_next(&mut self) -> HttpResult<()> { 135 | try!(self.conn.handle_next_frame(&mut TransportReceiveFrame::new(&mut self.receiver), 136 | &mut self.sender)); 137 | let responses = try!(self.handle_requests()); 138 | try!(self.prepare_responses(responses)); 139 | try!(self.flush_streams()); 140 | try!(self.reap_streams()); 141 | 142 | Ok(()) 143 | } 144 | 145 | /// Invokes the request handler for each fully received request. Collects all the responses 146 | /// into the returned `Vec`. 147 | fn handle_requests(&mut self) -> HttpResult> { 148 | let handler = &mut self.handler; 149 | let closed = self.conn 150 | .state 151 | .iter() 152 | .filter(|&(_, ref s)| s.is_closed_remote()); 153 | let responses = closed.map(|(&stream_id, stream)| { 154 | let req = ServerRequest { 155 | stream_id: stream_id, 156 | headers: stream.headers.as_ref().unwrap(), 157 | body: &stream.body, 158 | }; 159 | handler(req) 160 | }); 161 | 162 | Ok(responses.collect()) 163 | } 164 | 165 | /// Prepares the streams for each of the given responses. Headers for each response are 166 | /// immediately sent and the data staged into the streams' outgoing buffer. 167 | fn prepare_responses(&mut self, responses: Vec) -> HttpResult<()> { 168 | for response in responses.into_iter() { 169 | try!(self.conn.start_response(response.headers, 170 | response.stream_id, 171 | EndStream::No, 172 | &mut self.sender)); 173 | let mut stream = self.conn.state.get_stream_mut(response.stream_id).unwrap(); 174 | stream.set_full_data(response.body); 175 | } 176 | 177 | Ok(()) 178 | } 179 | 180 | /// Flushes the outgoing buffers of all streams. 181 | #[inline] 182 | fn flush_streams(&mut self) -> HttpResult<()> { 183 | while let SendStatus::Sent = try!(self.conn.send_next_data(&mut self.sender)) {} 184 | 185 | Ok(()) 186 | } 187 | 188 | /// Removes closed streams from the connection state. 189 | #[inline] 190 | fn reap_streams(&mut self) -> HttpResult<()> { 191 | // Moves the streams out of the state and then drops them 192 | let _ = self.conn.state.get_closed(); 193 | Ok(()) 194 | } 195 | } 196 | --------------------------------------------------------------------------------