IronでHTTPサーバーを立てる

# RustとHTTP

[Module std::net](https://doc.rust-lang.org/std/net/) というのがありますが、これはプリミティブなTCP/UDP通信を提供するものなので、これをそのまま使ってHTTPを扱うのは少し大変です。
[Are we web yet? Getting there](http://arewewebyet.com/) を読んで、今回はIronというフレームワークを使ってみました。

バージョンは以下のとおりです。

- rust: 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
- iron: 0.1.17

# Iron

[Iron](https://github.com/iron/iron) はミドルウェア指向で拡張性の高いHTTPサーバーのフレームワークです。Iron自体のソースコードは小さく、これに必要なミドルウェアやプラグインを足すスタイルになっています。

<img src="https://qiita-image-store.s3.amazonaws.com/0/179/8621f397-687f-215e-6dbd-efd9b25e93de.png" width="240px">

コアとなるモジュールはあらかじめバンドルされています。

Middleware:

- [Routing](https://github.com/iron/router)
- [Mounting](https://github.com/iron/mount)
- [Static File Serving](https://github.com/iron/static)
- [Logging](https://github.com/iron/logger)

Plugins:

- [JSON Body Parsing](https://github.com/iron/body-parser)
- [URL Encoded Data Parsing](https://github.com/iron/urlencoded)
- [Cookies](https://github.com/iron/cookie)
- [Sessions](https://github.com/iron/session)

Both:

- [Shared Memory (also used for Plugin configuration)](https://github.com/iron/persistent)

Railsを置き換えるようなものではなく、単機能の一部のサーバーに使うことを想定しているので、小さい部品を組み合わせて書ける方が都合が良いと思いました。

## Handler

基本的には以下のようにHandlerを渡してサーバーを起動します。

```rust
Iron::new(handler).http("localhost:3000").unwrap();
```

Handlerは受け取ったリクエストからレスポンスを作ります。Handlerは以下のようなトレイトになっています。

```rust
pub trait Handler: Send + Sync + Any {
    /// Produce a `Response` from a Request, with the possibility of error.
    fn handle(&self, &mut Request) -> IronResult<Response>;
}
```

`Request` を受け取って `IronResult<Response>` を返すものがHandlerということになります。なのでこのようにクロージャを渡しても良いですし、

```rust
fn main() {
    Iron::new(|_: &mut Request| {
        Ok(Response::with((status::Ok, "Hello world!")))
    }).http("localhost:3000").unwrap();
}
```

もちろんメソッドを渡すことも可能です。

```rust
fn main() {
    fn handler(req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Ok, "Hello world!")))
    }

    Iron::new(handler).http("localhost:3000").unwrap();
}
```

`Ok(...)` という値を返していますが、これはIronResultが [Module std::result](https://doc.rust-lang.org/std/result/) の型シノニムとして定義されているためです。

```rust
enum Result<T, E> {
   Ok(T),
   Err(E)
}

pub type IronResult<T> = Result<T, IronError>;
```

このサンプルでは `Ok(T)` を返しているということです。

### Router

パスで分岐した処理を書きやすくするために [Router](https://github.com/iron/router) というモジュールがあります。

```rust
let mut router = Router::new();
router.get("/", |_: &mut Request| {
    ...
});
```

RouterもHandlerなので、Handlerトレイトを実装しています。そのためRouterもIronのコンストラクタに渡すことができます。

```rust
Iron::new(router).http("localhost:3000").unwrap();
```

## MiddlewareとChain

IronではMiddlewareをChainに登録してスタックの玉ねぎを作ります。

<img src="https://qiita-image-store.s3.amazonaws.com/0/179/7934587e-6a72-2aed-6391-6b85f4a1b521.png" width="320px">

ChainもHandlerトレイトを実装しています。

```rust
let mut chain = Chain::new(router);

chain.link_before(MyBeforeMiddleware);
chain.link_after(MyAfterMmiddleware);

Iron::new(chain).http("localhost:3000").unwrap();
```

定義はこのようになります。

```rust
struct MyBeforeMiddleware;

impl BeforeMiddleware for MyBeforeMiddleware {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        ...
        Ok(())
    }
}

struct MyAfterMiddleware;

impl AfterMiddleware for MyAfterMiddleware {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        ...
        Ok(res)
    }
}
```

### req.extensions

Middlewareでリクエストに値を追加するには `req.extensions` を使います。extensionsは [TypeMap](https://github.com/reem/rust-typemap/) です。TypeMapはAnyMapのようですが、キーと対応するバリューの型を強制することができるモジュールです。
これを使ってBeforeMiddlewareからAfterMiddlewareに値を渡すこともできます。

```rust
struct MyBeforeMiddleware;

impl Key for BeforeMiddleware { type Value = String; }

impl BeforeMiddleware for MyBeforeMiddleware {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        let message = "This message from MyBeforeMiddleware".to_string();
        req.extensions.insert::<MyBeforeMiddleware>(message);
        Ok(())
    }
}

struct MyAfterMiddleware;

impl AfterMiddleware for MyAfterMiddleware {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        let message = req.extensions.get::<MyBeforeMiddleware>().unwrap();
        println!("{:?}", message); // => This message from MyBeforeMiddleware
        Ok(res)
    }
}
```

### レスポンスタイムを測る

ArroundMiddlewareを使うとHandlerの前後に処理をすることができます。ここではHandlerの前後で時間を計測してLoggerで出力しています。

```rust
struct LoggerHandler<H: Handler> { logger: Logger, handler: H }

impl<H: Handler> Handler for LoggerHandler<H> {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let entry = ::time::precise_time_ns();
        let res = self.handler.handle(req);
        let time = ::time::precise_time_ns() - entry;
        self.logger.log(req, res.as_ref(), time);
        res
    }
}

struct Logger;

impl Logger {
    fn log(&self, req: &Request, res: Result<&Response, &IronError>, time: u64) {
        println!("Request: {:?}\nResponse: {:?}\nResponse-Time: {:?}", req, res, time)
    }
}

impl AroundMiddleware for Logger {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(LoggerHandler {
            logger: self,
            handler: handler
        }) as Box<Handler>
    }
}

fn main() {
    let mut chain = Chain::new(router);
    chain.around(Logger);

    Iron::new(chain).http("localhost:3000").unwrap();
}
```

リクエストを送ると以下のようなログが出力されます。

```
Request: Request {
    url: Url { scheme: "http", host: Domain("localhost"), port: 3000, path: [""], username: None, password: None, query: None, fragment: None }
    method: Get
    remote_addr: V6([::1]:52567)
    local_addr: V6([::1]:3000)
}
Response: Ok(HTTP/1.1 200 OK OK
Content-Length: 12

)
Response-Time: 7247
```

ちなみに `cargo run` にreleaseフラグを付けて実行したら10倍以上速くなりました。

# その他

今回はIronを触ってみましたが [Nickel](http://nickel.rs/) というフレームワークも気になっています。後発だけあってインタフェースが洗練されていて使いやすそうなので、別の機会に試してみたいと思います。
Rustを実際にプロダクションで使うかと言われると、Rust自体が先日バージョン1になったくらいなので、世の中のライブラリは当然バージョン0.xという状態なので、すぐには使わないと思います。
しかし高い抽象度でありながら安全でC++に匹敵する速度が出るらしいRustには期待しています。