hyperium / hyperium/hyper

Low-level pull mode API

Open
#2,901 4 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

B-rfc C-feature
Dominant language
Rust
Stars
16.3k
Forks
1.8k
Avg merge
1d 22h
Merged PRs (30d)
14

Description

PROS

  • Low level, user code has the full flow-control, spawn free in hyper level
  • How-to/When-to use spawn could be full decided by the user level code
    • Connection Level
    • Stream Level
    • Stream with upgrading
    • Request Level
  • Easy to implement a full-controllable graceful shutdown
    • Listener Level
    • Connection level
    • Stream Level
  • Easy to implement priority control for user code
  • Easy to implement memory/resource/number-of-tasks control for user code
  • Possible to let user level code to known response has been sent.

CONS

  • Maybe low level too much

Example

async fn main() -> Result<()> {
    let mut listener = TcpListener::bind(...).await?;
    while let Ok((conn, _)) = listener.accept().await {
        // wrap low-level connection into http connection
        let conn = HttpProtocol::new(conn).await?;

        // stream could be h1/h2 or h3 someday, for h1: each conn yield only one stream
        while let Some(http_stream) = conn.next().await {
            handle_stream(http_stream?).await.ok();
        }
    }
    Ok(())
}

async fn handle_stream(stream: HttpStream) -> Result<()> {
    let (mut input, mut output) = http_stream.split();

    // pull a new request
    // we know that request is one-by-one inside a stream
    while let Some(item) = input.next().await {
        // key could be used to ensure request/response is matched (Eg. no re-order)
        // key is cheap to Clone, maybe Copy
        let (key, req) = item?;

        // handle upgrade if upgradable
        if key.is_upgradable() {
            let stream = output.upgrade(input, key, ...).await?; // consume input & output, into stream
            return handle_upgraded_stream(stream).await;
        }

        // handle request
        let res = handle_request(req).await;

        // now, we have the opportunity to know that reply has been sent
        let now = Instant::now();
        output.send((key, res)).await?;
        eprintln!("reply time: {:?}", now.elapsed());
    }

    Ok(())
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the proposed TcpListener, HttpProtocol, HttpStream, input, and output flow in the example, then compare it with Hyper's existing connection and stream APIs. Define the API boundaries and lifecycle behavior needed for pull-based requests, upgrades, flow control, and graceful shutdown before implementation; done means the design is agreed and covered by appropriate tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend-api-design, networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.