{"id":16603799,"url":"https://github.com/tuffnatty/zstd-asgi","last_synced_at":"2026-03-11T23:02:20.919Z","repository":{"id":62591017,"uuid":"406949162","full_name":"tuffnatty/zstd-asgi","owner":"tuffnatty","description":"ASGI middleware for Zstandard compression","archived":false,"fork":false,"pushed_at":"2025-11-24T15:51:02.000Z","size":37,"stargazers_count":31,"open_issues_count":4,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-25T08:22:12.811Z","etag":null,"topics":["asgi","middleware","zstd"],"latest_commit_sha":null,"homepage":"","language":"Python","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/tuffnatty.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-09-15T23:11:02.000Z","updated_at":"2026-02-02T19:41:03.000Z","dependencies_parsed_at":"2025-09-07T23:20:32.934Z","dependency_job_id":"ca8199b5-92b7-4e1e-8470-66da10a37433","html_url":"https://github.com/tuffnatty/zstd-asgi","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/tuffnatty/zstd-asgi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuffnatty%2Fzstd-asgi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuffnatty%2Fzstd-asgi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuffnatty%2Fzstd-asgi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuffnatty%2Fzstd-asgi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tuffnatty","download_url":"https://codeload.github.com/tuffnatty/zstd-asgi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuffnatty%2Fzstd-asgi/sbom","scorecard":{"id":901944,"data":{"date":"2025-08-11","repo":{"name":"github.com/tuffnatty/zstd-asgi","commit":"012dd2c2617e90a36bdebf16965303f7140f19bc"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":1,"reason":"Found 2/16 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pypi-publish.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/tuffnatty/zstd-asgi/pypi-publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pypi-publish.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/tuffnatty/zstd-asgi/pypi-publish.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/pypi-publish.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/tuffnatty/zstd-asgi/pypi-publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/tuffnatty/zstd-asgi/tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/tuffnatty/zstd-asgi/tests.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/pypi-publish.yml:20","Warn: pipCommand not pinned by hash: .github/workflows/pypi-publish.yml:21","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:29","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:30","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   4 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/pypi-publish.yml:1","Warn: no topLevel permission defined: .github/workflows/tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T15:54:04.423Z","repository_id":62591017,"created_at":"2025-08-24T15:54:04.424Z","updated_at":"2025-08-24T15:54:04.424Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30406400,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-11T22:36:59.286Z","status":"ssl_error","status_checked_at":"2026-03-11T22:36:57.544Z","response_time":84,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["asgi","middleware","zstd"],"created_at":"2024-10-12T00:53:06.820Z","updated_at":"2026-03-11T23:02:20.914Z","avatar_url":"https://github.com/tuffnatty.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# zstd-asgi\n\n[![Packaging status](https://img.shields.io/pypi/v/zstd-asgi?color=%2334D058\u0026label=pypi%20package)](https://pypi.org/project/zstd-asgi)\n[![CI](https://github.com/tuffnatty/zstd-asgi/workflows/Tests/badge.svg)](https://github.com/tuffnatty/zstd-asgi/actions?query=workflow%3ATests)\n\n\n\n`ZstdMiddleware` adds [Zstd](https://github.com/facebook/zstd) response compression to ASGI applications (Starlette, FastAPI, Quart, etc.). It provides faster and more dense compression than GZip, and can be used as a drop in replacement for the `GZipMiddleware` shipped with Starlette.\n\n**Installation**\n\n```bash\npip install zstd-asgi\n```\n\n## Examples\n\n### Starlette\n\n```python\nfrom starlette.applications import Starlette\nfrom starlette.responses import JSONResponse\nfrom starlette.routing import Route\nfrom starlette.middleware import Middleware\n\nfrom zstd_asgi import ZstdMiddleware\n\nasync def homepage(request):\n    return JSONResponse({\"data\": \"a\" * 4000})\n\napp = Starlette(\n  routes=[Route(\"/\", homepage)],\n  middleware=[Middleware(ZstdMiddleware)],\n)\n```\n\n### FastAPI\n\n```python\nfrom fastapi import FastAPI\nfrom zstd_asgi import ZstdMiddleware\n\napp = FastAPI()\napp.add_middleware(ZstdMiddleware)\n\n@app.get(\"/\")\ndef home() -\u003e dict:\n    return {\"data\": \"a\" * 4000}\n```\n\n## API Reference\n\n**Overview**\n\n```python\napp.add_middleware(\n  ZstdMiddleware,\n  level=3,\n  minimum_size=500,\n  threads=0,\n  write_checksum=True,\n  write_content_size=False,\n  gzip_fallback=True,\n  excluded_handlers=None,\n)\n```\n\n**Parameters**:\n\n- `level`: Compression level. Valid values are -2¹⁷ to 22.\n- `minimum_size`: Only compress responses that are bigger than this value in bytes.\n- `threads`: Number of threads to use to compress data concurrently. When set, compression operations are performed on multiple threads. The default value (0) disables multi-threaded compression. A value of -1 means to set the number of threads to the number of detected logical CPUs.\n- `write_checksum`: If True, a 4 byte content checksum will be written with the compressed data, allowing the decompressor to perform content verification.\n- `write_content_size`: If True (the default), the decompressed content size will be included in the header of the compressed data. This data will only be written if the compressor knows the size of the input data.\n- `gzip_fallback`: If `True`, uses gzip encoding if `zstd` is not in the Accept-Encoding header.\n- `excluded_handlers`: List of handlers to be excluded from being compressed.\n\n## Performance\n\nA simple comparative example using Python `sys.getsizof()` and `timeit`:\n\n```python\n# ipython console\nimport gzip\nimport sys\n\nimport brotli\nimport requests\ntry:\n    from compression import zstd\nexcept ImportError:\n    from backports import zstd\n\npage = requests.get(\"https://github.com/fullonic/brotli-asgi\").content\n%timeit zstd.compress(page, level=3)\n# 718 μs ± 37.2 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\nsys.getsizeof(zstd.compress(page, level=3))\n# 47718\n%timeit brotli.compress(page, quality=4)\n# 2.64 ms ± 246 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)\nsys.getsizeof(brotli.compress(page, quality=4))\n# 45095\n%timeit gzip.compress(page, compresslevel=6)\n# 4.89 ms ± 216 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)\nsys.getsizeof(gzip.compress(page, compresslevel=6))\n# 52577\n```\n\n## Compatibility\n\n- [RFC 8878](https://datatracker.ietf.org/doc/rfc8878/)\n- [Zstd nginx module](https://github.com/tokers/zstd-nginx-module)\n- [wget2](https://gitlab.com/gnuwget/wget2)\n- [Browser support](https://caniuse.com/zstd): transparent support in recent Chrome/Edge/Opera and Firefox versions.\n- [encode/httpx](https://github.com/encode/httpx/releases/tag/0.27.1)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuffnatty%2Fzstd-asgi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftuffnatty%2Fzstd-asgi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuffnatty%2Fzstd-asgi/lists"}