[Checkins] SVN: zope.publisher/branches/3.4/ Backport r101467 from trunk.

Adam Groszer agroszer at gmail.com
Tue Apr 6 03:23:32 EDT 2010


Log message for revision 110559:
  Backport r101467 from trunk.
  
  Fix for https://bugs.launchpad.net/zope3/+bug/98337
    
  Previously, when the Accept-Charset specified a charset that could not encode
  the result, a system error appeared, now we fall back to UTF-8, as per
  RFC 2616 section 10.4.7.
  

Changed:
  U   zope.publisher/branches/3.4/CHANGES.txt
  U   zope.publisher/branches/3.4/src/zope/publisher/http.py
  U   zope.publisher/branches/3.4/src/zope/publisher/tests/test_http.py

-=-
Modified: zope.publisher/branches/3.4/CHANGES.txt
===================================================================
--- zope.publisher/branches/3.4/CHANGES.txt	2010-04-06 07:21:36 UTC (rev 110558)
+++ zope.publisher/branches/3.4/CHANGES.txt	2010-04-06 07:23:32 UTC (rev 110559)
@@ -6,7 +6,14 @@
 
 * Removed ``finally``-clause from test to keep Python2.4 happy.
 
+* Backport r101467 from trunk.
 
+  Fix for https://bugs.launchpad.net/zope3/+bug/98337
+
+  Previously, when the Accept-Charset specified a charset that could not encode
+  the result, a system error appeared, now we fall back to UTF-8, as per
+  RFC 2616 section 10.4.7.
+
 3.4.9 (2009-07-13)
 ------------------
 
@@ -95,9 +102,9 @@
 3.4.0b1 (2007-07-05)
 --------------------
 
-* Fix caching issue. The input stream never got cached in a temp file 
-  because of a wrong content-length header lookup. Added CONTENT_LENGTH 
-  header check in addition to the previous used HTTP_CONTENT_LENGTH. The 
+* Fix caching issue. The input stream never got cached in a temp file
+  because of a wrong content-length header lookup. Added CONTENT_LENGTH
+  header check in addition to the previous used HTTP_CONTENT_LENGTH. The
   HTTP\_ prefix is sometimes added by some CGI proxies, but CONTENT_LENGTH
   is the right header info for the size.
 

Modified: zope.publisher/branches/3.4/src/zope/publisher/http.py
===================================================================
--- zope.publisher/branches/3.4/src/zope/publisher/http.py	2010-04-06 07:21:36 UTC (rev 110558)
+++ zope.publisher/branches/3.4/src/zope/publisher/http.py	2010-04-06 07:23:32 UTC (rev 110559)
@@ -814,11 +814,20 @@
 
             if 'charset' in params:
                 encoding = params['charset']
-            else:
-                content_type += ';charset=%s' %encoding
 
-            body = body.encode(encoding)
+            try:
+                body = body.encode(encoding)
+            except UnicodeEncodeError:
+                # RFC 2616 section 10.4.7 allows us to return an
+                # unacceptable encoding instead of 406 Not Acceptable
+                # response.
+                encoding = 'utf-8'
+                body = body.encode(encoding)
 
+            params['charset'] = encoding
+            content_type = "%s/%s;" % (major, minor)
+            content_type += ";".join(k + "=" + v for k, v in params.items())
+
         if content_type:
             headers = [('content-type', content_type),
                        ('content-length', str(len(body)))]
@@ -827,7 +836,6 @@
 
         return body, headers
 
-
     def handleException(self, exc_info):
         """
         Calls self.setBody() with an error response.

Modified: zope.publisher/branches/3.4/src/zope/publisher/tests/test_http.py
===================================================================
--- zope.publisher/branches/3.4/src/zope/publisher/tests/test_http.py	2010-04-06 07:21:36 UTC (rev 110558)
+++ zope.publisher/branches/3.4/src/zope/publisher/tests/test_http.py	2010-04-06 07:23:32 UTC (rev 110559)
@@ -24,6 +24,7 @@
 
 import zope.event
 import zope.testing.cleanup
+from zope.component import provideAdapter
 from zope.testing import doctest
 from zope.i18n.interfaces.locales import ILocale
 from zope.interface.verify import verifyObject
@@ -31,7 +32,7 @@
 from zope.interface import implements
 from zope.publisher.interfaces.logginginfo import ILoggingInfo
 from zope.publisher.http import HTTPRequest, HTTPResponse
-from zope.publisher.http import HTTPInputStream, DirectResult
+from zope.publisher.http import HTTPInputStream, DirectResult, HTTPCharsets
 from zope.publisher.publish import publish
 from zope.publisher.base import DefaultPublication
 from zope.publisher.interfaces.http import IHTTPRequest, IHTTPResponse
@@ -297,7 +298,6 @@
         eq = self.assertEqual
         unless = self.failUnless
 
-        from zope.component import provideAdapter
         from zope.publisher.browser import BrowserLanguages
         from zope.publisher.interfaces.http import IHTTPRequest
         from zope.i18n.interfaces import IUserPreferredLanguages
@@ -565,7 +565,24 @@
         request = self._createRequest({'PATH_INFO': '/test '})
         self.assertEqual(['test '], request.getTraversalStack())
 
+    def test_unacceptable_charset(self):
+        # Regression test for https://bugs.launchpad.net/zope3/+bug/98337
+        request = self._createRequest({'HTTP_ACCEPT_CHARSET': 'ISO-8859-1'})
+        result = u"Latin a with ogonek\u0105 Cyrillic ya \u044f"
+        provideAdapter(HTTPCharsets)
+        request.response.setHeader('Content-Type', 'text/plain')
 
+        # Instead of failing with HTTP code 406 we ignore the
+        # Accept-Charset header and return a response in UTF-8.
+        request.response.setResult(result)
+
+        body = request.response.consumeBody()
+        self.assertEquals(request.response.getStatus(), 200)
+        self.assertEquals(request.response.getHeader('Content-Type'),
+                          'text/plain;charset=utf-8')
+        self.assertEquals(body,
+                          'Latin a with ogonek\xc4\x85 Cyrillic ya \xd1\x8f')
+
 class ConcreteHTTPTests(HTTPTests):
     """Tests that we don't have to worry about subclasses inheriting and
     breaking.



More information about the checkins mailing list