Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions httpbin/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,23 @@ def view_brotli_encoded_content():
return jsonify(get_dict("origin", "headers", method=request.method, brotli=True))


@app.route("/zstd")
@filters.zstd
def view_zstandard_encoded_content():
"""Returns zstandard-encoded data.
---
tags:
- Response formats
produces:
- application/json
responses:
200:
description: zstandard-encoded data.
"""

return jsonify(get_dict("origin", "headers", method=request.method, zstandard=True))


@app.route("/redirect/<int:n>")
def redirect_n_times(n):
"""302 Redirects n times.
Expand Down
23 changes: 23 additions & 0 deletions httpbin/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import zlib

import brotlicffi as _brotli
import zstandard

from six import BytesIO
from decimal import Decimal
Expand Down Expand Up @@ -113,3 +114,25 @@ def brotli(f, *args, **kwargs):
return data

return deflated_data

@decorator
def zstd(f, *args, **kwargs):
"""zstandard Flask Response Decorator"""

data = f(*args, **kwargs)

if isinstance(data, Response):
content = data.data
else:
content = data

deflated_data = zstandard.ZstdCompressor().compress(content)

if isinstance(data, Response):
data.data = deflated_data
data.headers['Content-Encoding'] = 'zstd'
data.headers['Content-Length'] = str(len(data.data))

return data

return deflated_data
1 change: 1 addition & 0 deletions httpbin/templates/httpbin.1.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ <h2 id="ENDPOINTS">ENDPOINTS</h2>
<li><a href="{{ url_for('view_gzip_encoded_content') }}" data-bare-link="true"><code>/gzip</code></a> Returns gzip-encoded data.</li>
<li><a href="{{ url_for('view_deflate_encoded_content') }}" data-bare-link="true"><code>/deflate</code></a> Returns deflate-encoded data.</li>
<li><a href="{{ url_for('view_brotli_encoded_content') }}" data-bare-link="true"><code>/brotli</code></a> Returns brotli-encoded data.</li>
<li><a href="{{ url_for('view_zstandard_encoded_content') }}" data-bare-link="true"><code>/zstd</code></a> Returns zstandard-encoded data.</li>
<li><a href="{{ url_for('view_status_code', codes='418') }}"><code>/status/:code</code></a> Returns given HTTP Status code.</li>
<li><a href="{{ url_for('response_headers', **{'Content-Type': 'text/plain; charset=UTF-8', 'Server': 'httpbin'}) }}"><code>/response-headers?key=val</code></a> Returns given response headers.</li>
<li><a href="{{ url_for('redirect_n_times', n=6) }}"><code>/redirect/:n</code></a> 302 Redirects <em>n</em> times.</li>
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies = [
'importlib-metadata; python_version<"3.8"',
"six",
"werkzeug >= 2.2.2",
"zstandard >= 0.20.0",
]

[project.optional-dependencies]
Expand Down
4 changes: 4 additions & 0 deletions tests/test_httpbin.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,10 @@ def test_brotli(self):
response = self.app.get('/brotli')
self.assertEqual(response.status_code, 200)

def test_zstandard(self):
response = self.app.get('/zstd')
self.assertEqual(response.status_code, 200)

def test_bearer_auth(self):
token = 'abcd1234'
response = self.app.get(
Expand Down