概要
RustでHTTP2クライアントを使いたい。
ざっくり調べた感じ solicit と hyperが使えそうなのでそれを試してみました。
前提
項目 | 説明 |
---|---|
OS | MacOSX 10.11.2 |
Rust | 1.5.0 stable |
検証日時 | 2016.01.15 |
solicit
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を使っているようでした。
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でアクセスしたい
上記の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://
でもアクセスできるような対応をいれたサンプルは以下です。
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とかだといけるのかもしれません。試してません。)
[dependencies.solicit]
version = "*"
features = ["tls"]