{"id":19602338,"url":"https://github.com/scottlamb/multipart-stream-rs","last_synced_at":"2025-08-16T17:06:32.167Z","repository":{"id":46234909,"uuid":"361916480","full_name":"scottlamb/multipart-stream-rs","owner":"scottlamb","description":"Rust library to parse and serialize async multipart/x-mixed-replace streams.","archived":false,"fork":false,"pushed_at":"2022-12-01T02:54:55.000Z","size":38,"stargazers_count":13,"open_issues_count":2,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-19T21:21:24.460Z","etag":null,"topics":["http","multipart","rust","stream"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/multipart-stream","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/scottlamb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-04-26T23:01:22.000Z","updated_at":"2025-05-08T14:14:04.000Z","dependencies_parsed_at":"2023-01-23T12:00:28.702Z","dependency_job_id":null,"html_url":"https://github.com/scottlamb/multipart-stream-rs","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/scottlamb/multipart-stream-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottlamb%2Fmultipart-stream-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottlamb%2Fmultipart-stream-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottlamb%2Fmultipart-stream-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottlamb%2Fmultipart-stream-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scottlamb","download_url":"https://codeload.github.com/scottlamb/multipart-stream-rs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottlamb%2Fmultipart-stream-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270742043,"owners_count":24637504,"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-08-16T02:00:11.002Z","response_time":91,"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":["http","multipart","rust","stream"],"created_at":"2024-11-11T09:23:35.885Z","updated_at":"2025-08-16T17:06:32.113Z","avatar_url":"https://github.com/scottlamb.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![crates.io](https://img.shields.io/crates/v/multipart-stream)](https://crates.io/crates/multipart-stream)\n[![docs.rs](https://docs.rs/multipart-stream/badge.svg)](https://docs.rs/multipart-stream)\n[![CI](https://github.com/scottlamb/multipart-stream-rs/workflows/CI/badge.svg)](https://github.com/scottlamb/multipart-stream-rs/actions?query=workflow%3ACI)\n\nRust library to parse and serialize async `multipart/x-mixed-replace` streams,\nsuitable for use with `reqwest`, `hyper`, and `tokio`.\n\nNote `multipart/x-mixed-replace` is different than `multipart/form-data`; you\nmight be interested in the\n[`multipart` crate](https://crates.io/crates/multipart) for that.\n\n## What's a multipart stream for?\n\nA multipart stream is a sequence of parts in one HTTP response, each part\nhaving its own headers and body. A stream might last forever, serving parts\nthat didn't exist at the start of the request. This is a type of \"hanging GET\"\nor [Comet](https://en.wikipedia.org/wiki/Comet_(programming)) request. Each\npart might represent the latest state and conceptually replace previous ones,\nthus the MIME type `multipart/x-mixed-replace`.\n\nIt's a simple HTTP/1.1 way of accomplishing what otherwise might require\nfancier server- and client-side technologies, such as:\n\n*   [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)\n*   [HTTP/2 Server Push](https://en.wikipedia.org/wiki/HTTP/2_Server_Push)\n\nNever-ending multipart streams seem popular in the IP camera space:\n\n*   Dahua IP cameras provide a `multipart/x-mixed-replace` stream of events\n    such as motion detection changes.\n    ([spec](http://www.telecamera.ru/bitrix/components/bitrix/forum.interface/show_file.php?fid=1022477\u0026action=download))\n*   Hikvision IP cameras provide a `multipart/mixed` stream of events,\n    as described\n    [here](https://github.com/scottlamb/moonfire-playground/blob/4e6a786286272ee36f449d761740191c6e6a54fc/camera-motion/src/hikvision.rs#L33).\n*   wikipedia [mentions](https://en.wikipedia.org/wiki/MIME#Mixed-Replace)\n    that IP cameras use this format for MJPEG streams.\n\nThere's a big limitation, however, which is that browsers have fairly low\nlimits on the number of concurrent connections. In Chrome's case, six per\nhost. For this reason, multipart streams are only suitable in HTTP APIs where\nthe clients are *not* web browsers.\n\n## What is a multipart stream exactly?\n\nA multipart response might look like this:\n\n```\nContent-Type: multipart/x-mixed-replace: boundary=B\n\n--B\nContent-Type: text/plain\nContent-Length: 3\n\nfoo\n\n--B\nContent-Type: text/plain\nContent-Length: 3\n\nbar\n```\n\nand is typically paired with `Transfer-Encoding: chunked` or `Connection:\nclose` to allow sending a response whose size is infinite or not known until\nthe end.\n\nI can't find a good specification. [This WHATWG\ndocument](https://html.spec.whatwg.org/multipage/iana.html#multipart/x-mixed-replace)\ndescribes `multipart/x-mixed-replace` loosely. It refers to [RFC\n2046](https://tools.ietf.org/html/rfc2046) which defines multipart encodings\noriginally used for rich emails. I don't think these HTTP multipart streams\nquite follow that RFC. My library currently requires:\n\n*   Any content type—the caller should validate this to taste and pass the\n    boundary parameter to the `multipart-stream` library.\n*   No preamble. That is, no arbitrary bytes to discard before the first\n    part's boundary. (Newlines are okay.)\n*   Zero or more newlines (to be precise: `\\r\\n` sequences) between each part\n    and the next part's boundary.\n*   A `Content-Length` line for each part. This is a much cleaner approach\n    than producers attempting to choose a boundary that doesn't appear in any\n    part and consumers having to search through the part body.\n*   No extra `--` suffix on the final part's boundary. I've never seen one.\n\nPlease open a github issue if you encounter a multipart stream which doesn't\nmatch these requirements.\n\n## What does this library do?\n\nIt takes a stream of `Bytes` (such as those returned by\n[reqwest](https://crates.io/crates/reqwest) or\n[hyper](https://crates.io/crates/hyper)) and returns a stream of\n`multipart_stream::Part`s, or vice versa. (For client or server use cases,\nrespectively.) Each `Part` packages together headers and a body.\n\n## Author\n\nScott Lamb \u0026lt;slamb@slamb.org\u003e\n\n## License\n\nSPDX-License-Identifier: [MIT](https://spdx.org/licenses/MIT.html) OR [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html)\n\nSee [LICENSE-MIT.txt](LICENSE-MIT.txt) or [LICENSE-APACHE](LICENSE-APACHE.txt), respectively.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscottlamb%2Fmultipart-stream-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscottlamb%2Fmultipart-stream-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscottlamb%2Fmultipart-stream-rs/lists"}