# HG changeset patch
# User Matt Harbison <matt_harbi...@yahoo.com>
# Date 1487087965 18000
#      Tue Feb 14 10:59:25 2017 -0500
# Node ID 27a4bc77e8b8e50abc76c387f117082e5853c47e
# Parent  4f2862487d789edc1f36b5687d828a2914e1dc32
clone: use the HTTP 301 location to record the default path

This is needed to simplify making `hg serve -S` paths the same as `hg serve`.
Since 301 is permanent and cachable, this is arguably the proper behavior
anyway.  For example, once Firefox sees a 301, it automatically forwards,
without querying the original URL again.

Code hosting software may make use of redirects.  I only have access to SCM
Manager.  It uses 302 to access subrepos, so it isn't affected by this.  My
understanding of the python libraries being used is minimal, and this was
inspired by http://www.diveintopython.net/http_web_services/redirects.html.

Since `hg serve` doesn't issue redirects, the added tests aren't showing the new
redirect functionality yet.  But they set a baseline that won't change when
redirects are issued.  Check-commit complains about the methods with '_', but
those names are defined by python.

diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -621,6 +621,15 @@
 
         destrepo = destpeer.local()
         if destrepo:
+            # Update for 301 redirects
+            endsrc = srcpeer.url()
+            if not islocal(endsrc):
+                abspath = endsrc
+
+                # statichttprepository never sees the 'static-' prefix, so that
+                # need to be accounted for here.
+                if origsource.startswith('static-http'):
+                    abspath = 'static-' + abspath
             template = uimod.samplehgrcs['cloned']
             fp = destrepo.vfs("hgrc", "w", text=True)
             u = util.url(abspath)
diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
--- a/mercurial/httppeer.py
+++ b/mercurial/httppeer.py
@@ -88,12 +88,12 @@
                              (u.query or u.fragment))
 
         # urllib cannot handle URLs with embedded user or passwd
-        self._url, authinfo = u.authinfo()
+        self._url, self._authinfo = u.authinfo()
 
         self.ui = ui
         self.ui.debug('using %s\n' % self._url)
 
-        self.urlopener = url.opener(ui, authinfo)
+        self.urlopener = url.opener(ui, self._authinfo)
         self.requestbuilder = urlreq.request
 
     def __del__(self):
@@ -230,6 +230,16 @@
         if self._url.rstrip('/') != resp_url.rstrip('/'):
             if not self.ui.quiet:
                 self.ui.warn(_('real URL is %s\n') % resp_url)
+            if resp.status == httplib.MOVED_PERMANENTLY:
+                u = util.url(resp_url.rstrip('/'))
+
+                # The path has auth info on creation.  Restore that here.
+                creds = self._authinfo
+                if creds:
+                    u.user = creds[2]
+                    u.passwd = creds[3] or None
+                self.path = str(u)
+
         self._url = resp_url
         try:
             proto = resp.getheader('content-type')
diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py
--- a/mercurial/pycompat.py
+++ b/mercurial/pycompat.py
@@ -227,6 +227,7 @@
         "HTTPDigestAuthHandler",
         "HTTPHandler",
         "HTTPPasswordMgrWithDefaultRealm",
+        "HTTPRedirectHandler",
         "HTTPSHandler",
         "install_opener",
         "ProxyHandler",
diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -272,6 +272,30 @@
 
     return False
 
+class httpredirecthandler(urlreq.httpredirecthandler):
+    def __init__(self):
+        self._permmoved = True
+
+    def redirect_request(self, req, fp, code, msg, hdrs, newurl):
+        '''Called by all http_error_3xx() to monitor redirect types seen'''
+        # Avoid treating 302 -> 301 -> 200 or 301 -> 302 -> 200 as permanent
+        # redirects.
+        self._permmoved = self._permmoved and code == httplib.MOVED_PERMANENTLY
+
+        impl = urlreq.httpredirecthandler.redirect_request
+        return impl(self, req, fp, code, msg, hdrs, newurl)
+
+    def http_error_301(self, req, fp, code, msg, headers):
+        '''Capture the permanent redirect status for later access'''
+        impl = urlreq.httpredirecthandler.http_error_301
+        result = impl(self, req, fp, code, msg, headers)
+
+        # For an unbroken chain of 301, indicate 301 in the status.  Otherwise,
+        # keep the 200 status.
+        if self._permmoved:
+            result.status = code
+        return result
+
 class httphandler(keepalive.HTTPHandler):
     def http_open(self, req):
         return self.do_open(httpconnection, req)
@@ -437,6 +461,7 @@
             handlers.append(httpshandler(ui))
 
     handlers.append(proxyhandler(ui))
+    handlers.append(httpredirecthandler())
 
     passmgr = passwordmgr(ui, ui.httppasswordmgrdb)
     if authinfo is not None:
diff --git a/tests/test-subrepo-deep-nested-change.t 
b/tests/test-subrepo-deep-nested-change.t
--- a/tests/test-subrepo-deep-nested-change.t
+++ b/tests/test-subrepo-deep-nested-change.t
@@ -84,20 +84,20 @@
   adding sub2/ = $TESTTMP/main/sub1/sub2 (glob)
   $ cat hg1.pid >> $DAEMON_PIDS
 
-  $ hg clone http://localhost:$HGPORT/main httpclone --config 
progress.disable=True
+  $ hg clone http://user@localhost:$HGPORT/main httpclone --config 
progress.disable=True
   requesting all changes
   adding changesets
   adding manifests
   adding file changes
   added 1 changesets with 3 changes to 3 files
   updating to branch default
-  cloning subrepo sub1 from http://localhost:$HGPORT/sub1
+  cloning subrepo sub1 from http://user@localhost:$HGPORT/sub1
   requesting all changes
   adding changesets
   adding manifests
   adding file changes
   added 1 changesets with 3 changes to 3 files
-  cloning subrepo sub1/sub2 from http://localhost:$HGPORT/sub2 (glob)
+  cloning subrepo sub1/sub2 from http://user@localhost:$HGPORT/sub2 (glob)
   requesting all changes
   adding changesets
   adding manifests
@@ -105,6 +105,11 @@
   added 1 changesets with 1 changes to 1 files
   3 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
+  $ hg -R httpclone showconfig paths.default
+  http://user@localhost:$HGPORT/main
+  $ hg -R httpclone/sub1 showconfig paths.default
+  http://user@localhost:$HGPORT/sub1
+
   $ cat access.log
   * "GET /main?cmd=capabilities HTTP/1.1" 200 - (glob)
   * "GET /main?cmd=batch HTTP/1.1" 200 - * (glob)
diff --git a/tests/test-subrepo-recursion.t b/tests/test-subrepo-recursion.t
--- a/tests/test-subrepo-recursion.t
+++ b/tests/test-subrepo-recursion.t
@@ -263,20 +263,20 @@
   adding repo/foo/bar/ = $TESTTMP/repo/foo/bar (glob)
   $ cat hg1.pid >> $DAEMON_PIDS
 
-  $ hg clone http://localhost:$HGPORT/repo clone  --config 
progress.disable=True
+  $ hg clone http://user:pass@localhost:$HGPORT/repo clone  --config 
progress.disable=True
   requesting all changes
   adding changesets
   adding manifests
   adding file changes
   added 3 changesets with 5 changes to 3 files
   updating to branch default
-  cloning subrepo foo from http://localhost:$HGPORT/repo/foo
+  cloning subrepo foo from http://user@localhost:$HGPORT/repo/foo
   requesting all changes
   adding changesets
   adding manifests
   adding file changes
   added 4 changesets with 7 changes to 3 files
-  cloning subrepo foo/bar from http://localhost:$HGPORT/repo/foo/bar (glob)
+  cloning subrepo foo/bar from http://user@localhost:$HGPORT/repo/foo/bar 
(glob)
   requesting all changes
   adding changesets
   adding manifests
@@ -284,6 +284,11 @@
   added 3 changesets with 3 changes to 1 files
   3 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
+  $ hg -R clone showconfig paths.default
+  http://user@localhost:$HGPORT/repo
+  $ hg -R clone/foo showconfig paths.default
+  http://user@localhost:$HGPORT/repo/foo
+
   $ cat clone/foo/bar/z.txt
   z1
   z2
_______________________________________________
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Reply via email to