We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
add data-base-url attribute to HTML body tag in Plone 4
Since plone 4.3.12, the `<base href` attribute in HTML generated by Plone no longer always points to the context URL as it used to prior to the change. This change broke Plone and some add-ons. More breakage may still surface. Fixes have varied because no alternative was provided when the change was made.

For a lengthy background, see the [discussion](https://community.plone.org/t/how-to-get-context-url-in-js-on-plone-4-3-12/4031). 

Rather than rolling back the change which was done to support some other things and would require reverting them, I suggest providing a future-proof alternative (thanks @rodfersou for suggesting using a new attribute):

Plone 5 has removed `<base href` completely. Instead Plone 5 has added a `data-base-url` attribute to the HTML `body` tag. Which points to the context URL.

So, I suggest same be done for Plone 4. That way, anything in Plone core and/or add-ons needing context URL in Javascript have a future-proof way of getting it from here on.


@@sharing is broken on Page objects in Plone 4.3.12 and 4.3.14
## BUG/PROBLEM REPORT (OR OTHER COMMON ISSUE)

### What I did:

1. Create vanilla Plone 4.3.14 site.
2. Add private Page with title Test at the top of the site
3. Navigate to sharing tab for that page
4. Type some characters into the Search box
5. Kaboom: exception

### What I expect to happen:

List of potential users as search results

### What actually happened:

Large python back trace because the search form AJAX accessed:

  http://localhost:8080/Plone2/test/@@sharing/@@updateSharingInfo

rather than the following used by Plone 4.3.11:

  http://localhost:8080/Plone2/test/@@updateSharingInfo
 
The root cause appears to be:

https://pypi.python.org/pypi/plone.app.layout/2.3.17

  2.3.15 (2016-06-28)
   Fixes:
   _Fix base tag differs from actual URL (fixes [86](https://github.com/plone/plone.app.layout/issues/86)). [rodfersou]_

which was actually made **after** plone.app.layout 2.3.15 was released, (December 2016): that comment is placed incorrectly in the README file. I'm happy to make a bug report there as well.

### What version of Plone/ Addons I am using:

Vanilla Plone 4.3.14, which uses  plone.app.layout 2.3.17. So does Plone 4.3.12, and I see exactly the same problem there.

(NB: Pinning plone.app.layout 2.3.15 in Plone 4.3.14 resolves the problem).

Update: appears to be the same issue discussed in: https://github.com/plone/Products.CMFPlone/issues/2051


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `Products/CMFPlone/browser/jsvariables.py`
Content:
```
1 from zope.i18n import translate
2 from zope.publisher.browser import BrowserView
3 
4 from Products.CMFCore.utils import getToolByName
5 from Products.CMFPlone import PloneMessageFactory as _
6 
7 
8 TEMPLATE = """\
9 var portal_url = '%(portal_url)s';
10 var form_modified_message = '%(form_modified)s';
11 var form_resubmit_message = '%(form_resubmit)s';
12 var external_links_open_new_window = '%(open_links)s';
13 var mark_special_links = '%(mark_links)s';
14 var ajax_noresponse_message = '%(ajax_noresponse)s';
15 """
16 
17 FORM_MODIFIED = _(u'text_form_modified_message',
18                   default=u'Your form has not been saved. All changes you '
19                           u'have made will be lost.')
20 
21 FORM_RESUBMIT = _(u'text_form_resubmit_message',
22                   default=u'You already clicked the submit button. Do you '
23                           u'really want to submit this form again?')
24 
25 AJAX_NORESPONSE = _(u'text_ajax_noresponse_message',
26                     default=u'No response from server. Please try again '
27                             u'later.')
28 
29 
30 class JSVariables(BrowserView):
31 
32     def __call__(self, *args, **kwargs):
33         context = self.context
34         response = self.request.response
35         response.setHeader('content-type', 'text/javascript;;charset=utf-8')
36 
37         props = getToolByName(context, 'portal_properties').site_properties
38         portal_url = getToolByName(context, 'portal_url')()
39 
40         # the following are flags for mark_special_links.js
41         # links get the target="_blank" attribute
42         open_links = props.getProperty('external_links_open_new_window',
43                                        'false')
44         mark_links = props.getProperty('mark_special_links', 'false')
45 
46         form_modified = translate(FORM_MODIFIED, context=self.request)
47         form_resubmit = translate(FORM_RESUBMIT, context=self.request)
48         ajax_noresponse = translate(AJAX_NORESPONSE, context=self.request)
49 
50         # escape_for_js
51         form_modified = form_modified.replace("'", "\\'")
52         form_resubmit = form_resubmit.replace("'", "\\'")
53         ajax_noresponse = ajax_noresponse.replace("'", "\\'")
54 
55         return TEMPLATE % dict(
56             portal_url=portal_url,
57             open_links=open_links,
58             mark_links=mark_links,
59             form_modified=form_modified,
60             form_resubmit=form_resubmit,
61             ajax_noresponse=ajax_noresponse,
62         )
63
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/Products/CMFPlone/browser/jsvariables.py b/Products/CMFPlone/browser/jsvariables.py
--- a/Products/CMFPlone/browser/jsvariables.py
+++ b/Products/CMFPlone/browser/jsvariables.py
@@ -7,6 +7,7 @@
 
 TEMPLATE = """\
 var portal_url = '%(portal_url)s';
+var base_url = '%(base_url)s';
 var form_modified_message = '%(form_modified)s';
 var form_resubmit_message = '%(form_resubmit)s';
 var external_links_open_new_window = '%(open_links)s';
@@ -36,6 +37,7 @@
 
         props = getToolByName(context, 'portal_properties').site_properties
         portal_url = getToolByName(context, 'portal_url')()
+        base_url = self.request['HTTP_REFERER']
 
         # the following are flags for mark_special_links.js
         # links get the target="_blank" attribute
@@ -54,6 +56,7 @@
 
         return TEMPLATE % dict(
             portal_url=portal_url,
+            base_url=base_url,
             open_links=open_links,
             mark_links=mark_links,
             form_modified=form_modified,

{"golden_diff": "diff --git a/Products/CMFPlone/browser/jsvariables.py b/Products/CMFPlone/browser/jsvariables.py\n--- a/Products/CMFPlone/browser/jsvariables.py\n+++ b/Products/CMFPlone/browser/jsvariables.py\n@@ -7,6 +7,7 @@\n \n TEMPLATE = \"\"\"\\\n var portal_url = '%(portal_url)s';\n+var base_url = '%(base_url)s';\n var form_modified_message = '%(form_modified)s';\n var form_resubmit_message = '%(form_resubmit)s';\n var external_links_open_new_window = '%(open_links)s';\n@@ -36,6 +37,7 @@\n \n         props = getToolByName(context, 'portal_properties').site_properties\n         portal_url = getToolByName(context, 'portal_url')()\n+        base_url = self.request['HTTP_REFERER']\n \n         # the following are flags for mark_special_links.js\n         # links get the target=\"_blank\" attribute\n@@ -54,6 +56,7 @@\n \n         return TEMPLATE % dict(\n             portal_url=portal_url,\n+            base_url=base_url,\n             open_links=open_links,\n             mark_links=mark_links,\n             form_modified=form_modified,\n", "issue": "add data-base-url attribute to HTML body tag in Plone 4\nSince plone 4.3.12, the `<base href` attribute in HTML generated by Plone no longer always points to the context URL as it used to prior to the change. This change broke Plone and some add-ons. More breakage may still surface. Fixes have varied because no alternative was provided when the change was made.\r\n\r\nFor a lengthy background, see the [discussion](https://community.plone.org/t/how-to-get-context-url-in-js-on-plone-4-3-12/4031). \r\n\r\nRather than rolling back the change which was done to support some other things and would require reverting them, I suggest providing a future-proof alternative (thanks @rodfersou for suggesting using a new attribute):\r\n\r\nPlone 5 has removed `<base href` completely. Instead Plone 5 has added a `data-base-url` attribute to the HTML `body` tag. Which points to the context URL.\r\n\r\nSo, I suggest same be done for Plone 4. That way, anything in Plone core and/or add-ons needing context URL in Javascript have a future-proof way of getting it from here on.\r\n\r\n\n@@sharing is broken on Page objects in Plone 4.3.12 and 4.3.14\n## BUG/PROBLEM REPORT (OR OTHER COMMON ISSUE)\r\n\r\n### What I did:\r\n\r\n1. Create vanilla Plone 4.3.14 site.\r\n2. Add private Page with title Test at the top of the site\r\n3. Navigate to sharing tab for that page\r\n4. Type some characters into the Search box\r\n5. Kaboom: exception\r\n\r\n### What I expect to happen:\r\n\r\nList of potential users as search results\r\n\r\n### What actually happened:\r\n\r\nLarge python back trace because the search form AJAX accessed:\r\n\r\n  http://localhost:8080/Plone2/test/@@sharing/@@updateSharingInfo\r\n\r\nrather than the following used by Plone 4.3.11:\r\n\r\n  http://localhost:8080/Plone2/test/@@updateSharingInfo\r\n \r\nThe root cause appears to be:\r\n\r\nhttps://pypi.python.org/pypi/plone.app.layout/2.3.17\r\n\r\n  2.3.15 (2016-06-28)\r\n   Fixes:\r\n   _Fix base tag differs from actual URL (fixes [86](https://github.com/plone/plone.app.layout/issues/86)). [rodfersou]_\r\n\r\nwhich was actually made **after** plone.app.layout 2.3.15 was released, (December 2016): that comment is placed incorrectly in the README file. I'm happy to make a bug report there as well.\r\n\r\n### What version of Plone/ Addons I am using:\r\n\r\nVanilla Plone 4.3.14, which uses  plone.app.layout 2.3.17. So does Plone 4.3.12, and I see exactly the same problem there.\r\n\r\n(NB: Pinning plone.app.layout 2.3.15 in Plone 4.3.14 resolves the problem).\r\n\r\nUpdate: appears to be the same issue discussed in: https://github.com/plone/Products.CMFPlone/issues/2051\r\n\n", "before_files": [{"content": "from zope.i18n import translate\nfrom zope.publisher.browser import BrowserView\n\nfrom Products.CMFCore.utils import getToolByName\nfrom Products.CMFPlone import PloneMessageFactory as _\n\n\nTEMPLATE = \"\"\"\\\nvar portal_url = '%(portal_url)s';\nvar form_modified_message = '%(form_modified)s';\nvar form_resubmit_message = '%(form_resubmit)s';\nvar external_links_open_new_window = '%(open_links)s';\nvar mark_special_links = '%(mark_links)s';\nvar ajax_noresponse_message = '%(ajax_noresponse)s';\n\"\"\"\n\nFORM_MODIFIED = _(u'text_form_modified_message',\n                  default=u'Your form has not been saved. All changes you '\n                          u'have made will be lost.')\n\nFORM_RESUBMIT = _(u'text_form_resubmit_message',\n                  default=u'You already clicked the submit button. Do you '\n                          u'really want to submit this form again?')\n\nAJAX_NORESPONSE = _(u'text_ajax_noresponse_message',\n                    default=u'No response from server. Please try again '\n                            u'later.')\n\n\nclass JSVariables(BrowserView):\n\n    def __call__(self, *args, **kwargs):\n        context = self.context\n        response = self.request.response\n        response.setHeader('content-type', 'text/javascript;;charset=utf-8')\n\n        props = getToolByName(context, 'portal_properties').site_properties\n        portal_url = getToolByName(context, 'portal_url')()\n\n        # the following are flags for mark_special_links.js\n        # links get the target=\"_blank\" attribute\n        open_links = props.getProperty('external_links_open_new_window',\n                                       'false')\n        mark_links = props.getProperty('mark_special_links', 'false')\n\n        form_modified = translate(FORM_MODIFIED, context=self.request)\n        form_resubmit = translate(FORM_RESUBMIT, context=self.request)\n        ajax_noresponse = translate(AJAX_NORESPONSE, context=self.request)\n\n        # escape_for_js\n        form_modified = form_modified.replace(\"'\", \"\\\\'\")\n        form_resubmit = form_resubmit.replace(\"'\", \"\\\\'\")\n        ajax_noresponse = ajax_noresponse.replace(\"'\", \"\\\\'\")\n\n        return TEMPLATE % dict(\n            portal_url=portal_url,\n            open_links=open_links,\n            mark_links=mark_links,\n            form_modified=form_modified,\n            form_resubmit=form_resubmit,\n            ajax_noresponse=ajax_noresponse,\n        )\n", "path": "Products/CMFPlone/browser/jsvariables.py"}], "after_files": [{"content": "from zope.i18n import translate\nfrom zope.publisher.browser import BrowserView\n\nfrom Products.CMFCore.utils import getToolByName\nfrom Products.CMFPlone import PloneMessageFactory as _\n\n\nTEMPLATE = \"\"\"\\\nvar portal_url = '%(portal_url)s';\nvar base_url = '%(base_url)s';\nvar form_modified_message = '%(form_modified)s';\nvar form_resubmit_message = '%(form_resubmit)s';\nvar external_links_open_new_window = '%(open_links)s';\nvar mark_special_links = '%(mark_links)s';\nvar ajax_noresponse_message = '%(ajax_noresponse)s';\n\"\"\"\n\nFORM_MODIFIED = _(u'text_form_modified_message',\n                  default=u'Your form has not been saved. All changes you '\n                          u'have made will be lost.')\n\nFORM_RESUBMIT = _(u'text_form_resubmit_message',\n                  default=u'You already clicked the submit button. Do you '\n                          u'really want to submit this form again?')\n\nAJAX_NORESPONSE = _(u'text_ajax_noresponse_message',\n                    default=u'No response from server. Please try again '\n                            u'later.')\n\n\nclass JSVariables(BrowserView):\n\n    def __call__(self, *args, **kwargs):\n        context = self.context\n        response = self.request.response\n        response.setHeader('content-type', 'text/javascript;;charset=utf-8')\n\n        props = getToolByName(context, 'portal_properties').site_properties\n        portal_url = getToolByName(context, 'portal_url')()\n        base_url = self.request['HTTP_REFERER']\n\n        # the following are flags for mark_special_links.js\n        # links get the target=\"_blank\" attribute\n        open_links = props.getProperty('external_links_open_new_window',\n                                       'false')\n        mark_links = props.getProperty('mark_special_links', 'false')\n\n        form_modified = translate(FORM_MODIFIED, context=self.request)\n        form_resubmit = translate(FORM_RESUBMIT, context=self.request)\n        ajax_noresponse = translate(AJAX_NORESPONSE, context=self.request)\n\n        # escape_for_js\n        form_modified = form_modified.replace(\"'\", \"\\\\'\")\n        form_resubmit = form_resubmit.replace(\"'\", \"\\\\'\")\n        ajax_noresponse = ajax_noresponse.replace(\"'\", \"\\\\'\")\n\n        return TEMPLATE % dict(\n            portal_url=portal_url,\n            base_url=base_url,\n            open_links=open_links,\n            mark_links=mark_links,\n            form_modified=form_modified,\n            form_resubmit=form_resubmit,\n            ajax_noresponse=ajax_noresponse,\n        )\n", "path": "Products/CMFPlone/browser/jsvariables.py"}]}