Repository: mkdocs/mkdocs
Pull request #2804 (2022-03-26 11:24:41)

Revert to disregarding the mount path for /livereload/ endpoint
Previously there was a pull request "Move livereload endpoint under the mount path (#2740)"
and it definitely makes sense as a way to make livereload work behind a proxy.

However, this change also caused a major annoyance when working on several different sites.
Steps to reproduce:

1. `serve` one site (needs to have `site_url` customized)
2. open the site in a browser
3. stop serving it but keep the browser
4. `serve` another site with a different mount point
5. observe spam of "404" errors in the new terminal (also in the old browser but that's whatever)

So, this reverts the observable effect of commit fafdcc240e0520e34ac30b4dcf78adc4514101ec by @robertaistleitner



Patch:
diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py
index 9f615ca9..7c0db7c5 100644
--- a/mkdocs/config/config_options.py
+++ b/mkdocs/config/config_options.py
@@ -354,12 +354,8 @@ class RepoURL(URL):
                 edit_uri = ''
 
         # ensure a well-formed edit_uri
-        if edit_uri:
-            if not edit_uri.startswith(('?', '#')) \
-                    and not config['repo_url'].endswith('/'):
-                config['repo_url'] += '/'
-            if not edit_uri.endswith('/'):
-                edit_uri += '/'
+        if edit_uri and not edit_uri.endswith('/'):
+            edit_uri += '/'
 
         config['edit_uri'] = edit_uri
 
diff --git a/mkdocs/livereload/__init__.py b/mkdocs/livereload/__init__.py
index 55554a40..9feb27f7 100644
--- a/mkdocs/livereload/__init__.py
+++ b/mkdocs/livereload/__init__.py
@@ -32,7 +32,7 @@ var livereload = function(epoch, requestId) {
             setTimeout(launchNext, 3000);
         }
     };
-    req.open("GET", "${mount_path}livereload/" + epoch + "/" + requestId);
+    req.open("GET", "/livereload/" + epoch + "/" + requestId);
     req.send();
 
     console.log('Enabled live reload');
@@ -201,10 +201,8 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
         # https://github.com/bottlepy/bottle/blob/f9b1849db4/bottle.py#L984
         path = environ["PATH_INFO"].encode("latin-1").decode("utf-8", "ignore")
 
-        if path.startswith(self.mount_path):
-            rel_file_path = path[len(self.mount_path):]
-
-            m = re.fullmatch(r"livereload/([0-9]+)/[0-9]+", rel_file_path)
+        if path.startswith("/livereload/"):
+            m = re.fullmatch(r"/livereload/([0-9]+)/[0-9]+", path)
             if m:
                 epoch = int(m[1])
                 start_response("200 OK", [("Content-Type", "text/plain")])
@@ -220,6 +218,9 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
                         self._epoch_cond.wait_for(condition, timeout=self.poll_response_timeout)
                     return [b"%d" % self._visible_epoch]
 
+        if path.startswith(self.mount_path):
+            rel_file_path = path[len(self.mount_path):]
+
             if path.endswith("/"):
                 rel_file_path += "index.html"
             # Prevent directory traversal - normalize the path.
@@ -266,9 +267,7 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
             body_end = len(content)
         # The page will reload if the livereload poller returns a newer epoch than what it knows.
         # The other timestamp becomes just a unique identifier for the initiating page.
-        script = _SCRIPT_TEMPLATE.substitute(
-            mount_path=self.mount_path, epoch=epoch, request_id=_timestamp()
-        )
+        script = _SCRIPT_TEMPLATE.substitute(epoch=epoch, request_id=_timestamp())
         return b"%b<script>%b</script>%b" % (
             content[:body_end],
             script.encode(),
diff --git a/mkdocs/structure/pages.py b/mkdocs/structure/pages.py
index 951d3a88..db50ddb2 100644
--- a/mkdocs/structure/pages.py
+++ b/mkdocs/structure/pages.py
@@ -104,6 +104,9 @@ class Page:
     def _set_edit_url(self, repo_url, edit_uri):
         if repo_url and edit_uri:
             src_path = self.file.src_path.replace('\\', '/')
+            # Ensure urljoin behavior is correct
+            if not edit_uri.startswith(('?', '#')) and not repo_url.endswith('/'):
+                repo_url += '/'
             self.edit_url = urljoin(repo_url, edit_uri + src_path)
         else:
             self.edit_url = None


Test patch:
diff --git a/mkdocs/tests/config/config_options_tests.py b/mkdocs/tests/config/config_options_tests.py
index db01ba78..e344aec3 100644
--- a/mkdocs/tests/config/config_options_tests.py
+++ b/mkdocs/tests/config/config_options_tests.py
@@ -323,6 +323,7 @@ class RepoURLTest(unittest.TestCase):
         config = {'repo_url': "https://github.com/mkdocs/mkdocs"}
         option.post_validation(config, 'repo_url')
         self.assertEqual(config['edit_uri'], 'edit/master/docs/')
+        self.assertEqual(config['repo_url'], "https://github.com/mkdocs/mkdocs")
 
     def test_edit_uri_bitbucket(self):
 
@@ -330,6 +331,7 @@ class RepoURLTest(unittest.TestCase):
         config = {'repo_url': "https://bitbucket.org/gutworth/six/"}
         option.post_validation(config, 'repo_url')
         self.assertEqual(config['edit_uri'], 'src/default/docs/')
+        self.assertEqual(config['repo_url'], "https://bitbucket.org/gutworth/six/")
 
     def test_edit_uri_gitlab(self):
 
@@ -344,6 +346,7 @@ class RepoURLTest(unittest.TestCase):
         config = {'repo_url': "https://launchpad.net/python-tuskarclient"}
         option.post_validation(config, 'repo_url')
         self.assertEqual(config.get('edit_uri'), '')
+        self.assertEqual(config['repo_url'], "https://launchpad.net/python-tuskarclient")
 
     def test_repo_name_custom_and_empty_edit_uri(self):
 
diff --git a/mkdocs/tests/livereload_tests.py b/mkdocs/tests/livereload_tests.py
index 62483b5b..ecbbaecc 100644
--- a/mkdocs/tests/livereload_tests.py
+++ b/mkdocs/tests/livereload_tests.py
@@ -343,9 +343,9 @@ class BuildTests(unittest.TestCase):
             self.assertTrue(output.isdigit())
 
     @tempdir()
-    def test_serves_polling_from_mount_path(self, site_dir):
+    def test_serves_polling_with_mount_path(self, site_dir):
         with testing_server(site_dir, mount_path="/test/f*o") as server:
-            _, output = do_request(server, "GET /test/f*o/livereload/0/0")
+            _, output = do_request(server, "GET /livereload/0/0")
             self.assertTrue(output.isdigit())
 
     @tempdir()