Rouille Web Framework

repository·master·Indexed 22 days ago

https://github.com/tomaka/rouille

A synchronous Rust micro-web-framework designed for simplicity and ease of use. Rouille uses a dedicated thread for each incoming request and avoids middleware patterns, allowing developers to handle the entire request lifecycle linearly within a server closure. Version 3.6.2.

Tokens
14.5K
Snippets
42
Records
96
Agent score
78%

What's inside rouille

  1. Overview of multipart crate

    master

    The multipart crate provides client- and server-side abstractions for handling HTTP file uploads using Content-Type: multipart/form-data.

    Key details:

    • API Style: It uses a synchronous API. For asynchronous (futures-based) support, use the multipart-async crate.
    • Maintenance Status: Passive maintenance (as of June 2020). Bug reports are addressed as time permits, but no new features are being added to the existing API.
    • Minimum Rust Version: 1.36.0
  2. How Rouille handles requests and architecture

    master

    Rouille is a synchronous micro-web-framework. Unlike many modern frameworks that use asynchronous I/O, green threads, or coroutines, Rouille uses a dedicated thread for each incoming request.

    It does not use a middleware pattern. Instead of registering a chain of middleware functions, you handle the entire request lifecycle linearly within the server closure. This design is intended to be intuitive for Rust developers and avoids the complexity of middleware chains. Because it is synchronous, it is designed to work easily with any third-party library (like databases or templating engines) without requiring specific 'glue code' or asynchronous wrappers.

  3. Compare Rouille's request handling to middleware-based frameworks

    master
    In middleware-based frameworks (like Express.js), you typically register multiple middleware functions that the request passes through. In Rouille, you handle all logic—including what would traditionally be middleware—manually inside the request handler closure provided to start_server.
  4. Use multipart with Rocket

    master

    Direct integration is not provided for Rocket because Rocket handles multipart/form-data internally. However, you can still use multipart on a Rocket server by following the pattern shown in the project's examples.

    See examples/rocket.rs for a concrete implementation example.

  5. Available features in multipart

    master

    The multipart crate provides abstractions for HTTP multipart/form-data requests with the following feature flags:

    • client: Client-side abstractions for generating multipart requests.
    • server: Server-side abstractions for parsing multipart requests.
    • mock: Mock implementations of core client and server traits for debugging or non-standard use.
    • hyper: Integration with the Hyper HTTP library (requires client or server features).
    • iron: Integration with the Iron web application framework.
    • nickel: Integration with the Nickel web application framework.
    • tiny_http: Integration with the tiny_http crate.
  6. How LimitBehavior works in Intercept

    master

    The LimitBehavior enum defines how the Intercept middleware reacts when a request exceeds the configured file_size_limit or file_count_limit:

    • LimitBehavior::ThrowError: The middleware will stop processing and return an IronError. This is the default behavior.
    • LimitBehavior::Continue: The middleware will attempt to continue processing.
      • For size limits: The offending file will be truncated in the resulting Entries.
      • For count limits: The request will be completed with the files received up to the limit.
    #[derive(Clone, Copy, Debug, repr(u32))]
    pub enum LimitBehavior {
        ThrowError,
        Continue,
    }
  7. Handle multipart errors with `LazyError`

    master

    Errors occurring during the lazy construction or transmission of a multipart request are wrapped in LazyError. This error type provides context about which field caused the failure.

    Error Structure

    • field_name: An Option<Cow<'a, str>>. If Some, it contains the name of the field that caused the error (e.g., a file that failed to open). If None, the error occurred during stream initialization or finalization.
    • error: The underlying error (typically std::io::Error).

    LazyError implements std::error::Error and can be converted into a std::io::Error via Into.

  8. Start a simple web server with `start_server`

    master

    The easiest way to get started with Rouille is using the start_server function. It listens on the specified address and executes the provided closure for every incoming request. The closure receives a &Request and must return a Response.

    Important Requirements:

    • The handler closure must capture its environment by value (use the move keyword).
    • The handler must be thread-safe (Send and Sync). If you need to access shared state, use a Mutex or Atomic type.
    • If the handler panics, Rouille will automatically send a 500 Internal Server Error response to the client.
    use rouille::Request;
    use rouille::Response;
    
    rouille::start_server("0.0.0.0:80", move |request| {
        Response::text("hello world")
    });
  9. Use Intercept middleware for Iron-based servers

    master

    The Intercept struct implements BeforeMiddleware for the Iron framework. It intercepts multipart requests, parses them, and stores the resulting Entries in the iron::Request extensions map.

    To use it, add Intercept::default() (or a configured instance) to your Iron Chain using chain.link_before(). You can then retrieve the parsed multipart data from the request extensions using req.extensions.get::<Entries>().

    extern crate iron;
    extern crate multipart;
    
    use iron::prelude::*;
    use multipart::server::Entries;
    use multipart::server::iron::Intercept;
    
    fn main() {
        let mut chain = Chain::new(|req: &mut Request| {
            if let Some(entries) = req.extensions.get::<Entries>() {
                Ok(Response::with(format!("{:?}", entries)))
            } else {
                Ok(Response::with("Not a multipart request"))
            }
        });
    
        // Register the middleware
        chain.link_before(Intercept::default());
    
        Iron::new(chain).http("localhost:80").unwrap();
    }
  10. Use the WebSocket StateMachine for low-level frame parsing

    master

    The StateMachine provides a low-level way to parse WebSocket frames from a stream of bytes. It handles partial data, buffering headers, and decoding masked payloads.

    Workflow:

    1. Initialize a new state machine using StateMachine::new().
    2. Whenever new data is received from the socket, call StateMachine::feed(&[u8]).
    3. Iterate over the returned ElementsIter to process the decoded Element objects.
    4. If you encounter Element::Error, you must immediately terminate the connection.

    Glossary:

    • A WebSocket stream consists of multiple messages.
    • Each message consists of one or more frames.
    • Frames can be received progressively; StateMachine::feed handles the accumulation of bytes across multiple calls.