Merge lp:~pedronis/u1db/cors-middleware into lp:u1db

Proposed by Samuele Pedroni
Status: Merged
Approved by: Samuele Pedroni
Approved revision: 426
Merged at revision: 426
Proposed branch: lp:~pedronis/u1db/cors-middleware
Merge into: lp:u1db
Diff against target: 153 lines (+114/-2)
3 files modified
u1db/remote/cors_middleware.py (+42/-0)
u1db/tests/test_cors_middleware.py (+66/-0)
u1db/tests/test_remote_sync_target.py (+6/-2)
To merge this branch: bzr merge lp:~pedronis/u1db/cors-middleware
Reviewer Review Type Date Requested Status
Stuart Langridge (community) Approve
Lucio Torre (community) Approve
Review via email: mp+128991@code.launchpad.net

Commit message

add CORS middleware

Description of the change

- CORS middleware
- tweak to allow passing all tests with u1db.js under different origin conditions

testing beyond unit tests/trying:

get lp:~pedronis/u1db/u1db-js-different-origin

run in it:

TEST_BROWSER=firefox PYTHONPATH=../cors-middleware/:. unit2 tests.test_bridged

atm there should be only 1 unrelated failure there

To post a comment you must log in.
Revision history for this message
Samuele Pedroni (pedronis) wrote :

confirmed working against: chromium, safari, and firefox

Revision history for this message
Lucio Torre (lucio.torre) wrote :

code looks sane.

review: Approve
Revision history for this message
Stuart Langridge (sil) wrote :

Serving correct CORS headers, and u1db.js will sync with a u1db-serve which provides these headers.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'u1db/remote/cors_middleware.py'
--- u1db/remote/cors_middleware.py 1970-01-01 00:00:00 +0000
+++ u1db/remote/cors_middleware.py 2012-10-10 16:31:57 +0000
@@ -0,0 +1,42 @@
1# Copyright 2012 Canonical Ltd.
2#
3# This file is part of u1db.
4#
5# u1db is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License version 3
7# as published by the Free Software Foundation.
8#
9# u1db is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with u1db. If not, see <http://www.gnu.org/licenses/>.
16"""U1DB Cross-Origin Resource Sharing WSGI middleware."""
17
18
19class CORSMiddleware(object):
20 """U1DB Cross-Origin Resource Sharing WSGI middleware."""
21
22 def __init__(self, app, accept_cors_connections):
23 self.origins = ' '.join(accept_cors_connections)
24 self.app = app
25
26 def _cors_headers(self):
27 return [('access-control-allow-origin', self.origins),
28 ('access-control-allow-headers',
29 'authorization, content-type'),
30 ('access-control-allow-methods',
31 'GET, POST, PUT, DELETE, OPTIONS')]
32
33 def __call__(self, environ, start_response):
34 def wrap_start_response(status, headers, exc_info=None):
35 headers += self._cors_headers()
36 return start_response(status, headers, exc_info)
37
38 if environ['REQUEST_METHOD'].lower() == 'options':
39 wrap_start_response("200 OK", [('content-type', 'text/plain')])
40 return ['']
41
42 return self.app(environ, wrap_start_response)
043
=== added file 'u1db/tests/test_cors_middleware.py'
--- u1db/tests/test_cors_middleware.py 1970-01-01 00:00:00 +0000
+++ u1db/tests/test_cors_middleware.py 2012-10-10 16:31:57 +0000
@@ -0,0 +1,66 @@
1# Copyright 2012 Canonical Ltd.
2#
3# This file is part of u1db.
4#
5# u1db is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License version 3
7# as published by the Free Software Foundation.
8#
9# u1db is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with u1db. If not, see <http://www.gnu.org/licenses/>.
16
17"""Test CORS wsgi middleware"""
18import paste.fixture
19
20from u1db import tests
21
22from u1db.remote.cors_middleware import CORSMiddleware
23
24
25class TestCORSMiddleware(tests.TestCase):
26
27 def setUp(self):
28 super(TestCORSMiddleware, self).setUp()
29
30 def app(self, accept_cors_connections):
31
32 def base_app(environ, start_response):
33 start_response("200 OK", [("content-type", "application/json")])
34 return ['{}']
35
36 return paste.fixture.TestApp(CORSMiddleware(base_app,
37 accept_cors_connections))
38
39 def _check_cors_headers(self, resp, expect):
40 self.assertEqual(expect, resp.header('access-control-allow-origin'))
41 self.assertEqual("GET, POST, PUT, DELETE, OPTIONS",
42 resp.header('access-control-allow-methods'))
43 self.assertEqual("authorization, content-type",
44 resp.header('access-control-allow-headers'))
45
46 def test_options(self):
47 app = self.app(['*'])
48 resp = app._gen_request('OPTIONS', '/')
49 self.assertEqual(200, resp.status)
50 self._check_cors_headers(resp, '*')
51 self.assertEqual('', resp.body)
52
53 app = self.app(['http://bar.example', 'http://foo.example'])
54 resp = app._gen_request('OPTIONS', '/db1')
55 self.assertEqual(200, resp.status)
56 self._check_cors_headers(resp, 'http://bar.example http://foo.example')
57 self.assertEqual('', resp.body)
58
59 def test_pass_through(self):
60 app = self.app(['*'])
61 resp = app.get('/db0')
62 self.assertEqual(200, resp.status)
63 self._check_cors_headers(resp, '*')
64 self.assertEqual('application/json', resp.header('content-type'))
65 self.assertEqual('{}', resp.body)
66
067
=== modified file 'u1db/tests/test_remote_sync_target.py'
--- u1db/tests/test_remote_sync_target.py 2012-09-25 20:04:08 +0000
+++ u1db/tests/test_remote_sync_target.py 2012-10-10 16:31:57 +0000
@@ -177,9 +177,13 @@
177 self.assertGetDoc(177 self.assertGetDoc(
178 db, 'doc-here', 'replica:1', '{"value": "here"}', False)178 db, 'doc-here', 'replica:1', '{"value": "here"}', False)
179179
180 failure_scenario_exceptions = (Exception, errors.HTTPError)
181
180 def test_sync_exchange_send_failure_and_retry_scenario(self):182 def test_sync_exchange_send_failure_and_retry_scenario(self):
181 self.startServer()183 self.startServer()
182184
185 server_side_exc, client_side_exc = self.failure_scenario_exceptions
186
183 def blackhole_getstderr(inst):187 def blackhole_getstderr(inst):
184 return cStringIO.StringIO()188 return cStringIO.StringIO()
185189
@@ -193,7 +197,7 @@
193 replica_uid=None, replica_gen=None,197 replica_uid=None, replica_gen=None,
194 replica_trans_id=None):198 replica_trans_id=None):
195 if doc.doc_id in trigger_ids:199 if doc.doc_id in trigger_ids:
196 raise Exception200 raise server_side_exc
197 return _put_doc_if_newer(doc, save_conflict=save_conflict,201 return _put_doc_if_newer(doc, save_conflict=save_conflict,
198 replica_uid=replica_uid, replica_gen=replica_gen,202 replica_uid=replica_uid, replica_gen=replica_gen,
199 replica_trans_id=replica_trans_id)203 replica_trans_id=replica_trans_id)
@@ -209,7 +213,7 @@
209 doc2 = self.make_document('doc-here2', 'replica:1',213 doc2 = self.make_document('doc-here2', 'replica:1',
210 '{"value": "here2"}')214 '{"value": "here2"}')
211 self.assertRaises(215 self.assertRaises(
212 errors.HTTPError,216 client_side_exc,
213 remote_target.sync_exchange,217 remote_target.sync_exchange,
214 [(doc1, 10, 'T-sid'), (doc2, 11, 'T-sud')],218 [(doc1, 10, 'T-sid'), (doc2, 11, 'T-sud')],
215 'replica', last_known_generation=0, last_known_trans_id=None,219 'replica', last_known_generation=0, last_known_trans_id=None,

Subscribers

People subscribed via source and target branches