Merge lp:~stevenk/launchpad/handle-invalid-unicode-in-query-string into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: William Grant
Approved revision: no longer in the source branch.
Merged at revision: 16461
Proposed branch: lp:~stevenk/launchpad/handle-invalid-unicode-in-query-string
Merge into: lp:launchpad
Diff against target: 77 lines (+23/-4)
2 files modified
lib/lp/services/webapp/servers.py (+10/-1)
lib/lp/services/webapp/tests/test_servers.py (+13/-3)
To merge this branch: bzr merge lp:~stevenk/launchpad/handle-invalid-unicode-in-query-string
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+146029@code.launchpad.net

Commit message

If we fail to decode the query string parameters, forcibly decode it to utf-8 with replacements.

Description of the change

If BrowserRequest._decode() fails to decode a string using the users charsets, it will leave it as a string. Which means that an invalid utf-8 bare string can be tossed into a TextWidget, which expects unicode, and blows up with a OOPS when it attempts to decode it.

Now, if we get back a string from BrowserRequest._decode(), we will forcibly decode it to utf-8 with replacements.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/services/webapp/servers.py'
2--- lib/lp/services/webapp/servers.py 2013-01-07 02:40:55 +0000
3+++ lib/lp/services/webapp/servers.py 2013-02-01 02:59:23 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
6+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 """Definition of the internet servers that Launchpad uses."""
10@@ -657,6 +657,15 @@
11 """As per zope.publisher.browser.BrowserRequest._createResponse"""
12 return LaunchpadBrowserResponse()
13
14+ def _decode(self, text):
15+ text = super(LaunchpadBrowserRequest, self)._decode(text)
16+ if isinstance(text, str):
17+ # BrowserRequest._decode failed to do so with the user-specified
18+ # charsets, so decode as UTF-8 with replacements, since we always
19+ # want unicode.
20+ text = unicode(text, 'utf-8', 'replace')
21+ return text
22+
23 @cachedproperty
24 def form_ng(self):
25 """See ILaunchpadBrowserApplicationRequest."""
26
27=== modified file 'lib/lp/services/webapp/tests/test_servers.py'
28--- lib/lp/services/webapp/tests/test_servers.py 2013-01-07 02:40:55 +0000
29+++ lib/lp/services/webapp/tests/test_servers.py 2013-02-01 02:59:23 +0000
30@@ -1,4 +1,4 @@
31-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
32+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
33 # GNU Affero General Public License version 3 (see the file LICENSE).
34
35 __metaclass__ = type
36@@ -50,6 +50,7 @@
37 EventRecorder,
38 TestCase,
39 )
40+from lp.testing.layers import FunctionalLayer
41
42
43 class SetInWSGIEnvironmentTestCase(TestCase):
44@@ -230,8 +231,7 @@
45
46 for method in denied_methods:
47 env = self.wsgi_env(self.non_api_path, method)
48- self.assert_(self.factory.canHandle(env),
49- "Sanity check")
50+ self.assert_(self.factory.canHandle(env), "Sanity check")
51 # Returns a tuple of (request_factory, publication_factory).
52 rfactory, pfactory = self.factory.checkRequest(env)
53 self.assert_(rfactory is not None,
54@@ -352,6 +352,8 @@
55 class TestBasicLaunchpadRequest(TestCase):
56 """Tests for the base request class"""
57
58+ layer = FunctionalLayer
59+
60 def test_baserequest_response_should_vary(self):
61 """Test that our base response has a proper vary header."""
62 request = LaunchpadBrowserRequest(StringIO.StringIO(''), {})
63@@ -387,6 +389,14 @@
64 request = LaunchpadBrowserRequest(StringIO.StringIO(''), env)
65 self.assertEquals(u'fnord/trunk\ufffd', request.getHeader('PATH_INFO'))
66
67+ def test_request_with_invalid_query_string_recovers(self):
68+ # When the query string has invalid utf-8, it is decoded with
69+ # replacement.
70+ env = {'QUERY_STRING': 'field.title=subproc\xe9s '}
71+ request = LaunchpadBrowserRequest(StringIO.StringIO(''), env)
72+ self.assertEquals(
73+ [u'subproc\ufffds '], request.query_string_params['field.title'])
74+
75
76 class TestFeedsBrowserRequest(TestCase):
77 """Tests for `FeedsBrowserRequest`."""