Skip to content

Commit ea44202

Browse files
committed
Add support for a zstandard compressed endpoint
1 parent e32f993 commit ea44202

5 files changed

Lines changed: 46 additions & 0 deletions

File tree

httpbin/core.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,23 @@ def view_brotli_encoded_content():
541541
return jsonify(get_dict("origin", "headers", method=request.method, brotli=True))
542542

543543

544+
@app.route("/zstd")
545+
@filters.zstd
546+
def view_zstandard_encoded_content():
547+
"""Returns zstandard-encoded data.
548+
---
549+
tags:
550+
- Response formats
551+
produces:
552+
- application/json
553+
responses:
554+
200:
555+
description: zstandard-encoded data.
556+
"""
557+
558+
return jsonify(get_dict("origin", "headers", method=request.method, zstandard=True))
559+
560+
544561
@app.route("/redirect/<int:n>")
545562
def redirect_n_times(n):
546563
"""302 Redirects n times.

httpbin/filters.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import zlib
1212

1313
import brotlicffi as _brotli
14+
import zstandard
1415

1516
from six import BytesIO
1617
from decimal import Decimal
@@ -113,3 +114,25 @@ def brotli(f, *args, **kwargs):
113114
return data
114115

115116
return deflated_data
117+
118+
@decorator
119+
def zstd(f, *args, **kwargs):
120+
"""zstandard Flask Response Decorator"""
121+
122+
data = f(*args, **kwargs)
123+
124+
if isinstance(data, Response):
125+
content = data.data
126+
else:
127+
content = data
128+
129+
deflated_data = zstandard.ZstdCompressor().compress(content)
130+
131+
if isinstance(data, Response):
132+
data.data = deflated_data
133+
data.headers['Content-Encoding'] = 'zstd'
134+
data.headers['Content-Length'] = str(len(data.data))
135+
136+
return data
137+
138+
return deflated_data

httpbin/templates/httpbin.1.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ <h2 id="ENDPOINTS">ENDPOINTS</h2>
2121
<li><a href="{{ url_for('view_gzip_encoded_content') }}" data-bare-link="true"><code>/gzip</code></a> Returns gzip-encoded data.</li>
2222
<li><a href="{{ url_for('view_deflate_encoded_content') }}" data-bare-link="true"><code>/deflate</code></a> Returns deflate-encoded data.</li>
2323
<li><a href="{{ url_for('view_brotli_encoded_content') }}" data-bare-link="true"><code>/brotli</code></a> Returns brotli-encoded data.</li>
24+
<li><a href="{{ url_for('view_zstandard_encoded_content') }}" data-bare-link="true"><code>/zstd</code></a> Returns zstandard-encoded data.</li>
2425
<li><a href="{{ url_for('view_status_code', codes='418') }}"><code>/status/:code</code></a> Returns given HTTP Status code.</li>
2526
<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>
2627
<li><a href="{{ url_for('redirect_n_times', n=6) }}"><code>/redirect/:n</code></a> 302 Redirects <em>n</em> times.</li>

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ dependencies = [
3939
'importlib-metadata; python_version<"3.8"',
4040
"six",
4141
"werkzeug >= 2.2.2",
42+
"zstandard >= 0.23.0",
4243
]
4344

4445
[project.optional-dependencies]

tests/test_httpbin.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ def test_brotli(self):
303303
response = self.app.get('/brotli')
304304
self.assertEqual(response.status_code, 200)
305305

306+
def test_zstandard(self):
307+
response = self.app.get('/zstd')
308+
self.assertEqual(response.status_code, 200)
309+
306310
def test_bearer_auth(self):
307311
token = 'abcd1234'
308312
response = self.app.get(

0 commit comments

Comments
 (0)