From 0826ed75d9ed282a53d8a6df0aaebd05e8cda208 Mon Sep 17 00:00:00 2001 From: Piotr Dobrogost Date: Sun, 26 Feb 2012 19:48:17 +0100 Subject: [PATCH 1/9] this can raise IndexError but not KeyError --- run_httpbin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run_httpbin.py b/run_httpbin.py index 3d7641b..1b44eea 100755 --- a/run_httpbin.py +++ b/run_httpbin.py @@ -8,7 +8,7 @@ from httpbin import app try: port = int(sys.argv[1]) -except (KeyError, ValueError): +except (IndexError, ValueError): port = 5000 print 'Starting httpbin on port {0}'.format(port) From da07bb6675bede549253c2ce569374b6bef0843c Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Sun, 26 Feb 2012 21:59:34 -0800 Subject: [PATCH 2/9] Add POST PUT and DELETE to the status endpoint --- httpbin/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpbin/core.py b/httpbin/core.py index d9a6c9a..9970401 100644 --- a/httpbin/core.py +++ b/httpbin/core.py @@ -167,7 +167,7 @@ def stream_n_messages(n): @app.route('/status/') -def view_status_code(codes): +def view_status_code(codes, methods=("GET", "POST", "PUT", "DELETE")): """Return status code or random status code if more than one are given""" if not ',' in codes: From 16f7ab8c7060025bbbf8a63e76ae5d3da897c654 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Sun, 26 Feb 2012 22:23:02 -0800 Subject: [PATCH 3/9] Remove very broken JSON stuff --- httpbin/helpers.py | 5 +++-- run_httpbin.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/httpbin/helpers.py b/httpbin/helpers.py index fc899e7..3b73c8f 100644 --- a/httpbin/helpers.py +++ b/httpbin/helpers.py @@ -7,6 +7,7 @@ httpbin.helpers This module provides helper functions for httpbin. """ +import json from hashlib import md5 from werkzeug.http import parse_authorization_header @@ -95,9 +96,9 @@ def get_dict(*keys, **extras): form = nonflat_dict try: - json = json.loads(request.data) + json_input = json.loads(request.data) except ValueError: - json = None + json_input = None d = dict( diff --git a/run_httpbin.py b/run_httpbin.py index 1b44eea..1f604b3 100755 --- a/run_httpbin.py +++ b/run_httpbin.py @@ -12,5 +12,6 @@ except (IndexError, ValueError): port = 5000 print 'Starting httpbin on port {0}'.format(port) +app.debug = True http_server = WSGIServer(('', port), app) -http_server.serve_forever() \ No newline at end of file +http_server.serve_forever() From 38d04e0bb9544a1516fc49c08a7c28b1f68a304a Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Sun, 26 Feb 2012 22:35:36 -0800 Subject: [PATCH 4/9] Show proper scheme in urls --- httpbin/helpers.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/httpbin/helpers.py b/httpbin/helpers.py index 3b73c8f..86a3676 100644 --- a/httpbin/helpers.py +++ b/httpbin/helpers.py @@ -6,7 +6,6 @@ httpbin.helpers This module provides helper functions for httpbin. """ - import json from hashlib import md5 from werkzeug.http import parse_authorization_header @@ -73,6 +72,11 @@ def get_headers(hide_env=True): return CaseInsensitiveDict(headers.items()) +def get_url(): + scheme = request.headers.get("X-Forwarded-Proto", "http") + return request.url.replace("http", scheme) + + def get_dict(*keys, **extras): """Returns request dict of given keys.""" @@ -102,7 +106,7 @@ def get_dict(*keys, **extras): d = dict( - url=request.url, + url=get_url(), args=request.args, form=form, data=data, From 5eb1c9ad0d1cf18b676ffa270d5b390c15a5d247 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Sun, 26 Feb 2012 22:38:17 -0800 Subject: [PATCH 5/9] Remove app.debug --- run_httpbin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/run_httpbin.py b/run_httpbin.py index 1f604b3..282006d 100755 --- a/run_httpbin.py +++ b/run_httpbin.py @@ -12,6 +12,5 @@ except (IndexError, ValueError): port = 5000 print 'Starting httpbin on port {0}'.format(port) -app.debug = True http_server = WSGIServer(('', port), app) http_server.serve_forever() From 7de330b2fc7d62059ae7d3a1749b45e7b471cf56 Mon Sep 17 00:00:00 2001 From: Chris Dary Date: Tue, 28 Feb 2012 10:02:10 -0500 Subject: [PATCH 6/9] Add redirect_to functionality. --- httpbin/core.py | 7 +++++++ httpbin/templates/httpbin.1.html | 1 + 2 files changed, 8 insertions(+) diff --git a/httpbin/core.py b/httpbin/core.py index 9970401..0d9564e 100644 --- a/httpbin/core.py +++ b/httpbin/core.py @@ -148,6 +148,13 @@ def relative_redirect_n_times(n): response.headers['Location'] = '/relative-redirect/{0}'.format(n - 1) return response +@app.route('/redirect-to/') +def redirect_to(url): + """ Redirect to the given URL. """ + response = app.make_response('') + response.status_code = 302 + response.headers['Location'] = url + return response @app.route('/stream/') def stream_n_messages(n): diff --git a/httpbin/templates/httpbin.1.html b/httpbin/templates/httpbin.1.html index 857948f..5c22c5f 100644 --- a/httpbin/templates/httpbin.1.html +++ b/httpbin/templates/httpbin.1.html @@ -19,6 +19,7 @@
  • /response-headers?key=val Returns given response headers.
  • /redirect/:n 302 Redirects n times.
  • /relative-redirect/:n 302 Relative redirects n times.
  • +
  • /redirect-to/:url 302 Redirects to the given URL.
  • /cookies Returns cookie data.
  • /cookies/set/:name/:value Sets a simple cookie.
  • /basic-auth/:user/:passwd Challenges HTTPBasic Auth.
  • From 9e277be559f6fd0d144ee6591ddb2a866bd0eb68 Mon Sep 17 00:00:00 2001 From: Chris Dary Date: Tue, 28 Feb 2012 10:02:27 -0500 Subject: [PATCH 7/9] Some spelling fixes. --- httpbin/core.py | 2 +- httpbin/helpers.py | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/httpbin/core.py b/httpbin/core.py index 0d9564e..032083a 100644 --- a/httpbin/core.py +++ b/httpbin/core.py @@ -106,7 +106,7 @@ def view_patch(): @app.route('/delete', methods=('DELETE',)) def view_delete(): - """Returns DETLETE Data.""" + """Returns DELETE Data.""" return jsonify(get_dict('url', 'args', 'data', 'origin', 'headers', 'json')) diff --git a/httpbin/helpers.py b/httpbin/helpers.py index 86a3676..11b29e4 100644 --- a/httpbin/helpers.py +++ b/httpbin/helpers.py @@ -188,7 +188,7 @@ def HA1(realm, username, password): password)) -def HA2(credentails, request): +def HA2(credentials, request): """Create HA2 md5 hash If the qop directive's value is "auth" or is unspecified, then HA2: @@ -196,9 +196,9 @@ def HA2(credentails, request): If the qop directive's value is "auth-int" , then HA2 is HA2 = md5(A2) = MD5(method:digestURI:MD5(entityBody)) """ - if credentails.get("qop") == "auth" or credentails.get('qop') is None: + if credentials.get("qop") == "auth" or credentials.get('qop') is None: return H("%s:%s" % (request['method'], request['uri'])) - elif credentails.get("qop") == "auth-int": + elif credentials.get("qop") == "auth-int": for k in 'method', 'uri', 'body': if k not in request: raise ValueError("%s required" % k) @@ -208,7 +208,7 @@ def HA2(credentails, request): raise ValueError -def response(credentails, password, request): +def response(credentials, password, request): """Compile digest auth response If the qop directive's value is "auth" or "auth-int" , then compute the response as follows: @@ -217,24 +217,24 @@ def response(credentails, password, request): RESPONSE = MD5(HA1:nonce:HA2) Arguments: - - `credentails`: credentails dict + - `credentials`: credentials dict - `password`: request user password - `request`: request dict """ response = None - HA1_value = HA1(credentails.get('realm'), credentails.get('username'), password) - HA2_value = HA2(credentails, request) - if credentails.get('qop') is None: - response = H(":".join([HA1_value, credentails.get('nonce'), HA2_value])) - elif credentails.get('qop') == 'auth' or credentails.get('qop') == 'auth-int': + HA1_value = HA1(credentials.get('realm'), credentials.get('username'), password) + HA2_value = HA2(credentials, request) + if credentials.get('qop') is None: + response = H(":".join([HA1_value, credentials.get('nonce'), HA2_value])) + elif credentials.get('qop') == 'auth' or credentials.get('qop') == 'auth-int': for k in 'nonce', 'nc', 'cnonce', 'qop': - if k not in credentails: + if k not in credentials: raise ValueError("%s required for response H" % k) response = H(":".join([HA1_value, - credentails.get('nonce'), - credentails.get('nc'), - credentails.get('cnonce'), - credentails.get('qop'), + credentials.get('nonce'), + credentials.get('nc'), + credentials.get('cnonce'), + credentials.get('qop'), HA2_value])) else: raise ValueError("qop value are wrong") @@ -246,12 +246,12 @@ def check_digest_auth(user, passwd): """Check user authentication using HTTP Digest auth""" if request.headers.get('Authorization'): - credentails = parse_authorization_header(request.headers.get('Authorization')) - if not credentails: + credentials = parse_authorization_header(request.headers.get('Authorization')) + if not credentials: return - response_hash = response(credentails, passwd, dict(uri=request.path, + response_hash = response(credentials, passwd, dict(uri=request.path, body=request.data, method=request.method)) - if credentails['response'] == response_hash: + if credentials['response'] == response_hash: return True return False From 295dc90db6f52c8581d8a656ec3928a8f184b1a2 Mon Sep 17 00:00:00 2001 From: Chris Dary Date: Tue, 28 Feb 2012 10:43:08 -0500 Subject: [PATCH 8/9] Redirect-to now uses a query param instead. --- httpbin/core.py | 6 ++++-- httpbin/templates/httpbin.1.html | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/httpbin/core.py b/httpbin/core.py index 032083a..b745267 100644 --- a/httpbin/core.py +++ b/httpbin/core.py @@ -148,9 +148,11 @@ def relative_redirect_n_times(n): response.headers['Location'] = '/relative-redirect/{0}'.format(n - 1) return response -@app.route('/redirect-to/') -def redirect_to(url): + +@app.route('/redirect-to') +def redirect_to(): """ Redirect to the given URL. """ + url = request.args.get('url', '/') response = app.make_response('') response.status_code = 302 response.headers['Location'] = url diff --git a/httpbin/templates/httpbin.1.html b/httpbin/templates/httpbin.1.html index 5c22c5f..8c13f53 100644 --- a/httpbin/templates/httpbin.1.html +++ b/httpbin/templates/httpbin.1.html @@ -19,7 +19,7 @@
  • /response-headers?key=val Returns given response headers.
  • /redirect/:n 302 Redirects n times.
  • /relative-redirect/:n 302 Relative redirects n times.
  • -
  • /redirect-to/:url 302 Redirects to the given URL.
  • +
  • /redirect-to?url=some-url 302 Redirects to the given URL.
  • /cookies Returns cookie data.
  • /cookies/set/:name/:value Sets a simple cookie.
  • /basic-auth/:user/:passwd Challenges HTTPBasic Auth.
  • From c4895849cc43e4592621a7269e79d3e4aeb538b2 Mon Sep 17 00:00:00 2001 From: Chris Dary Date: Tue, 28 Feb 2012 11:31:58 -0500 Subject: [PATCH 9/9] UTF8 Encoding --- httpbin/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpbin/core.py b/httpbin/core.py index b745267..0985f9b 100644 --- a/httpbin/core.py +++ b/httpbin/core.py @@ -155,7 +155,7 @@ def redirect_to(): url = request.args.get('url', '/') response = app.make_response('') response.status_code = 302 - response.headers['Location'] = url + response.headers['Location'] = url.encode('utf-8') return response @app.route('/stream/')