LoginSignup
27
24

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-01-14

概要

RustでHTTP2クライアントを使いたい。
ざっくり調べた感じ solicithyperが使えそうなのでそれを試してみました。

前提

項目 説明
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"]
27
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
24