Giter Club home page Giter Club logo

iron's Introduction

Iron

Build Status Crates.io Status License

Extensible, Concurrency Focused Web Development in Rust.

Response Timer Example

Note: This example works with the current iron code in this repository (master branch). If you are using iron 0.6 from crates.io, please refer to the corresponding example in the branch 0.6-maintenance.

extern crate iron;
extern crate time;

use iron::prelude::*;
use iron::{typemap, AfterMiddleware, BeforeMiddleware};
use time::precise_time_ns;

struct ResponseTime;

impl typemap::Key for ResponseTime { type Value = u64; }

impl BeforeMiddleware for ResponseTime {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<ResponseTime>(precise_time_ns());
        Ok(())
    }
}

impl AfterMiddleware for ResponseTime {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        let delta = precise_time_ns() - *req.extensions.get::<ResponseTime>().unwrap();
        println!("Request took: {} ms", (delta as f64) / 1000000.0);
        Ok(res)
    }
}

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((iron::StatusCode::OK, "Hello World")))
}

fn main() {
    let mut chain = Chain::new(hello_world);
    chain.link_before(ResponseTime);
    chain.link_after(ResponseTime);
    Iron::new(chain).http("localhost:3000");
}

Overview

Iron is a high level web framework built in and for Rust, built on hyper. Iron is designed to take advantage of Rust's greatest features - its excellent type system and its principled approach to ownership in both single threaded and multi threaded contexts.

Iron is highly concurrent and can scale horizontally on more machines behind a load balancer or by running more threads on a more powerful machine. Iron avoids the bottlenecks encountered in highly concurrent code by avoiding shared writes and locking in the core framework.

Iron is 100% safe code:

$ rg unsafe src | wc
       0       0       0

Philosophy

Iron is meant to be as extensible and pluggable as possible; Iron's core is concentrated and avoids unnecessary features by leaving them to middleware, plugins, and modifiers.

Middleware, Plugins, and Modifiers are the main ways to extend Iron with new functionality. Most extensions that would be provided by middleware in other web frameworks are instead addressed by the much simpler Modifier and Plugin systems.

Modifiers allow external code to manipulate Requests and Response in an ergonomic fashion, allowing third-party extensions to get the same treatment as modifiers defined in Iron itself. Plugins allow for lazily-evaluated, automatically cached extensions to Requests and Responses, perfect for parsing, accessing, and otherwise lazily manipulating an http connection.

Middleware are only used when it is necessary to modify the control flow of a Request flow, hijack the entire handling of a Request, check an incoming Request, or to do final post-processing. This covers areas such as routing, mounting, static asset serving, final template rendering, authentication, and logging.

Iron comes with only basic modifiers for setting the status, body, and various headers, and the infrastructure for creating modifiers, plugins, and middleware. No plugins or middleware are bundled with Iron.

Performance

Iron averages 72,000+ requests per second for hello world and is mostly IO-bound, spending over 70% of its time in the kernel send-ing or recv-ing data.*

* Numbers from profiling on my OS X machine, your mileage may vary.

Core Extensions

Iron aims to fill a void in the Rust web stack - a high level framework that is extensible and makes organizing complex server code easy.

Extensions are painless to build. Some important ones are:

Middleware:

Plugins:

Both:

This allows for extremely flexible and powerful setups and allows nearly all of Iron's features to be swappable - you can even change the middleware resolution algorithm by swapping in your own Chain.

* Due to the rapidly evolving state of the Rust ecosystem, not everything builds all the time. Please be patient and file issues for breaking builds, we're doing our best.

Underlying HTTP Implementation

Iron is based on and uses hyper as its HTTP implementation, and lifts several types from it, including its header representation, status, and other core HTTP types. It is usually unnecessary to use hyper directly when using Iron, since Iron provides a facade over hyper's core facilities, but it is sometimes necessary to depend on it as well.

Installation

If you're using Cargo, just add Iron to your Cargo.toml:

[dependencies.iron]
version = "*"

The documentation is hosted online and auto-updated with each successful release. You can also use cargo doc to build a local copy.

Check out the examples directory!

You can run an individual example using cargo run --bin example-name inside the examples directory. Note that for benchmarking you should make sure to use the --release flag, which will cause cargo to compile the entire toolchain with optimizations. Without --release you will get truly sad numbers.

Getting Help

Feel free to ask questions as github issues in this or other related repos.

The best place to get immediate help is on IRC, on any of these channels on the mozilla network:

  • #rust-webdev
  • #iron
  • #rust

One of the maintainers or contributors is usually around and can probably help. We encourage you to stop by and say hi and tell us what you're using Iron for, even if you don't have any questions. It's invaluable to hear feedback from users and always nice to hear if someone is using the framework we've worked on.

Maintainers

Jonathan Reem (reem) is the core maintainer and author of Iron.

Commit Distribution (as of 8e55759):

Jonathan Reem (415)
Zach Pomerantz (123)
Michael Sproul (9)
Patrick Tran (5)
Corey Richardson (4)
Bryce Fisher-Fleig (3)
Barosl Lee (2)
Christoph Burgdorf (2)
da4c30ff (2)
arathunku (1)
Cengiz Can (1)
Darayus (1)
Eduardo Bautista (1)
Mehdi Avdi (1)
Michael Sierks (1)
Nerijus Arlauskas (1)
SuprDewd (1)

License

MIT

iron's People

Contributors

aerialx avatar brycefisher avatar carols10cents avatar dorfsmay avatar duelinmarkers avatar eduardobautista avatar emberian avatar fiedzia avatar fuchsnj avatar gsquire avatar iori-yja avatar lambda-fairy avatar leoyvens avatar mcreinhard avatar michaelsproul avatar mjdsys avatar panicbit avatar phlmn avatar reem avatar robinst avatar sfackler avatar skylerlipthay avatar steveklabnik avatar theptrk avatar tim-semba avatar tomprince avatar trotter avatar untitaker avatar zgtm avatar zzmp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

iron's Issues

Hello world benchmark

Hello, made a simple benchmark with hello.rs example and 'wrk' as benchamrking tool:

$ wrk -c 10 -t 10 http://0.0.0.0:3000
Running 10s test @ http://0.0.0.0:3000
  10 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   267.33us  287.79us   9.02ms   98.94%
    Req/Sec     4.27k     1.41k    7.55k    52.58%
  401271 requests in 9.99s, 29.47MB read
Requests/sec:  40150.24
Transfer/sec:      2.95MB

And the iron log:

$ ./target/hello_iron
On 3000

10000 requests made thus far. Current means:
- Total:               100%,  336186.8456
- Spawn:               41.539946%,  139651.8329
- Load request:        0.335941%,    1129.3904
- Initialise response: 0.102383%,     344.1996
- Handle:              58.02173%,  195061.4227

20000 requests made thus far. Current means:
- Total:               100%,  268444.1866
- Spawn:               26.011335%,  69825.91645
- Load request:        0.210359%,     564.6952
- Initialise response: 0.122886%,     329.8801
- Handle:              73.655421%, 197723.69485

30000 requests made thus far. Current means:
- Total:               100%, 245398.889967
- Spawn:               18.969365%, 46550.610967
- Load request:        0.153409%,   376.463467
- Initialise response: 0.132745%,     325.7537
- Handle:              80.744482%, 198146.061833

40000 requests made thus far. Current means:
- Total:               100%, 234276.087925
- Spawn:               14.902485%, 34912.958225
- Load request:        0.120519%,     282.3476
- Initialise response: 0.140365%,    328.84125
- Handle:              84.836631%, 198751.94085

50000 requests made thus far. Current means:
- Total:               100%,  224318.8409
- Spawn:               12.451191%,  27930.36658
- Load request:        0.100695%,    225.87808
- Initialise response: 0.146902%,    329.52836
- Handle:              87.301212%, 195833.06788

60000 requests made thus far. Current means:
- Total:               100%, 217639.218067
- Spawn:               10.694445%, 23275.305483
- Load request:        0.086488%,   188.231733
- Initialise response: 0.152383%,   331.646233
- Handle:              89.066684%, 193844.034617

70000 requests made thus far. Current means:
- Total:               100%, 212900.984157
- Spawn:               9.370676%, 19950.261843
- Load request:        0.075782%,   161.341486
- Initialise response: 0.156028%,   332.185643
- Handle:              90.397513%, 192457.195186

80000 requests made thus far. Current means:
- Total:               100%, 209371.914825
- Spawn:               8.337546%, 17456.479113
- Load request:        0.067427%,     141.1738
- Initialise response: 0.159411%,   333.761363
- Handle:              91.435616%, 191440.50055

90000 requests made thus far. Current means:
- Total:               100%, 206606.409522
- Spawn:               7.510353%, 15516.870322
- Load request:        0.060738%,   125.487822
- Initialise response: 0.162002%,   334.706856
- Handle:              92.266907%, 190629.344522

100000 requests made thus far. Current means:
- Total:               100%, 204531.75973
- Spawn:               6.82788%,  13965.18329
- Load request:        0.055218%,    112.93904
- Initialise response: 0.163844%,    335.11283
- Handle:              92.953058%, 190118.52457

110000 requests made thus far. Current means:
- Total:               100%, 203432.843436
- Spawn:               6.240694%, 12695.621173
- Load request:        0.05047%,   102.671855
- Initialise response: 0.164814%,     335.2865
- Handle:              93.544022%, 190299.263909

120000 requests made thus far. Current means:
- Total:               100%, 201892.850625
- Spawn:               5.764272%, 11637.652742
- Load request:        0.046617%,    94.115867
- Initialise response: 0.165954%,   335.048258
- Handle:              94.023158%, 189826.033758

130000 requests made thus far. Current means:
- Total:               100%, 200585.132562
- Spawn:               5.355556%, 10742.448685
- Load request:        0.043311%,    86.876185
- Initialise response: 0.166993%,   334.963262
- Handle:              94.43414%, 189420.844431

140000 requests made thus far. Current means:
- Total:               100%, 199740.195521
- Spawn:               4.994053%,  9975.130921
- Load request:        0.040388%,    80.670743
- Initialise response: 0.167754%,   335.072671
- Handle:              94.797805%, 189349.321186

150000 requests made thus far. Current means:
- Total:               100%, 199007.517087
- Spawn:               4.678277%,  9310.122193
- Load request:        0.037834%,    75.292693
- Initialise response: 0.168222%,   334.775007
- Handle:              95.115667%, 189287.327193

160000 requests made thus far. Current means:
- Total:               100%, 198151.007287
- Spawn:               4.404842%,  8728.239556
- Load request:        0.035623%,      70.5869
- Initialise response: 0.169046%,   334.966412
- Handle:              95.390489%, 189017.214419

170000 requests made thus far. Current means:
- Total:               100%, 197321.828071
- Spawn:               4.163155%,    8214.8137
- Load request:        0.033668%,    66.434729
- Initialise response: 0.169533%,     334.5248
- Handle:              95.633644%, 188706.054841

180000 requests made thus far. Current means:
- Total:               100%, 196628.889172
- Spawn:               3.945725%,  7758.435161
- Load request:        0.03191%,    62.743911
- Initialise response: 0.170121%,   334.507411
- Handle:              95.852244%, 188473.202689

190000 requests made thus far. Current means:
- Total:               100%, 196009.044137
- Spawn:               3.749876%,  7350.096468
- Load request:        0.030326%,      59.4416
- Initialise response: 0.170616%,   334.422021
- Handle:              96.049182%, 188265.084047

200000 requests made thus far. Current means:
- Total:               100%, 195427.21219
- Spawn:               3.572988%,  6982.591645
- Load request:        0.028895%,     56.46952
- Initialise response: 0.171175%,    334.52168
- Handle:              96.226942%, 188053.629345

210000 requests made thus far. Current means:
- Total:               100%, 194907.422548
- Spawn:               3.411921%,  6650.087281
- Load request:        0.027593%,    53.780495
- Initialise response: 0.171606%,   334.472795
- Handle:              96.38888%, 187869.081976

220000 requests made thus far. Current means:
- Total:               100%, 194426.380586
- Spawn:               3.264892%,  6347.810586
- Load request:        0.026404%,    51.335927
- Initialise response: 0.171917%,   334.252036
- Handle:              96.536788%, 187692.982036

230000 requests made thus far. Current means:
- Total:               100%, 194025.704813
- Spawn:               3.129389%,  6071.818822
- Load request:        0.025308%,     49.10393
- Initialise response: 0.172374%,   334.450665
- Handle:              96.672929%, 187570.331396

240000 requests made thus far. Current means:
- Total:               100%, 193653.568929
- Spawn:               3.004761%,  5818.826371
- Load request:        0.0243%,    47.057933
- Initialise response: 0.173016%,   335.052388
- Handle:              96.797923%, 187452.632237

250000 requests made thus far. Current means:
- Total:               100%, 193300.255928
- Spawn:               2.889843%,  5586.073316
- Load request:        0.023371%,    45.175616
- Initialise response: 0.173308%,   335.005672
- Handle:              96.913478%, 187334.001324

260000 requests made thus far. Current means:
- Total:               100%, 192976.868435
- Spawn:               2.783351%,  5371.224342
- Load request:        0.022509%,    43.438092
- Initialise response: 0.173516%,   334.846346
- Handle:              97.020623%, 187227.359654

270000 requests made thus far. Current means:
- Total:               100%, 192674.385126
- Spawn:               2.684472%,  5172.290107
- Load request:        0.02171%,    41.829274
- Initialise response: 0.173799%,   334.865656
- Handle:              97.120019%, 187125.400089

280000 requests made thus far. Current means:
- Total:               100%, 192378.687518
- Spawn:               2.592577%,  4987.565461
- Load request:        0.020967%,    40.335371
- Initialise response: 0.174069%,   334.872104
- Handle:              97.212387%, 187015.914582

290000 requests made thus far. Current means:
- Total:               100%, 192102.119717
- Spawn:               2.506782%,  4815.580445
- Load request:        0.020273%,    38.944497
- Initialise response: 0.17421%,   334.660186
- Handle:              97.298736%, 186912.93459

300000 requests made thus far. Current means:
- Total:               100%, 191868.651723
- Spawn:               2.426171%,  4655.061097
- Load request:        0.019621%,    37.646347
- Initialise response: 0.174389%,    334.59762
- Handle:              97.379819%, 186841.34666

310000 requests made thus far. Current means:
- Total:               100%, 191644.612545
- Spawn:               2.350652%,  4504.897835
- Load request:        0.01901%,    36.431948
- Initialise response: 0.174524%,   334.466323
- Handle:              97.455814%, 186768.816439

320000 requests made thus far. Current means:
- Total:               100%, 191424.453662
- Spawn:               2.279813%,  4364.119778
- Load request:        0.018437%,     35.29345
- Initialise response: 0.174667%,   334.355016
- Handle:              97.527083%, 186690.685419

330000 requests made thus far. Current means:
- Total:               100%, 191219.716845
- Spawn:               2.213095%,  4231.873724
- Load request:        0.017898%,    34.223952
- Initialise response: 0.174852%,   334.351048
- Handle:              97.594156%, 186619.268121

340000 requests made thus far. Current means:
- Total:               100%, 191036.950468
- Spawn:               2.150059%,   4107.40685
- Load request:        0.017388%,    33.217365
- Initialise response: 0.17504%,   334.391394
- Handle:              97.657513%, 186561.934859

350000 requests made thus far. Current means:
- Total:               100%, 190861.30556
- Spawn:               2.090551%,  3990.052369
- Load request:        0.016907%,    32.268297
- Initialise response: 0.175154%,   334.301754
- Handle:              97.717388%, 186504.68314

360000 requests made thus far. Current means:
- Total:               100%, 190682.823439
- Spawn:               2.034382%,  3879.217581
- Load request:        0.016452%,    31.371956
- Initialise response: 0.175375%,   334.410814
- Handle:              97.77379%, 186437.823089

370000 requests made thus far. Current means:
- Total:               100%, 190520.371914
- Spawn:               1.981087%,  3774.373862
- Load request:        0.016021%,    30.524065
- Initialise response: 0.175542%,   334.444057
- Handle:              97.827349%, 186381.02993

380000 requests made thus far. Current means:
- Total:               100%, 190391.112826
- Spawn:               1.930262%,  3675.048234
- Load request:        0.01561%,      29.7208
- Initialise response: 0.175649%,     334.4196
- Handle:              97.878478%, 186351.924192

390000 requests made thus far. Current means:
- Total:               100%, 190256.267526
- Spawn:               1.882102%,  3580.816228
- Load request:        0.015221%,    28.958728
- Initialise response: 0.175878%,   334.618879
- Handle:              97.9268%, 186311.87369

400000 requests made thus far. Current means:
- Total:               100%, 190115.65088
- Spawn:               1.836406%,  3491.295823
- Load request:        0.014851%,     28.23476
- Initialise response: 0.175991%,   334.585708
- Handle:              97.972752%, 186261.53459

Alas, for some reason benchmarking with 'ab' gives really poor results - around 1800 requests per second.

My CPU is:
Intel(R) Core(TM) i7-2670QM CPU @ 2.20GHz

Substantial Sample Application

Should include widespread use of many middleware, API integration, database integration, etc. I'd love to see what a full app written in Iron actually looks like and it would be extremely helpful for people trying to learn the framework.

headers modified after res.serve() are never written to response

Headers are written on res.serv(), therefore headers added after are ignored. I don't think this is the desired outcome.

example:

let _ = res.serve(::http::status::Ok, "Hello, world!");
res.headers.extensions.insert("Server".to_string(), "iron".to_string());

Add hyperlinks to docs

There should be easier docs navigation than provided for within rustdoc, using the same linking scheme.

Any time we reference another trait/struct/fn in our /// comments, we should use markdown to link them correctly to their doc like so:

Furnace

The relative link is dependent on where we are in the file structure (look at generated docs for more details).

Handle Url Encoded Urls

@zzmp - currently, urls with url-encoded values cause Iron to silently fail (or trigger the on_error() method). This is true even outside query parameters. Apparently, we need to use rust-encoding to properly handle these values.

Is the current API problematic with regards to concurrency?

Hi guys, I just checked out the Iron docs, and I realized that there might be potential problems with the way the middleware API is designed, given that requests could be served concurrently. I may be way of base with this, so feel free to call me and idiot in case my reasoning is off.

Here's the middleware example from the homepage:

#[deriving(Clone)]
struct ResponseTime { entry: u64 };

impl Middleware for ResponseTime {
    fn enter(&mut self, _: &mut Request, _: &mut Response, _: &mut Alloy) -> Status {
        self.entry = time::now(); Continue
    }
    fn exit(&mut self, _: &mut Request, _: &mut Response, _: &mut Alloy) -> Status {
        println!("Response took: {} ms", time::now() - self.entry);
    }
}

fn hello_world(_: &mut Request, res: &mut Response, _: &mut Alloy) -> Status {
    res.write(b"Hello World!");
    Continue
}

fn main() {
    let mut server: ServerT = Iron::new();
    server.chain.link(ResponseTime { entry: 0u });
    server.chain.link(FromFn::new(hello_world));
}

ResponseTime is instantiated once for the server, it becomes shared mutable state. Rust prevents us from mutating the middleware concurrently, which is great, but it doesn't help in this case. In case it isn't obvious:

  • Request A: Enter middleware @ 1234 -> set entry to 1234
  • Request B: Enter middleware @ 1236 -> set entry to 1236
  • Request A: Exit middleware @1238 -> response time is 1238 - 1236 = 2

Request A had a response time of 4ms, but the middleware claims the response time was 2ms instead.

Clearly sharing middleware like this is not safe.

One could argue "Well then don't do that". Clearly adding states to middleware is a bad idea, so let's not do that then. I think this goes against Rust's philosophy of avoiding errors by making it impossible to make them in the first place. I've worked with concurrent Rack middlewares in Ruby which have screwed this up because they didn't properly consider the concurrency problems involved.

An easy fix would be changing the borrow in the middleware to &self instead of &mut self, but then the kind of thing that the ResponseTime middleware achieves quite easily would be pretty awkward to implement.

Again, apologies if I'm way off on this critique. I haven't looked at the source at all, but I wanted to voice this concern in case it is valid, and requires changing the API before it's too late.

Compile Common

  • Router
  • Mount
  • Persistent
  • Static File
  • Parsers (unlikely to be fixed, should be obsoleted by decode when I get something working)
  • Logger
  • Cookie
  • Session

Not Common:

  • Iron-Cors
  • Iron-Test

Question -- convert u16 into http:status::Status enum?

I'm unable to get the equivalent code working in DefaultErrors:

extern crate iron;
use iron::status::Status;

fn main() {
    let status_code: u16 = 200;
    let status: Option<Status> = Status::from_u16(status_code);
    println!("{}", status);
}

Normally, I receive the error message "unresolved name from_u16". Do you have any insight into how I might get this working?

Abstract Iron to traits for extensibility.

Iron is hard-coded to use rust-http, as it is a pub struct.

Eventually, we should consider abstracting its impl to traits (potentially with defaults to rust-http) so that other crates/bindings can be used.

Request, Response may be only choices for coercion - not extensible

Types are coerced in Iron with no extensibility. The only choice for coerced types is, at this point, IronRequest and IronResponse, unless we retool the boot process.

The coercion would need to be stored in the Iron struct as functions.
This might be better saved until we have something to work with besides rust-http, but I want to keep it in mind.

Create a friendlier development workflow

Currently it's not possible to develop an application with Iron, following the 'change-refresh-test` paradigm. This approach is very convenient and is used in many modern web frameworks.
With interpreted languages this paradigm is natural, scripts are re-parsed and re-executed for every browser request. With compiled languages it's possible if the compilation is fast enough.

Rust compiler is fairly fast, so I would think of a Cargo extension that watches file changes in the background and recompiles them when they occur.
A typical command could be:

cargo live - performs initial compilation and starts watching the files. When some of the rust files change, the background recompilation is triggered and then the application is restarted.

Currently one needs to:

  1. Kill running application (if it's running).
  2. Compile the application with cargo build
  3. Copy the executable to the place, where the mounted middleware paths make sense.
  4. Start the application.

Step 2 is necessary because executable is places in target directory, where paths like assets/main.js or views/index.html don't exist.

Type-Safe, Lazy, Order-Independent Plugin System

I've come up with and implemented a new scheme for fast, safe, type-directed plugins that allow types to be extended in a type-safe way. I implemented a version of this solution here: https://github.com/reem/rust-plugin.

My general thoughts are that we should expose a system similar to the one in rust-plugin, in fact we can even use it as soon as anymap is updated for the methods necessary.

Effectively all we have to do to enable this API would be to add a dependency on rust-plugin and implement Extensible for both Request and Response, which would necessitate adding an AnyMap to Response. Coincidentally I think we should also rename the alloy field to extensions and possibly remove the alloy type in favor of just using AnyMap directly, but I'm unsure.

Hello World not working

Not sure what I'm making wrong, but for this example I'm getting following output

λ bennyklotz IronApp → λ git master* → cargo run
   Compiling IronApp v0.0.1 (file:///home/benny/Web/rust/learn/IronApp)
error: linking with `cc` failed: exit code: 1
note: cc '-m64' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-o' '/home/benny/Web/rust/learn/IronApp/target/IronApp' '/home/benny/Web/rust/learn/IronApp/target/IronApp.o' '-Wl,--whole-archive' '-lmorestack' '-Wl,--no-whole-archive' '-nodefaultlibs' '-fno-lto' '-Wl,--gc-sections' '-pie' '-Wl,--as-needed' '/home/benny/Web/rust/learn/IronApp/target/deps/libiron-94e197af3c7f7b9d.rlib' '/home/benny/Web/rust/learn/IronApp/target/deps/liberror-e5e02eafec1ab2f1.rlib' '/home/benny/Web/rust/learn/IronApp/target/deps/libtypeable-d0d1baca4b0d6107.rlib' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lnative-4e7c5e5c' '/home/benny/Web/rust/learn/IronApp/target/deps/libcontent_type-b3fc4f01bc3dcbfb.rlib' '/home/benny/Web/rust/learn/IronApp/target/deps/libphf-4fc01267f85abb4e.rlib' '/home/benny/Web/rust/learn/IronApp/target/deps/libplugin-f845a6ab531c9346.rlib' '/home/benny/Web/rust/learn/IronApp/target/deps/libphantom-da5bb593d3eb3a9e.rlib' '-L' '/home/benny/Web/rust/learn/IronApp/target/deps' '-lgenerator-e170cac01c08bdc6' '-L' '/home/benny/Web/rust/learn/IronApp/target/deps' '-lphf_mac-78b8694be35c3487' '/home/benny/Web/rust/learn/IronApp/target/deps/libtypemap-3fdac74be380d9e4.rlib' '/home/benny/Web/rust/learn/IronApp/target/deps/libunsafe-any-411b26d39a73c121.rlib' '/home/benny/Web/rust/learn/IronApp/target/deps/libreplace-map-d1de898a4eb569a5.rlib' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lrustc-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lflate-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-ltime-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lrustc_back-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lsyntax-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lterm-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-larena-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lfmt_macros-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lgraphviz-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lgetopts-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-ldebug-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lrbml-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lserialize-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lrustc_llvm-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-llog-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lregex-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lstd-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lsync-4e7c5e5c' '-L' '/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-lrustrt-4e7c5e5c' '-L' '/home/benny/Web/rust/learn/IronApp/target' '-L' '/home/benny/Web/rust/learn/IronApp/target/deps' '-L' '/home/benny/Web/rust/learn/IronApp/target/native/http-b27c1e7938f5a5d0' '-L' '/home/benny/Web/rust/learn/IronApp/.rust' '-L' '/home/benny/Web/rust/learn/IronApp' '-Wl,--whole-archive' '-Wl,-Bstatic' '-Wl,--no-whole-archive' '-Wl,-Bdynamic' '-lssl' '-lcrypto' '-lcrypto' '-lcrypto' '-lcrypto' '-lcrypto' '-lcrypto' '-lcrypto' '-lcrypto' '-lrt' '-lpthread' '-lrt' '-ldl' '-lm' '-ldl' '-lpthread' '-lgcc_s' '-lpthread' '-lc' '-lm' '-lcompiler-rt'
note: /home/benny/Web/rust/learn/IronApp/target/deps/libgenerator-e170cac01c08bdc6.so: undefined reference to `BN_is_zero'
collect2: error: ld returned 1 exit status

error: aborting due to previous error
Could not compile `IronApp`.

To learn more, run the command again with --verbose.
λ bennyklotz IronApp → λ git master* → 

Environment:

λ bennyklotz IronApp → λ git master* → rustc --version
rustc 0.12.0-nightly (94b0aace1 2014-09-27 23:12:54 +0000)
λ bennyklotz IronApp → λ git master* → cargo --version
cargo 0.0.1-pre-nightly (ee02b9a 2014-09-25 16:50:29 +0000)
λ bennyklotz IronApp → λ git master* → uname -a
Linux bennyklotz.dev 3.13.0-36-generic #63-Ubuntu SMP Wed Sep 3 21:30:07 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

Response.from_file() should not automatically override existing Response

@michaelsproul @reem I know you guys just updated this, but I'd like to argue that we shouldn't do too much in from_file() (or we ought to provide a less opinionated convenience method).

Specifically, in my library DefaultErrors, I want to be able to serve a static file as an error message to site visitors. The status should not be 200 -- it should be 404, 500, etc. Perhaps my use case is limited, but it does seem a bit odd to entirely discard the existing response and generate a totally new one.

I realize that developers building on top of Iron will want the existing implementation 99% of the time.

@reem would you be interested in a PR from me that creates a separate method that reads a file into the body of an existing Response object?

Make iron/iron's travis go green (pass all tests)

Last nightly rust-ci build failed due to reem/rust-unsafe-any dependency. reem/rust-unsafe-any failed cargo doc:

Build failed, waiting for other jobs to finish...
Could not document `unsafe-any`.

--- stderr

task '<unnamed>' failed at 'failed to generate documentation: couldn't create directory 
(File exists; path=/home/travis/build/iron/iron/target/doc; mode=FilePermission { bits: 448 })',
/home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/librustdoc/lib.rs:286

Incorrect Links and Other Smaller Stuff

I'm quite impressed by this project! I was just browsing through the documentation and noticed these little things, which are themselves far too small for individual issues:

  • The link to urldecoded in the Readme doesn't work (it's spelled urlencod_ing_).
  • You say "Iron averages 17,000+ requests per second for hello world." but this information is worthless with nothing to compare it to. How many requests per seconds does a similar php/node/go implementation achieve on the same machine? Just link to a gist with a .rs file, a .php file, how to run this, and the results and everything will become much clearer.
  • You should add the short description and the "hello world" example from the Readme as a doc comment to lib.rs so the documentation index shows it.
  • The link to rust-http in iron.rs doesn't work because of the quotation marks in the brackets.

Introducing DefaultErrors

@reem,

Last week I promised to create a new piece of middleware to provide an easy error messages for specific status codes. Today, I deliver on that promise with DefaultErrors.

It's an early version, but it allows you to register a response (either a static string or file) for a specific http status code. For instance, you can register a custom 404 page.

I wasn't sure of the best way to reach you, so I figured I'd open an issue. Thanks for all your encouragement and support! Let me know if I should move this information somewhere else or if you have any feedback on this project.

Use cargo install script

Cargo now uses an install script, and this makes Travis fail:

$ curl http://static.rust-lang.org/cargo-dist/cargo-nightly-linux.tar.gz | sudo tar --strip-components 1 -C /usr -xzf -
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  9.7M  100  9.7M    0     0  5852k      0  0:00:01  0:00:01 --:--:-- 6132k
$ cargo build -v
/home/travis/build.sh: line 244: cargo: command not found
The command "cargo build -v" exited with 127.

We'll need to update our .travis.yml to account for this.

Weirdness with ChainBuilder.catch

An error returned by ChainBuilder.call causes all the middleware to be run twice... Not ideal. Perhaps we should just remove ChainBuilder.catch?

Cannot compile on OS X

Trying to compile on OS X: I cloned, ran "cargo build", and got the following error:

note: ld: warning: directory not found for option '-L/Users/chadrussell/.cargo/git/checkouts/rust-http-content-type-e95bbac12cca2eca/master/generator/.rust' Undefined symbols for architecture x86_64: "_BN_is_zero", referenced from: bn::BigNum.Zero::is_zero::hb7701ad9f388df0fbTa in libopenssl-fbe75530f7eda428.rlib(openssl-fbe75530f7eda428.o) ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

Obviously it is a linker error. I have libssl installed, any ideas what the fix might be?

Return "404 Not Found" when no middleware handles a request

Thank you for such a cool Rust library!

The following Express server has no middleware, and it returns 404 Not Found for all requests:

var connect = require('connect');
var http = require('http');

var app = connect();
http.createServer(app).listen(3000);

This makes sense, because if no middleware chooses to handle a given request, treating it as a 404 Not Found gives sensible results.

But if we do the same thing in Iron:

extern crate http;
extern crate iron;

use std::io::net::ip::Ipv4Addr;
use iron::{Iron,Server};

fn main() {
    let mut server: Server = Iron::new();
    server.listen(Ipv4Addr(0, 0, 0, 0), 3000);
}

…we get a 200 OK with an empty body:

$ telnet 0.0.0.0 3000
Trying 0.0.0.0...
Connected to 0.0.0.0.
Escape character is '^]'.
GET / HTTP/1.1
Host: www.example.com

HTTP/1.1 200 OK
Transfer-Encoding: chunked

0

This means that every Iron app that wants to return a 404 must manually install a Not Found handler:

fn not_found(_req: &mut Request, res: &mut Response,
             _alloy: &mut Alloy) -> Status {
    let _ = res.serve(NotFound, "Not found."));
    Unwind
}

fn main() {
    let mut server: Server = Iron::new();
    server.chain.link(FromFn::new(not_found));
    server.listen(Ipv4Addr(0, 0, 0, 0), get_server_port());
}

At least to me, it seems like 404 Not Found is a much more sensible default for an unhandled request, because doing so treats all URLs with no explicit handlers as non-existent. It's also the default for Connect.js. Rack, on the other hand, makes it hard to create an application without a default handler, but I could probably figure out a way to work around that if anybody is interested in Rack's defaults.

Once again, thank you for a very useful library!

Describe how to write unit tests for middleware

Currently I want to fix iron-graveyard/static-file#36. Coming from Ruby/JS my first attempt would be to write a unit/integration test to confirm the bug, then fix it, rerun the tests and see them go green. I don't know where to start in writing a unit test for a middleware.

Please update the documentation with at least one example of doing it.

Add universal, configurable parsing as a built-in feature or core middleware

Things like parsing the body are so basic that I think we should include them as builtins, so that request.decode::<SomethingDecodable>() works right out of the box. However, this should be highly configurable, and significant thought is needed into how this should work.]

Will post tomorrow with further thoughts.

Creating AroundMiddleware is tricky.

Capturing a handler inside a struct implementing AroundMiddleware is unergonomic. It seems like quite a natural pattern would be:

struct SomeStruct {
    handler: Box<Handler + Send + Sync>
}

impl Handler for SomeStruct {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        match self.handler() {
            Ok(res) => // do something
            Err(err) => // do something else
        }
    }
}

impl AroundMiddleware for SomeStruct {
    fn with_handler(&mut self, handler: Box<Handler + Send + Sync>) {
        self.handler = handler
    }
}

The problem is that it's impossible to create an empty SomeStruct without a handler. I see two solutions:

  1. Use an optional handler inside structs implementing AroundMiddleware (requires more matching).
  2. Make AroundMiddleware's method static to encourage the above pattern. Something like:
fn from_handler(handler: Box<Handler + Send + Sync>) -> Self;

pinning deps versions ?

replace-map is currently broken see, reem/rust-replace-map#2

To fix this, I have pinned it to rev 2bbe0c9352f1a781293e52e88d21f79644a405a9 in the cargo file

Since some of the deps are very new projects, what about pinning all of them to specific revisions so "cargo build" works ?

Ergonomics - AroundMiddleware

When writing AroundMiddleware, so far I'm relying using Option in my own struct so that I can create AroundMiddleware without a handler before the with_handler() method passes in the real handler. Is there a better way to do this? It seems to make my code unnecessarily complex. Thanks!

Move alloy to Request::alloy

This many advantages, the least of which is it means enter and exit have shorter signatures. Mostly, this allows a transition from manually looking things up in an alloy to using Mixins.

fn is no longer cloneable

This is due to the implicit bound lifetimes in &mut. See rust-lang/rust#14820

Until this is fixed upstream, we'll need to have a wrapper for functions. Essentially, that is what middleware is, so this merits discussion.

If we do, it can be something like pub struct MiddleFn(fn (&mut ...) -> Status), where we will impl Clone for MiddleFn and impl Middleware for MiddleFn.

I'll work on a PR tonight, and we can discuss in the AM. I do not think we should implement a workaround, instead striking the function impl of Middleware from iron. This will avoid having to deprecate the workaround struct in the future, and prevent code bloat.

Document a proper way to benchmark

Iron averages 17,000+ requests per second for hello world.

I was excited and close to a nerdgasm after I read this, however I can't reach anywhere close to that number while testing with ab.

Here's the best result I could get

Server Software:        
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /
Document Length:        23 bytes

Concurrency Level:      10
Time taken for tests:   5.030 seconds
Complete requests:      4000
Failed requests:        0
Write errors:           0
Total transferred:      280000 bytes
HTML transferred:       92000 bytes
Requests per second:    795.17 [#/sec] (mean)
Time per request:       12.576 [ms] (mean)
Time per request:       1.258 [ms] (mean, across all concurrent requests)
Transfer rate:          54.36 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.5      0      11
Processing:     1   12   5.1     12      35
Waiting:        0   12   5.1     12      35
Total:          1   13   5.1     12      35

Percentage of the requests served within a certain time (ms)
  50%     12
  66%     14
  75%     16
  80%     17
  90%     19
  95%     21
  98%     24
  99%     26
 100%     35 (longest request)

Increasing concurrency breaks after a certain point

$ ab -n 4000 -c 1024 http://127.0.0.1:3000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 400 requests
Completed 800 requests
Completed 1200 requests
Completed 1600 requests
Completed 2000 requests
Completed 2400 requests
Completed 2800 requests
Completed 3200 requests
Completed 3600 requests
apr_socket_recv: Connection reset by peer (104)
Total of 3997 requests completed

I'm using hello.rs from examples and Cargo is my builder.

Oh and here are some server info (I like the way it does this)

10000 requests made thus far. Current means:
- Total:               100%, 562597075.1797
- Spawn:               4.411144%, 24816968.919
- Load request:        94.218812%, 530072282.7292
- Initialise response: 0.387284%, 2178851.0601
- Handle:              0.982759%, 5528972.4714

20000 requests made thus far. Current means:
- Total:               100%, 290072743.8153
- Spawn:               7.147771%, 20733734.58895
- Load request:        91.455186%, 265286567.5536
- Initialise response: 0.379641%, 1101235.3573
- Handle:              1.017402%, 2951206.31545

30000 requests made thus far. Current means:
- Total:               100%, 217531289.832967
- Spawn:               13.366853%, 29077087.7829
- Load request:        85.067903%, 185049307.6369
- Initialise response: 0.451864%, 982945.529467
- Handle:              1.11338%, 2421948.8837

Maybe ab has some overhead, I don't know.

What is the proper way to benchmark? Or is it something else with my machine that caps my results?

$ rustc -v
rustc 0.12.0-pre (459ffc2adc74f5e8b64a76f5670edb419b9f65da 2014-07-17 01:16:19 +0000)

(feat) Provide a useful interface to Request URL data.

Exposing a url::Url is less than ideal as we know the URL will always be in a relative scheme like HTTP or HTTPS.

@SimonSapin's rust-url strictly adheres to the WhatWG URL spec, so I don't think we can expect upstream changes for our own convenience.

To provide Iron users with a friendlier interface for HTTP and HTTPS URLs, I think we should wrap a url::Url. In order to minimise the use of {Option,Result}::unwrap these are the features I would like to add to the wrapper:

  • A method to retrieve the port as a 32-bit integer. HTTP and HTTPS have well defined default ports which can be returned in the case where no port is explicitly provided. The url::Url::port method returns an Option<&str>, which is guaranteed to be Some for relative schemes. It can be empty, in the case of a file:// scheme, but seeing as we're writing a web server, we should be able to safely unwrap the return value of std​::i32​::parse_bytes.
  • A method to retrieve the username as an Option<&str>. The URL spec dictates that usernames are possibly empty strings, so rust-url just provides a username: String field inside the RelativeSchemeData struct. For parsing purposes the presence of an @ character is irrelevant: http://example.com and http://@example.com parse the same and yeild a username field equal to "". I'm tempted to map the empty string to None to be more Rust-like, and to remain consistent with the password accessor. One thing to note is that url::Url::username returns an Option<&str>, but it's only None in the case of a non-relative scheme like data:.
  • A method to retrieve the password as an Option<&str>. Just return a reference to the password field from the relative scheme data (equivalent to calling url::Url::password, but with one less match).
  • A method to retrieve the host as a url::Host. Use RelativeSchemeData::host.
  • A method to retrieve the path as a &[String]. Use RelativeSchemeData::path.
  • A method to retrieve the query as an Option<&str>. Use Url::query.
  • A method to retrieve the fragment as an Option<&str>. Use Url::fragment.

Unresolved issues:

  • What do we do about domain?
  • What should we call the wrapper class? WebURL seems kind of appropriate, but not perfect.
  • Should we use stronger types for any of the fields? Username(&str), Password(&str), etc?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.