D2822: hgweb: support constructing URLs from an alternate base URL

2018-03-12 Thread indygreg (Gregory Szorc)
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG219b23359f4c: hgweb: support constructing URLs from an 
alternate base URL (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2822?vs=6888=6952

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

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

CHANGE DETAILS

diff --git a/tests/test-wsgirequest.py b/tests/test-wsgirequest.py
--- a/tests/test-wsgirequest.py
+++ b/tests/test-wsgirequest.py
@@ -23,11 +23,12 @@
 r'wsgi.run_once': False,
 }
 
-def parse(env, bodyfh=None, reponame=None, extra=None):
+def parse(env, bodyfh=None, reponame=None, altbaseurl=None, extra=None):
 env = dict(env)
 env.update(extra or {})
 
-return requestmod.parserequestfromenv(env, bodyfh, reponame=reponame)
+return requestmod.parserequestfromenv(env, bodyfh, reponame=reponame,
+  altbaseurl=altbaseurl)
 
 class ParseRequestTests(unittest.TestCase):
 def testdefault(self):
@@ -242,6 +243,174 @@
 self.assertEqual(r.dispatchpath, b'path1/path2')
 self.assertEqual(r.reponame, b'prefix/repo')
 
+def testaltbaseurl(self):
+# Simple hostname remap.
+r = parse(DEFAULT_ENV, altbaseurl='http://altserver')
+
+self.assertEqual(r.url, b'http://testserver')
+self.assertEqual(r.baseurl, b'http://testserver')
+self.assertEqual(r.advertisedurl, b'http://altserver')
+self.assertEqual(r.advertisedbaseurl, b'http://altserver')
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'')
+self.assertEqual(r.dispatchparts, [])
+self.assertIsNone(r.dispatchpath)
+self.assertIsNone(r.reponame)
+
+# With a custom port.
+r = parse(DEFAULT_ENV, altbaseurl='http://altserver:8000')
+self.assertEqual(r.url, b'http://testserver')
+self.assertEqual(r.baseurl, b'http://testserver')
+self.assertEqual(r.advertisedurl, b'http://altserver:8000')
+self.assertEqual(r.advertisedbaseurl, b'http://altserver:8000')
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'')
+self.assertEqual(r.dispatchparts, [])
+self.assertIsNone(r.dispatchpath)
+self.assertIsNone(r.reponame)
+
+# With a changed protocol.
+r = parse(DEFAULT_ENV, altbaseurl='https://altserver')
+self.assertEqual(r.url, b'http://testserver')
+self.assertEqual(r.baseurl, b'http://testserver')
+self.assertEqual(r.advertisedurl, b'https://altserver')
+self.assertEqual(r.advertisedbaseurl, b'https://altserver')
+# URL scheme is defined as the actual scheme, not advertised.
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'')
+self.assertEqual(r.dispatchparts, [])
+self.assertIsNone(r.dispatchpath)
+self.assertIsNone(r.reponame)
+
+# Need to specify explicit port number for proper https:// alt URLs.
+r = parse(DEFAULT_ENV, altbaseurl='https://altserver:443')
+self.assertEqual(r.url, b'http://testserver')
+self.assertEqual(r.baseurl, b'http://testserver')
+self.assertEqual(r.advertisedurl, b'https://altserver')
+self.assertEqual(r.advertisedbaseurl, b'https://altserver')
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'')
+self.assertEqual(r.dispatchparts, [])
+self.assertIsNone(r.dispatchpath)
+self.assertIsNone(r.reponame)
+
+# With only PATH_INFO defined.
+r = parse(DEFAULT_ENV, altbaseurl='http://altserver', extra={
+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://altserver/path1/path2')
+self.assertEqual(r.advertisedbaseurl, b'http://altserver')
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'')
+self.assertEqual(r.dispatchparts, [b'path1', b'path2'])
+self.assertEqual(r.dispatchpath, b'path1/path2')
+self.assertIsNone(r.reponame)
+
+# Path on alt URL.
+r = parse(DEFAULT_ENV, altbaseurl='http://altserver/altpath')
+self.assertEqual(r.url, b'http://testserver')
+self.assertEqual(r.baseurl, b'http://testserver')
+self.assertEqual(r.advertisedurl, b'http://altserver/altpath')
+self.assertEqual(r.advertisedbaseurl, b'http://altserver')
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'/altpath')
+self.assertEqual(r.dispatchparts, [])
+self.assertIsNone(r.dispatchpath)
+self.assertIsNone(r.reponame)
+
+  

D2822: hgweb: support constructing URLs from an alternate base URL

2018-03-12 Thread indygreg (Gregory Szorc)
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The web.baseurl config option allows server operators to define a
  custom URL for hosted content.
  
  The way it works today is that hgwebdir parses this config
  option into URL components then updates the appropriate
  WSGI environment variables so the request "lies" about its
  details. For example, SERVER_NAME is updated to reflect the
  alternate base URL's hostname.
  
  The WSGI environment should not be modified because WSGI
  applications may want to know the original request details (for
  debugging, etc).
  
  This commit teaches our request parser about the existence of
  an alternate base URL. If defined, the advertised URL and other
  self-reflected paths will take the alternate base URL into account.
  
  The hgweb WSGI application didn't use web.baseurl. But hgwebdir
  did. We update hgwebdir to alter the environment parsing
  accordingly. The old code around environment manipulation
  has been removed.
  
  With this change, parserequestfromenv() has grown to a bit
  unwieldy. Now that practically everyone is using it, it is
  obvious that there is some unused features that can be trimmed.
  So look for this in follow-up commits.

REPOSITORY
  rHG Mercurial

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

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

CHANGE DETAILS

diff --git a/tests/test-wsgirequest.py b/tests/test-wsgirequest.py
--- a/tests/test-wsgirequest.py
+++ b/tests/test-wsgirequest.py
@@ -23,11 +23,12 @@
 r'wsgi.run_once': False,
 }
 
-def parse(env, bodyfh=None, reponame=None, extra=None):
+def parse(env, bodyfh=None, reponame=None, altbaseurl=None, extra=None):
 env = dict(env)
 env.update(extra or {})
 
-return requestmod.parserequestfromenv(env, bodyfh, reponame=reponame)
+return requestmod.parserequestfromenv(env, bodyfh, reponame=reponame,
+  altbaseurl=altbaseurl)
 
 class ParseRequestTests(unittest.TestCase):
 def testdefault(self):
@@ -242,6 +243,174 @@
 self.assertEqual(r.dispatchpath, b'path1/path2')
 self.assertEqual(r.reponame, b'prefix/repo')
 
+def testaltbaseurl(self):
+# Simple hostname remap.
+r = parse(DEFAULT_ENV, altbaseurl='http://altserver')
+
+self.assertEqual(r.url, b'http://testserver')
+self.assertEqual(r.baseurl, b'http://testserver')
+self.assertEqual(r.advertisedurl, b'http://altserver')
+self.assertEqual(r.advertisedbaseurl, b'http://altserver')
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'')
+self.assertEqual(r.dispatchparts, [])
+self.assertIsNone(r.dispatchpath)
+self.assertIsNone(r.reponame)
+
+# With a custom port.
+r = parse(DEFAULT_ENV, altbaseurl='http://altserver:8000')
+self.assertEqual(r.url, b'http://testserver')
+self.assertEqual(r.baseurl, b'http://testserver')
+self.assertEqual(r.advertisedurl, b'http://altserver:8000')
+self.assertEqual(r.advertisedbaseurl, b'http://altserver:8000')
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'')
+self.assertEqual(r.dispatchparts, [])
+self.assertIsNone(r.dispatchpath)
+self.assertIsNone(r.reponame)
+
+# With a changed protocol.
+r = parse(DEFAULT_ENV, altbaseurl='https://altserver')
+self.assertEqual(r.url, b'http://testserver')
+self.assertEqual(r.baseurl, b'http://testserver')
+self.assertEqual(r.advertisedurl, b'https://altserver')
+self.assertEqual(r.advertisedbaseurl, b'https://altserver')
+# URL scheme is defined as the actual scheme, not advertised.
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'')
+self.assertEqual(r.dispatchparts, [])
+self.assertIsNone(r.dispatchpath)
+self.assertIsNone(r.reponame)
+
+# Need to specify explicit port number for proper https:// alt URLs.
+r = parse(DEFAULT_ENV, altbaseurl='https://altserver:443')
+self.assertEqual(r.url, b'http://testserver')
+self.assertEqual(r.baseurl, b'http://testserver')
+self.assertEqual(r.advertisedurl, b'https://altserver')
+self.assertEqual(r.advertisedbaseurl, b'https://altserver')
+self.assertEqual(r.urlscheme, b'http')
+self.assertEqual(r.apppath, b'')
+self.assertEqual(r.dispatchparts, [])
+self.assertIsNone(r.dispatchpath)
+self.assertIsNone(r.reponame)
+
+# With only PATH_INFO defined.
+r = parse(DEFAULT_ENV, altbaseurl='http://altserver', extra={
+r'PATH_INFO': r'/path1/path2',
+})
+self.assertEqual(r.url, b'http://testserver/path1/path2')
+