diff --git a/0001-Make-flasgger-dep-optional-26.patch b/0001-Make-flasgger-dep-optional-26.patch index 240edef..4b38e89 100644 --- a/0001-Make-flasgger-dep-optional-26.patch +++ b/0001-Make-flasgger-dep-optional-26.patch @@ -16,31 +16,30 @@ when we want it). Signed-off-by: Adam Williamson --- - httpbin/core.py | 151 +++++++++++++++++++++++++----------------------- + httpbin/core.py | 150 +++++++++++++++++++++++++----------------------- pyproject.toml | 2 +- - 2 files changed, 81 insertions(+), 72 deletions(-) + 2 files changed, 80 insertions(+), 72 deletions(-) diff --git a/httpbin/core.py b/httpbin/core.py -index 5c1783a..2a97447 100644 +index a82c1b8..ca4a845 100644 --- a/httpbin/core.py +++ b/httpbin/core.py -@@ -33,7 +33,11 @@ try: +@@ -33,7 +33,10 @@ try: except ImportError: # werkzeug < 2.1 from werkzeug.wrappers import BaseResponse as Response - from werkzeug.http import parse_authorization_header + -from flasgger import Swagger, NO_SANITIZER -+ +try: + from flasgger import Swagger, NO_SANITIZER +except ImportError: + Swagger = False - + from . import filters from .helpers import ( -@@ -94,77 +98,78 @@ app.add_template_global("HTTPBIN_TRACKING" in os.environ, name="tracking_enabled - +@@ -95,77 +98,78 @@ app.add_template_global("HTTPBIN_TRACKING" in os.environ, name="tracking_enabled + app.config["SWAGGER"] = {"title": "httpbin.org", "uiversion": 3} - + -template = { - "swagger": "2.0", - "info": { @@ -179,39 +178,39 @@ index 5c1783a..2a97447 100644 + "swagger_ui": True, + "specs_route": "/", + } - + -swagger = Swagger(app, sanitizer=NO_SANITIZER, template=template, config=swagger_config) + swagger = Swagger(app, sanitizer=NO_SANITIZER, template=template, config=swagger_config) - + # Set up Bugsnag exception tracking, if desired. To use Bugsnag, install the # Bugsnag Python client with the command "pip install bugsnag", and set the -@@ -242,8 +247,12 @@ def set_cors_headers(response): +@@ -243,8 +247,12 @@ def set_cors_headers(response): # Routes # ------ - + +if Swagger: + staticroute = "/legacy" +else: + staticroute = "/" - + -@app.route("/legacy") +@app.route(staticroute) def view_landing_page(): """Generates Landing Page in legacy layout.""" return render_template("index.html") diff --git a/pyproject.toml b/pyproject.toml -index 73f3f41..5b255bc 100644 +index 9454e56..d63f994 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,6 @@ dependencies = [ - "Flask", + "flask >= 2.2.4", "brotlicffi", "decorator", - "flasgger", 'greenlet < 3.0; python_version<"3.12"', 'greenlet >= 3.0.0a1; python_version>="3.12.0rc0"', 'importlib-metadata; python_version<"3.8"', -@@ -45,6 +44,7 @@ dependencies = [ +@@ -44,6 +43,7 @@ dependencies = [ [project.optional-dependencies] test = ["pytest", "tox"] mainapp = [ @@ -219,6 +218,6 @@ index 73f3f41..5b255bc 100644 "gunicorn", "gevent", ] --- +-- 2.41.0 diff --git a/Add-fallback-for-Werkzeug-3.patch b/Add-fallback-for-Werkzeug-3.patch new file mode 100644 index 0000000..20e8676 --- /dev/null +++ b/Add-fallback-for-Werkzeug-3.patch @@ -0,0 +1,142 @@ +From 61dc6c89a631d5b09b1e008fe50d831dbf9d723e Mon Sep 17 00:00:00 2001 +From: Nate Prewitt +Date: Fri, 6 Oct 2023 13:30:17 -0700 +Subject: [PATCH 1/2] Add fallback for Werkzeug 3.0.0 + +--- + httpbin/core.py | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/httpbin/core.py b/httpbin/core.py +index 5c1783a1..748575d8 100644 +--- a/httpbin/core.py ++++ b/httpbin/core.py +@@ -32,7 +32,13 @@ + from werkzeug.wrappers import Response + except ImportError: # werkzeug < 2.1 + from werkzeug.wrappers import BaseResponse as Response +-from werkzeug.http import parse_authorization_header ++ ++try: ++ from werkzeug.http import parse_authorization_header ++except ImportError: # werkzeug < 2.3 ++ from werkzeug.datastructures import Authorization ++ parse_authorization_header = Authorization.from_header ++ + from flasgger import Swagger, NO_SANITIZER + + from . import filters + +From 3ac10b8d89fddb06529b37053dc3f0b3affc06b3 Mon Sep 17 00:00:00 2001 +From: Nate Prewitt +Date: Fri, 6 Oct 2023 13:36:43 -0700 +Subject: [PATCH 2/2] Fix Flask requirements and werkzeug imports + +--- + httpbin/core.py | 12 ++---------- + httpbin/helpers.py | 21 ++++++++++++++++----- + pyproject.toml | 3 +-- + 3 files changed, 19 insertions(+), 17 deletions(-) + +diff --git a/httpbin/core.py b/httpbin/core.py +index 748575d8..a82c1b88 100644 +--- a/httpbin/core.py ++++ b/httpbin/core.py +@@ -33,12 +33,6 @@ + except ImportError: # werkzeug < 2.1 + from werkzeug.wrappers import BaseResponse as Response + +-try: +- from werkzeug.http import parse_authorization_header +-except ImportError: # werkzeug < 2.3 +- from werkzeug.datastructures import Authorization +- parse_authorization_header = Authorization.from_header +- + from flasgger import Swagger, NO_SANITIZER + + from . import filters +@@ -53,6 +47,7 @@ + H, + ROBOT_TXT, + ANGRY_ASCII, ++ parse_authorization_header, + parse_multi_value_header, + next_stale_after_value, + digest_challenge_response, +@@ -642,16 +637,13 @@ def redirect_to(): + args_dict = request.args.items() + args = CaseInsensitiveDict(args_dict) + +- # We need to build the response manually and convert to UTF-8 to prevent +- # werkzeug from "fixing" the URL. This endpoint should set the Location +- # header to the exact string supplied. + response = app.make_response("") + response.status_code = 302 + if "status_code" in args: + status_code = int(args["status_code"]) + if status_code >= 300 and status_code < 400: + response.status_code = status_code +- response.headers["Location"] = args["url"].encode("utf-8") ++ response.headers["Location"] = args["url"] + + return response + +diff --git a/httpbin/helpers.py b/httpbin/helpers.py +index b29e1835..836c8026 100644 +--- a/httpbin/helpers.py ++++ b/httpbin/helpers.py +@@ -13,8 +13,14 @@ + import time + import os + from hashlib import md5, sha256, sha512 +-from werkzeug.http import parse_authorization_header + from werkzeug.datastructures import WWWAuthenticate ++from werkzeug.http import dump_header ++ ++try: ++ from werkzeug.http import parse_authorization_header ++except ImportError: # werkzeug < 2.3 ++ from werkzeug.datastructures import Authorization ++ parse_authorization_header = Authorization.from_header + + from flask import request, make_response + from six.moves.urllib.parse import urlparse, urlunparse +@@ -466,9 +472,14 @@ def digest_challenge_response(app, qop, algorithm, stale = False): + ]), algorithm) + opaque = H(os.urandom(10), algorithm) + +- auth = WWWAuthenticate("digest") +- auth.set_digest('me@kennethreitz.com', nonce, opaque=opaque, +- qop=('auth', 'auth-int') if qop is None else (qop,), algorithm=algorithm) +- auth.stale = stale ++ values = { ++ 'realm': 'me@kennethreitz.com', ++ 'nonce': nonce, ++ 'opaque': opaque, ++ 'qop': dump_header(('auth', 'auth-int') if qop is None else (qop,)), ++ 'algorithm': algorithm, ++ 'stale': stale, ++ } ++ auth = WWWAuthenticate("digest", values=values) + response.headers['WWW-Authenticate'] = auth.to_header() + return response +diff --git a/pyproject.toml b/pyproject.toml +index 020457ec..9454e569 100644 +--- a/pyproject.toml ++++ b/pyproject.toml +@@ -31,14 +31,13 @@ classifiers = [ + "Programming Language :: Python :: 3.12", + ] + dependencies = [ +- "Flask", ++ "flask >= 2.2.4", + "brotlicffi", + "decorator", + "flasgger", + 'greenlet < 3.0; python_version<"3.12"', + 'greenlet >= 3.0.0a1; python_version>="3.12.0rc0"', + 'importlib-metadata; python_version<"3.8"', +- "werkzeug >= 0.14.1", + "six", + ] + diff --git a/python-httpbin.spec b/python-httpbin.spec index 6150465..1fff2aa 100644 --- a/python-httpbin.spec +++ b/python-httpbin.spec @@ -18,6 +18,9 @@ Summary: HTTP Request & Response Service, written in Python + Flask License: MIT URL: https://github.com/psf/httpbin Source: https://files.pythonhosted.org/packages/source/h/%{modname}/%{modname}-%{version}.tar.gz +# https://github.com/psf/httpbin/pull/29 +# Adds support for Flask/Werzeug >= 3.0 +Patch: Add-fallback-for-Werkzeug-3.patch # https://github.com/psf/httpbin/issues/26 # https://github.com/psf/httpbin/pull/32 # Make the dependency on flasgger optional - it has a heavy dep chain