merge with stable
authorAugie Fackler <augie@google.com>
Fri, 26 Jun 2020 11:20:58 -0400
changeset 45005 05277278f177
parent 45002 d2227d4c9e6b (current diff)
parent 45004 2632c1ed8f34 (diff)
child 45006 36178b5c9aeb
merge with stable
--- a/mercurial/hgweb/request.py	Fri Jun 26 09:37:34 2020 +0200
+++ b/mercurial/hgweb/request.py	Fri Jun 26 11:20:58 2020 -0400
@@ -12,6 +12,7 @@
 
 from ..thirdparty import attr
 from .. import (
+    encoding,
     error,
     pycompat,
     util,
@@ -162,11 +163,19 @@
     # strings on Python 3 must be between \00000-\000FF. We deal with bytes
     # in Mercurial, so mass convert string keys and values to bytes.
     if pycompat.ispy3:
-        env = {k.encode('latin-1'): v for k, v in pycompat.iteritems(env)}
-        env = {
-            k: v.encode('latin-1') if isinstance(v, str) else v
-            for k, v in pycompat.iteritems(env)
-        }
+
+        def tobytes(s):
+            if not isinstance(s, str):
+                return s
+            if pycompat.iswindows:
+                # This is what mercurial.encoding does for os.environ on
+                # Windows.
+                return encoding.strtolocal(s)
+            else:
+                # This is what is documented to be used for os.environ on Unix.
+                return pycompat.fsencode(s)
+
+        env = {tobytes(k): tobytes(v) for k, v in pycompat.iteritems(env)}
 
     # Some hosting solutions are emulating hgwebdir, and dispatching directly
     # to an hgweb instance using this environment variable.  This was always
--- a/tests/test-wsgirequest.py	Fri Jun 26 09:37:34 2020 +0200
+++ b/tests/test-wsgirequest.py	Fri Jun 26 11:20:58 2020 -0400
@@ -3,7 +3,7 @@
 import unittest
 
 from mercurial.hgweb import request as requestmod
-from mercurial import error
+from mercurial import error, pycompat
 
 DEFAULT_ENV = {
     'REQUEST_METHOD': 'GET',
@@ -432,6 +432,18 @@
         self.assertEqual(r.dispatchpath, b'path1/path2')
         self.assertEqual(r.reponame, b'repo')
 
+    def testenvencoding(self):
+        if pycompat.iswindows:
+            # On Windows, we can't generally know which non-ASCII characters
+            # are supported.
+            r = parse(DEFAULT_ENV, extra={'foo': 'bar'})
+            self.assertEqual(r.rawenv[b'foo'], b'bar')
+        else:
+            # Unix is byte-based. Therefore we test all possible bytes.
+            b = b''.join(pycompat.bytechr(i) for i in range(256))
+            r = parse(DEFAULT_ENV, extra={'foo': pycompat.fsdecode(b)})
+            self.assertEqual(r.rawenv[b'foo'], b)
+
 
 if __name__ == '__main__':
     import silenttestrunner