Merge pull request #79 from rochacon/cors

Adding CORS support for all requests
This commit is contained in:
Kenneth Reitz
2013-07-10 15:01:56 -07:00
4 changed files with 75 additions and 2 deletions
+30
View File
@@ -23,6 +23,7 @@ Freely hosted in [HTTP](http://httpbin.org) &
- [`/relative-redirect/:n`](http://httpbin.org/relative-redirect/6) 302 Relative redirects *n* times.
- [`/cookies`](http://httpbin.org/cookies) Returns cookie data.
- [`/cookies/set?name=value`](http://httpbin.org/cookies/set?k1=v1&k2=v2) Sets one or more simple cookies.
- [`/cookies/delete?name`](http://httpbin.org/cookies/delete?k1&k2) Deletes one or more simple cookies.
- [`/basic-auth/:user/:passwd`](http://httpbin.org/basic-auth/user/passwd) Challenges HTTPBasic Auth.
- [`/hidden-basic-auth/:user/:passwd`](http://httpbin.org/hidden-basic-auth/user/passwd) 404'd BasicAuth.
- [`/digest-auth/:qop/:user/:passwd`](http://httpbin.org/digest-auth/auth/user/passwd) Challenges HTTP Digest Auth.
@@ -82,6 +83,35 @@ All endpoint responses are JSON-encoded.
Content-Length: 135
### $ curl https://httpbin.org/get?show_env=1
{
"headers": {
"Content-Length": "",
"Accept-Language": "en-US,en;q=0.8",
"Accept-Encoding": "gzip,deflate,sdch",
"X-Forwarded-Port": "443",
"X-Forwarded-For": "109.60.101.240",
"X-Heroku-Dynos-In-Use": "1",
"Host": "httpbin.org",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"User-Agent": "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.83 Safari/535.11",
"X-Request-Start": "1350053933441",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.3",
"Connection": "keep-alive",
"X-Forwarded-Proto": "https",
"Cookie": "_gauges_unique_day=1; _gauges_unique_month=1; _gauges_unique_year=1; _gauges_unique=1; _gauges_unique_hour=1",
"X-Heroku-Queue-Depth": "0",
"X-Heroku-Queue-Wait-Time": "11",
"Content-Type": ""
},
"args": {
"show_env": "1"
},
"origin": "109.60.101.240",
"url": "http://httpbin.org/get?show_env=1"
}
## AUTHOR
A [Kenneth Reitz](http://kennethreitz.com/pages/open-projects.html)
+26
View File
@@ -46,6 +46,20 @@ app = Flask(__name__)
sentry = Sentry(app)
# -----------
# Middlewares
# -----------
@app.after_request
def set_cors_headers(response):
response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
if request.method == 'OPTIONS':
response.headers['Access-Control-Allow-Credentials'] = 'true'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, PATCH, OPTIONS'
response.headers['Access-Control-Max-Age'] = '3600' # 1 hour cache
return response
# ------
# Routes
# ------
@@ -293,6 +307,18 @@ def set_cookies():
return r
@app.route('/cookies/delete')
def delete_cookies():
"""Deletes cookie(s) as provided by the query string and redirects to cookie list."""
cookies = dict(request.args.items())
r = app.make_response(redirect('/cookies'))
for key, value in cookies.items():
r.delete_cookie(key=key)
return r
@app.route('/basic-auth/<user>/<passwd>')
def basic_auth(user='user', passwd='passwd'):
"""Prompts the user for authorization using HTTP Basic Auth."""
+1
View File
@@ -24,6 +24,7 @@
<li><a href="/relative-redirect/6"><code>/relative-redirect/:n</code></a> 302 Relative redirects <em>n</em> times.</li>
<li><a href="/cookies" data-bare-link="true"><code>/cookies</code></a> Returns cookie data.</li>
<li><a href="/cookies/set?k1=v1&amp;k2=v2"><code>/cookies/set?name=value</code></a> Sets one or more simple cookies.</li>
<li><a href="/cookies/delete?k1&amp;k2"><code>/cookies/delete?name</code></a> Deletes one or more simple cookies.</li>
<li><a href="/basic-auth/user/passwd"><code>/basic-auth/:user/:passwd</code></a> Challenges HTTPBasic Auth.</li>
<li><a href="/hidden-basic-auth/user/passwd"><code>/hidden-basic-auth/:user/:passwd</code></a> 404'd BasicAuth.</li>
<li><a href="/digest-auth/auth/user/passwd"><code>/digest-auth/:qop/:user/:passwd</code></a> Challenges HTTP Digest Auth.</li>
+18 -2
View File
@@ -1,9 +1,9 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import base64
import unittest
import httpbin
import unittest
import base64
def _string_to_base64(string):
@@ -41,6 +41,22 @@ class HttpbinTestCase(unittest.TestCase):
response = self.app.post('/post', data={"file": f})
self.assertEquals(response.status_code, 200)
def test_set_cors_headers_after_request(self):
response = self.app.get('/get')
self.assertEquals(response.headers.get('Access-Control-Allow-Origin'), '*')
def test_set_cors_headers_after_request_with_request_origin(self):
response = self.app.get('/get', headers={'Origin': 'origin'})
self.assertEquals(response.headers.get('Access-Control-Allow-Origin'), 'origin')
def test_set_cors_headers_with_options_verb(self):
response = self.app.open('/get', method='OPTIONS')
self.assertEquals(response.headers.get('Access-Control-Allow-Origin'), '*')
self.assertEquals(response.headers.get('Access-Control-Allow-Credentials'), 'true')
self.assertEquals(response.headers.get('Access-Control-Allow-Methods'), 'GET, POST, PUT, DELETE, PATCH, OPTIONS')
self.assertEquals(response.headers.get('Access-Control-Max-Age'), '3600')
self.assertNotIn('Access-Control-Allow-Headers', response.headers) # FIXME should we add any extra headers?
if __name__ == '__main__':
unittest.main()