Patchwork D2818: tests: add test coverage for parsing WSGI requests

login
register
mail settings
Submitter phabricator
Date March 12, 2018, 9:16 p.m.
Message ID <differential-rev-PHID-DREV-rzb3wzjhoyru5ys34ikd-req@phab.mercurial-scm.org>
Download mbox | patch
Permalink /patch/29328/
State Superseded
Headers show

Comments

phabricator - March 12, 2018, 9:16 p.m.
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  A subsequent commit will need to make this code more complicated
  in order to support alternate base URLs. Let's establish some test
  coverage before we diverge too far from PEP 3333.
  
  As part of this, a minor bug related to a missing SCRIPT_NAME
  key has been squashed.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D2818

AFFECTED FILES
  mercurial/hgweb/request.py
  tests/test-wsgirequest.py

CHANGE DETAILS




To: indygreg, #hg-reviewers
Cc: mercurial-devel

Patch

diff --git a/tests/test-wsgirequest.py b/tests/test-wsgirequest.py
new file mode 100644
--- /dev/null
+++ b/tests/test-wsgirequest.py
@@ -0,0 +1,255 @@ 
+from __future__ import absolute_import, print_function
+
+import unittest
+
+from mercurial.hgweb import (
+    request as requestmod,
+)
+
+DEFAULT_ENV = {
+    r'REQUEST_METHOD': r'GET',
+    r'SERVER_NAME': r'testserver',
+    r'SERVER_PORT': r'80',
+    r'SERVER_PROTOCOL': r'http',
+    r'wsgi.version': (1, 0),
+    r'wsgi.url_scheme': r'http',
+    r'wsgi.input': None,
+    r'wsgi.errors': None,
+    r'wsgi.multithread': False,
+    r'wsgi.multiprocess': True,
+    r'wsgi.run_once': False,
+}
+
+def parse(env, bodyfh=None, extra=None):
+    env = dict(env)
+    env.update(extra or {})
+
+    return requestmod.parserequestfromenv(env, bodyfh)
+
+class ParseRequestTests(unittest.TestCase):
+    def testdefault(self):
+        r = parse(DEFAULT_ENV)
+        self.assertEqual(r.url, b'http://testserver')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.urlscheme, b'http')
+        self.assertEqual(r.method, b'GET')
+        self.assertIsNone(r.remoteuser)
+        self.assertIsNone(r.remotehost)
+        self.assertEqual(r.apppath, b'')
+        self.assertEqual(r.dispatchparts, [])
+        self.assertEqual(r.dispatchpath, b'')
+        self.assertFalse(r.havepathinfo)
+        self.assertIsNone(r.reponame)
+        self.assertEqual(r.querystring, b'')
+        self.assertEqual(len(r.qsparams), 0)
+        self.assertEqual(len(r.headers), 0)
+
+    def testcustomport(self):
+        r = parse(DEFAULT_ENV, extra={
+            r'SERVER_PORT': r'8000',
+        })
+
+        self.assertEqual(r.url, b'http://testserver:8000')
+        self.assertEqual(r.baseurl, b'http://testserver:8000')
+        self.assertEqual(r.advertisedurl, b'http://testserver:8000')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver:8000')
+
+        r = parse(DEFAULT_ENV, extra={
+            r'SERVER_PORT': r'4000',
+            r'wsgi.url_scheme': r'https',
+        })
+
+        self.assertEqual(r.url, b'https://testserver:4000')
+        self.assertEqual(r.baseurl, b'https://testserver:4000')
+        self.assertEqual(r.advertisedurl, b'https://testserver:4000')
+        self.assertEqual(r.advertisedbaseurl, b'https://testserver:4000')
+
+    def testhttphost(self):
+        r = parse(DEFAULT_ENV, extra={
+            r'HTTP_HOST': r'altserver',
+        })
+
+        self.assertEqual(r.url, b'http://altserver')
+        self.assertEqual(r.baseurl, b'http://altserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+
+    def testscriptname(self):
+        r = parse(DEFAULT_ENV, extra={
+            r'SCRIPT_NAME': r'',
+        })
+
+        self.assertEqual(r.url, b'http://testserver')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'')
+        self.assertEqual(r.dispatchparts, [])
+        self.assertEqual(r.dispatchpath, b'')
+        self.assertFalse(r.havepathinfo)
+
+        r = parse(DEFAULT_ENV, extra={
+            r'SCRIPT_NAME': r'/script',
+        })
+
+        self.assertEqual(r.url, b'http://testserver/script')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver/script')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'/script')
+        self.assertEqual(r.dispatchparts, [])
+        self.assertEqual(r.dispatchpath, b'')
+        self.assertFalse(r.havepathinfo)
+
+        r = parse(DEFAULT_ENV, extra={
+            r'SCRIPT_NAME': r'/multiple words',
+        })
+
+        self.assertEqual(r.url, b'http://testserver/multiple%20words')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver/multiple%20words')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'/multiple words')
+        self.assertEqual(r.dispatchparts, [])
+        self.assertEqual(r.dispatchpath, b'')
+        self.assertFalse(r.havepathinfo)
+
+    def testpathinfo(self):
+        r = parse(DEFAULT_ENV, extra={
+            r'PATH_INFO': r'',
+        })
+
+        self.assertEqual(r.url, b'http://testserver')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'')
+        self.assertEqual(r.dispatchparts, [])
+        self.assertEqual(r.dispatchpath, b'')
+        self.assertTrue(r.havepathinfo)
+
+        r = parse(DEFAULT_ENV, extra={
+            r'PATH_INFO': r'/pathinfo',
+        })
+
+        self.assertEqual(r.url, b'http://testserver/pathinfo')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver/pathinfo')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'')
+        self.assertEqual(r.dispatchparts, [b'pathinfo'])
+        self.assertEqual(r.dispatchpath, b'pathinfo')
+        self.assertTrue(r.havepathinfo)
+
+        r = parse(DEFAULT_ENV, extra={
+            r'PATH_INFO': r'/one/two/',
+        })
+
+        self.assertEqual(r.url, b'http://testserver/one/two/')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver/one/two/')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'')
+        self.assertEqual(r.dispatchparts, [b'one', b'two'])
+        self.assertEqual(r.dispatchpath, b'one/two')
+        self.assertTrue(r.havepathinfo)
+
+    def testscriptandpathinfo(self):
+        r = parse(DEFAULT_ENV, extra={
+            r'SCRIPT_NAME': r'/script',
+            r'PATH_INFO': r'/pathinfo',
+        })
+
+        self.assertEqual(r.url, b'http://testserver/script/pathinfo')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver/script/pathinfo')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'/script')
+        self.assertEqual(r.dispatchparts, [b'pathinfo'])
+        self.assertEqual(r.dispatchpath, b'pathinfo')
+        self.assertTrue(r.havepathinfo)
+
+        r = parse(DEFAULT_ENV, extra={
+            r'SCRIPT_NAME': r'/script1/script2',
+            r'PATH_INFO': r'/path1/path2',
+        })
+
+        self.assertEqual(r.url,
+                         b'http://testserver/script1/script2/path1/path2')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl,
+                         b'http://testserver/script1/script2/path1/path2')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'/script1/script2')
+        self.assertEqual(r.dispatchparts, [b'path1', b'path2'])
+        self.assertEqual(r.dispatchpath, b'path1/path2')
+        self.assertTrue(r.havepathinfo)
+
+        r = parse(DEFAULT_ENV, extra={
+            r'HTTP_HOST': r'hostserver',
+            r'SCRIPT_NAME': r'/script',
+            r'PATH_INFO': r'/pathinfo',
+        })
+
+        self.assertEqual(r.url, b'http://hostserver/script/pathinfo')
+        self.assertEqual(r.baseurl, b'http://hostserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver/script/pathinfo')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'/script')
+        self.assertEqual(r.dispatchparts, [b'pathinfo'])
+        self.assertEqual(r.dispatchpath, b'pathinfo')
+        self.assertTrue(r.havepathinfo)
+
+    def testreponame(self):
+        """REPO_NAME path components get stripped from URL."""
+        r = parse(DEFAULT_ENV, extra={
+            r'REPO_NAME': r'repo',
+            r'PATH_INFO': r'/path1/path2'
+        })
+
+        self.assertEqual(r.url, b'http://testserver/path1/path2')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver/path1/path2')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'/repo')
+        self.assertEqual(r.dispatchparts, [b'path1', b'path2'])
+        self.assertEqual(r.dispatchpath, b'path1/path2')
+        self.assertTrue(r.havepathinfo)
+        self.assertEqual(r.reponame, b'repo')
+
+        r = parse(DEFAULT_ENV, extra={
+            r'REPO_NAME': r'repo',
+            r'PATH_INFO': r'/repo/path1/path2',
+        })
+
+        self.assertEqual(r.url, b'http://testserver/repo/path1/path2')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl, b'http://testserver/repo/path1/path2')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'/repo')
+        self.assertEqual(r.dispatchparts, [b'path1', b'path2'])
+        self.assertEqual(r.dispatchpath, b'path1/path2')
+        self.assertTrue(r.havepathinfo)
+        self.assertEqual(r.reponame, b'repo')
+
+        r = parse(DEFAULT_ENV, extra={
+            r'REPO_NAME': r'prefix/repo',
+            r'PATH_INFO': r'/prefix/repo/path1/path2',
+        })
+
+        self.assertEqual(r.url, b'http://testserver/prefix/repo/path1/path2')
+        self.assertEqual(r.baseurl, b'http://testserver')
+        self.assertEqual(r.advertisedurl,
+                         b'http://testserver/prefix/repo/path1/path2')
+        self.assertEqual(r.advertisedbaseurl, b'http://testserver')
+        self.assertEqual(r.apppath, b'/prefix/repo')
+        self.assertEqual(r.dispatchparts, [b'path1', b'path2'])
+        self.assertEqual(r.dispatchpath, b'path1/path2')
+        self.assertTrue(r.havepathinfo)
+        self.assertEqual(r.reponame, b'prefix/repo')
+
+if __name__ == '__main__':
+    import silenttestrunner
+    silenttestrunner.main(__name__)
diff --git a/mercurial/hgweb/request.py b/mercurial/hgweb/request.py
--- a/mercurial/hgweb/request.py
+++ b/mercurial/hgweb/request.py
@@ -222,7 +222,7 @@ 
     # root. We also exclude its path components from PATH_INFO when resolving
     # the dispatch path.
 
-    apppath = env['SCRIPT_NAME']
+    apppath = env.get('SCRIPT_NAME', '')
 
     if env.get('REPO_NAME'):
         if not apppath.endswith('/'):