RustでHTTP2クライアントを試す

## 概要
RustでHTTP2クライアントを使いたい。
ざっくり調べた感じ [solicit](https://github.com/mlalic/solicit) と [hyper](https://github.com/hyperium/hyper)が使えそうなのでそれを試してみました。

## 前提
| 項目 | 説明 |
|----|-------------------------|
| OS | MacOSX 10.11.2 |
| Rust | 1.5.0 stable |
| 検証日時 | 2016.01.15              |

## solicit
```rust:http2-solicit.rs
extern crate solicit;
use solicit::http::client::CleartextConnector;
use solicit::client::SimpleClient;
use std::str;

static HOST: &'static str = "http2bin.org";

fn main() {
    let connector = CleartextConnector::new(HOST);
    let mut client = SimpleClient::with_connector(connector).unwrap();
    let resp = client.get(b"/get", &[]).unwrap();

    println!("{}", str::from_utf8(&resp.body).unwrap());
}
```
かなり小さいですが、HTTP2使ってアクセスできます。

```
{
  "args": {},
  "headers": {
    "Connection": "keep-alive",
    "Host": "http2bin.org",
    "Via": "2 http2bin.org"
  },
  "origin": "180.44.100.161",
  "url": "http://http2bin.org/get"
}
```

## hyper
RustでHTTPを扱えるcrateと言えばhyperですが、hyperもHTTP2を扱うことができます。
[中身はsolicitを使っているようでした。](https://github.com/hyperium/hyper/blob/4c7f6f0c1ec863859dd04d56610d45dae4e2ae04/src/http/h2.rs#L24)

```rust:http2-hyper.rs
extern crate hyper;
use std::io;
use hyper::Client;
use hyper::http::h2;

static URL: &'static str = "http://http2bin.org/get";

// http -> OK
// https -> Error:
//          thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value:
//          Io(Error { repr: Custom(Custom { kind: InvalidInput, error: StringError("Invalid scheme for
//          Http") }) })', ../src/libcore/result.rs:738
fn http2_with_error() {
    let client = Client::with_protocol(h2::new_protocol());
    let mut res = client.get(URL).send().unwrap();

    println!("Response: {}", res.status);
    println!("Headers:\n{}", res.headers);
    io::copy(&mut res, &mut io::stdout()).unwrap();
}

fn main() {
    http2_with_error();
}
```

```
Response: 200 OK
Headers:
content-type: application/json
access-control-allow-origin: *
server: h2o/1.6.1
content-length: 222
:status: 200
date: Thu, 14 Jan 2016 21:36:05 GMT
x-clacks-overhead: GNU Terry Pratchett
access-control-allow-credentials: true

{
  "args": {},
  "headers": {
    "Connection": "keep-alive",
    "Host": "http2bin.org,http2bin.org",
    "Via": "2 http2bin.org"
  },
  "origin": "180.44.100.161",
  "url": "http://http2bin.org,http2bin.org/get"
}
```
アクセスはできてそうですが、Hostとurlの値に少し違和感あります。どうも`:authority:`擬似ヘッダと`Host`ヘッダを両方持っているようで、http2bin.orgで上記のように表示されるようです。

[リクエスト時にHostヘッダを含めないパッチ](https://github.com/hhatto/hyper/commit/021c309fafcf8106d06e1c2d206034220d33a8af)を作ってみましたが、かなり強引な対応なので今はそっと置いておこうかと思います。

### httpsでアクセスしたい
上記のhyperの例で`https://`でアクセスしようとすると実行時に以下のようなエラーになります。

```
thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: Io(Error { repr: Custom(Custom { kind: InvalidInput, error: StringError("Invalid scheme for Http") }) })', ../src/libcore/result.rs:738
```

`https://`でもアクセスできるような対応をいれたサンプルは以下です。

```rust
extern crate hyper;
use std::io::Read;
use hyper::Client;
use hyper::http::h2::Http2Protocol;
use hyper::net::{HttpsConnector, Openssl};

static URL: &'static str = "https://http2bin.org/get";
static CERT_FILE: &'static str = "tmp.crt";
static KEY_FILE: &'static str = "tmp.key";

fn http2() {
    let ssl = Openssl::with_cert_and_key(CERT_FILE, KEY_FILE).unwrap();
    let ssl_connector = HttpsConnector::new(ssl);
    let http2_client = Client::with_protocol(Http2Protocol::with_connector(ssl_connector));
    let mut res = http2_client.get(URL).send().unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    println!("{}", body);
}

fn main() {
    http2();
}
```

### solicitでhttpsアクセス
featuresに`tls`を含めろってことなので、それでビルドしてみてもビルドこけて使う事できませんでした。（nightlyとかだといけるのかもしれません。試してません。）

```toml
[dependencies.solicit]
version = "*"
features = ["tls"]
```