{"id":24725561,"url":"https://github.com/routerify/stream-body","last_synced_at":"2025-12-12T15:24:32.365Z","repository":{"id":47556221,"uuid":"253054525","full_name":"routerify/stream-body","owner":"routerify","description":"An HttpBody implementation with efficient streaming support for the Rust HTTP library hyper","archived":false,"fork":false,"pushed_at":"2021-07-28T07:53:07.000Z","size":24,"stargazers_count":24,"open_issues_count":3,"forks_count":8,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-13T23:20:19.851Z","etag":null,"topics":["asynchronous","http","hyper","rust","stream"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/routerify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-04T17:08:45.000Z","updated_at":"2025-02-14T19:47:27.000Z","dependencies_parsed_at":"2022-09-11T07:24:11.257Z","dependency_job_id":null,"html_url":"https://github.com/routerify/stream-body","commit_stats":null,"previous_names":["rousan/stream-body"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/routerify/stream-body","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/routerify%2Fstream-body","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/routerify%2Fstream-body/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/routerify%2Fstream-body/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/routerify%2Fstream-body/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/routerify","download_url":"https://codeload.github.com/routerify/stream-body/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/routerify%2Fstream-body/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001975,"owners_count":26083244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asynchronous","http","hyper","rust","stream"],"created_at":"2025-01-27T13:19:47.406Z","updated_at":"2025-10-09T19:31:16.705Z","avatar_url":"https://github.com/routerify.png","language":"Rust","readme":"# stream-body\n\n[![crates.io](https://img.shields.io/crates/v/stream-body.svg)](https://crates.io/crates/stream-body)\n[![Documentation](https://docs.rs/stream-body/badge.svg)](https://docs.rs/stream-body)\n[![MIT](https://img.shields.io/crates/l/stream-body.svg)](./LICENSE)\n\nAn [HttpBody](https://docs.rs/hyper/0.13.4/hyper/body/trait.HttpBody.html) implementation with efficient streaming support for the Rust HTTP library [hyper](https://hyper.rs/).\n\n[Docs](https://docs.rs/stream-body)\n\n## Motivation\n\nThe existing [Body](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html) type in [hyper](https://hyper.rs/) uses [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html)\nas streaming chunk. Hence, a lot of buffer allocation and de-allocation happen during the real-time large data streaming because of the [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html) type.\nTherefore, `StreamBody` comes to tackle this kind of situation. The `StreamBody` implements [HttpBody](https://docs.rs/hyper/0.13.4/hyper/body/trait.HttpBody.html) and uses `\u0026[u8]`\nslice as the streaming chunk, so it is possible to use the same buffer without allocating a new one; hence it overcomes any allocation/de-allocation overhead.\n\nAlso, the [channel()](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html#method.channel) method in hyper [Body](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html) returns\na pair of a [Sender](https://docs.rs/hyper/0.13.4/hyper/body/struct.Sender.html) and a [Body](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html).\nHere, the [Sender](https://docs.rs/hyper/0.13.4/hyper/body/struct.Sender.html) accepts [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html) as a data chunk which again\ncreates allocation/de-allocation overhead.\nTo solve this, `StreamBody` has a method named `StreamBody::channel()` which returns a pair of an [AsyncWrite](https://docs.rs/tokio/0.2.16/tokio/io/trait.AsyncWrite.html) and the `StreamBody`\nitself. As the [AsyncWrite](https://docs.rs/tokio/0.2.16/tokio/io/trait.AsyncWrite.html) accepts `\u0026[u8]` instead of [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html), there will\nbe no allocation/de-allocation overhead.\n\n## Usage\n\nFirst add this to your Cargo.toml:\n\n```toml\n[dependencies]\nstream-body = \"0.1\"\n```\n\nAn example on handling a large file:\n```rust\nuse hyper::service::{make_service_fn, service_fn};\nuse hyper::{Body, Request, Response, Server};\nuse std::{convert::Infallible, net::SocketAddr};\nuse stream_body::StreamBody;\nuse tokio::fs::File;\nuse tokio::io::{AsyncReadExt, AsyncWriteExt};\n\nasync fn handle(_: Request\u003cBody\u003e) -\u003e Result\u003cResponse\u003cStreamBody\u003e, Infallible\u003e {\n    let (mut writer, body) = StreamBody::channel();\n\n    tokio::spawn(async move {\n        let mut f = File::open(\"large-file\").await.unwrap();\n\n        // Reuse this buffer\n        let mut buf = [0_u8; 1024 * 16];\n        loop {\n            let read_count = f.read(\u0026mut buf).await.unwrap();\n            if read_count == 0 {\n                break;\n            }\n            writer.write_all(\u0026buf[..read_count]).await.unwrap();\n        }\n    });\n\n    Ok(Response::builder().body(body).unwrap())\n}\n\n#[tokio::main]\nasync fn main() {\n    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));\n\n    let make_svc = make_service_fn(|_conn| async { Ok::\u003c_, Infallible\u003e(service_fn(handle)) });\n\n    let server = Server::bind(\u0026addr).serve(make_svc);\n\n    if let Err(e) = server.await {\n        eprintln!(\"server error: {}\", e);\n    }\n}\n```\n\n## Contributing\n\nYour PRs and stars are always welcome.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frouterify%2Fstream-body","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frouterify%2Fstream-body","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frouterify%2Fstream-body/lists"}