mercurial/hgweb/request.py
changeset 43076 2372284d9457
parent 40545 6107d4549fcc
child 43077 687b865b95ad
--- a/mercurial/hgweb/request.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/hgweb/request.py	Sun Oct 06 09:45:02 2019 -0400
@@ -8,17 +8,16 @@
 
 from __future__ import absolute_import
 
-#import wsgiref.validate
+# import wsgiref.validate
 
-from ..thirdparty import (
-    attr,
-)
+from ..thirdparty import attr
 from .. import (
     error,
     pycompat,
     util,
 )
 
+
 class multidict(object):
     """A dict like object that can store multiple values for a key.
 
@@ -26,6 +25,7 @@
 
     This is inspired by WebOb's class of the same name.
     """
+
     def __init__(self):
         self._items = {}
 
@@ -76,6 +76,7 @@
     def asdictoflists(self):
         return {k: list(v) for k, v in self._items.iteritems()}
 
+
 @attr.s(frozen=True)
 class parsedrequest(object):
     """Represents a parsed WSGI request.
@@ -124,6 +125,7 @@
     # WSGI environment dict, unmodified.
     rawenv = attr.ib()
 
+
 def parserequestfromenv(env, reponame=None, altbaseurl=None, bodyfh=None):
     """Parse URL components from environment variables.
 
@@ -153,7 +155,7 @@
     # We first validate that the incoming object conforms with the WSGI spec.
     # We only want to be dealing with spec-conforming WSGI implementations.
     # TODO enable this once we fix internal violations.
-    #wsgiref.validate.check_environ(env)
+    # wsgiref.validate.check_environ(env)
 
     # PEP-0333 states that environment keys and values are native strings
     # (bytes on Python 2 and str on Python 3). The code points for the Unicode
@@ -161,8 +163,10 @@
     # in Mercurial, so mass convert string keys and values to bytes.
     if pycompat.ispy3:
         env = {k.encode('latin-1'): v for k, v in env.iteritems()}
-        env = {k: v.encode('latin-1') if isinstance(v, str) else v
-               for k, v in env.iteritems()}
+        env = {
+            k: v.encode('latin-1') if isinstance(v, str) else v
+            for k, v in env.iteritems()
+        }
 
     # Some hosting solutions are emulating hgwebdir, and dispatching directly
     # to an hgweb instance using this environment variable.  This was always
@@ -255,16 +259,19 @@
             raise error.ProgrammingError('reponame requires PATH_INFO')
 
         if not env['PATH_INFO'].startswith(repoprefix):
-            raise error.ProgrammingError('PATH_INFO does not begin with repo '
-                                         'name: %s (%s)' % (env['PATH_INFO'],
-                                                            reponame))
+            raise error.ProgrammingError(
+                'PATH_INFO does not begin with repo '
+                'name: %s (%s)' % (env['PATH_INFO'], reponame)
+            )
 
-        dispatchpath = env['PATH_INFO'][len(repoprefix):]
+        dispatchpath = env['PATH_INFO'][len(repoprefix) :]
 
         if dispatchpath and not dispatchpath.startswith('/'):
-            raise error.ProgrammingError('reponame prefix of PATH_INFO does '
-                                         'not end at path delimiter: %s (%s)' %
-                                         (env['PATH_INFO'], reponame))
+            raise error.ProgrammingError(
+                'reponame prefix of PATH_INFO does '
+                'not end at path delimiter: %s (%s)'
+                % (env['PATH_INFO'], reponame)
+            )
 
         apppath = apppath.rstrip('/') + repoprefix
         dispatchparts = dispatchpath.strip('/').split('/')
@@ -295,9 +302,10 @@
     headers = []
     for k, v in env.iteritems():
         if k.startswith('HTTP_'):
-            headers.append((k[len('HTTP_'):].replace('_', '-'), v))
+            headers.append((k[len('HTTP_') :].replace('_', '-'), v))
 
-    from . import wsgiheaders # avoid cycle
+    from . import wsgiheaders  # avoid cycle
+
     headers = wsgiheaders.Headers(headers)
 
     # This is kind of a lie because the HTTP header wasn't explicitly
@@ -313,24 +321,30 @@
     if bodyfh is None:
         bodyfh = env['wsgi.input']
         if 'Content-Length' in headers:
-            bodyfh = util.cappedreader(bodyfh,
-                                       int(headers['Content-Length'] or '0'))
+            bodyfh = util.cappedreader(
+                bodyfh, int(headers['Content-Length'] or '0')
+            )
 
-    return parsedrequest(method=env['REQUEST_METHOD'],
-                         url=fullurl, baseurl=baseurl,
-                         advertisedurl=advertisedfullurl,
-                         advertisedbaseurl=advertisedbaseurl,
-                         urlscheme=env['wsgi.url_scheme'],
-                         remoteuser=env.get('REMOTE_USER'),
-                         remotehost=env.get('REMOTE_HOST'),
-                         apppath=apppath,
-                         dispatchparts=dispatchparts, dispatchpath=dispatchpath,
-                         reponame=reponame,
-                         querystring=querystring,
-                         qsparams=qsparams,
-                         headers=headers,
-                         bodyfh=bodyfh,
-                         rawenv=env)
+    return parsedrequest(
+        method=env['REQUEST_METHOD'],
+        url=fullurl,
+        baseurl=baseurl,
+        advertisedurl=advertisedfullurl,
+        advertisedbaseurl=advertisedbaseurl,
+        urlscheme=env['wsgi.url_scheme'],
+        remoteuser=env.get('REMOTE_USER'),
+        remotehost=env.get('REMOTE_HOST'),
+        apppath=apppath,
+        dispatchparts=dispatchparts,
+        dispatchpath=dispatchpath,
+        reponame=reponame,
+        querystring=querystring,
+        qsparams=qsparams,
+        headers=headers,
+        bodyfh=bodyfh,
+        rawenv=env,
+    )
+
 
 class offsettrackingwriter(object):
     """A file object like object that is append only and tracks write count.
@@ -345,6 +359,7 @@
     a WSGI ``start_response()`` function. Since ``write()`` is a callable and
     not a file object, it doesn't implement other file object methods.
     """
+
     def __init__(self, writefn):
         self._write = writefn
         self._offset = 0
@@ -363,6 +378,7 @@
     def tell(self):
         return self._offset
 
+
 class wsgiresponse(object):
     """Represents a response to a WSGI request.
 
@@ -389,7 +405,8 @@
         self._startresponse = startresponse
 
         self.status = None
-        from . import wsgiheaders # avoid cycle
+        from . import wsgiheaders  # avoid cycle
+
         self.headers = wsgiheaders.Headers([])
 
         self._bodybytes = None
@@ -399,8 +416,11 @@
         self._bodywritefn = None
 
     def _verifybody(self):
-        if (self._bodybytes is not None or self._bodygen is not None
-            or self._bodywillwrite):
+        if (
+            self._bodybytes is not None
+            or self._bodygen is not None
+            or self._bodywillwrite
+        ):
             raise error.ProgrammingError('cannot define body multiple times')
 
     def setbodybytes(self, b):
@@ -450,8 +470,11 @@
         if not self.status:
             raise error.ProgrammingError('status line not defined')
 
-        if (self._bodybytes is None and self._bodygen is None
-            and not self._bodywillwrite):
+        if (
+            self._bodybytes is None
+            and self._bodygen is None
+            and not self._bodywillwrite
+        ):
             raise error.ProgrammingError('response body not defined')
 
         # RFC 7232 Section 4.1 states that a 304 MUST generate one of
@@ -469,20 +492,30 @@
 
             # Strictly speaking, this is too strict. But until it causes
             # problems, let's be strict.
-            badheaders = {k for k in self.headers.keys()
-                          if k.lower() not in ('date', 'etag', 'expires',
-                                               'cache-control',
-                                               'content-location',
-                                               'content-security-policy',
-                                               'vary')}
+            badheaders = {
+                k
+                for k in self.headers.keys()
+                if k.lower()
+                not in (
+                    'date',
+                    'etag',
+                    'expires',
+                    'cache-control',
+                    'content-location',
+                    'content-security-policy',
+                    'vary',
+                )
+            }
             if badheaders:
                 raise error.ProgrammingError(
-                    'illegal header on 304 response: %s' %
-                    ', '.join(sorted(badheaders)))
+                    'illegal header on 304 response: %s'
+                    % ', '.join(sorted(badheaders))
+                )
 
             if self._bodygen is not None or self._bodywillwrite:
-                raise error.ProgrammingError("must use setbodybytes('') with "
-                                             "304 responses")
+                raise error.ProgrammingError(
+                    "must use setbodybytes('') with " "304 responses"
+                )
 
         # Various HTTP clients (notably httplib) won't read the HTTP response
         # until the HTTP request has been sent in full. If servers (us) send a
@@ -531,10 +564,11 @@
                 if not chunk:
                     break
 
-        strheaders = [(pycompat.strurl(k), pycompat.strurl(v)) for
-                      k, v in self.headers.items()]
-        write = self._startresponse(pycompat.sysstr(self.status),
-                                    strheaders)
+        strheaders = [
+            (pycompat.strurl(k), pycompat.strurl(v))
+            for k, v in self.headers.items()
+        ]
+        write = self._startresponse(pycompat.sysstr(self.status), strheaders)
 
         if self._bodybytes:
             yield self._bodybytes
@@ -566,17 +600,22 @@
             raise error.ProgrammingError('must call setbodywillwrite() first')
 
         if not self._started:
-            raise error.ProgrammingError('must call sendresponse() first; did '
-                                         'you remember to consume it since it '
-                                         'is a generator?')
+            raise error.ProgrammingError(
+                'must call sendresponse() first; did '
+                'you remember to consume it since it '
+                'is a generator?'
+            )
 
         assert self._bodywritefn
         return offsettrackingwriter(self._bodywritefn)
 
+
 def wsgiapplication(app_maker):
     '''For compatibility with old CGI scripts. A plain hgweb() or hgwebdir()
     can and should now be used as a WSGI application.'''
     application = app_maker()
+
     def run_wsgi(env, respond):
         return application(env, respond)
+
     return run_wsgi