Repository: plone/Products.CMFPlone

Issue:
plone-upgrade to 5.0.3 shows plain text as result
This is caused by https://github.com/plone/plone.app.upgrade/pull/67 by @vangheem, though this change looks fine to me.

With the above change, when running `@@plone-upgrade`, even with dry-run selected, the result page is shown as text: you see plain html. Very strange. Reported here: https://community.plone.org/t/plone-5-0-3-soft-released/1699/4
When I empty the registry.xml, keeping only the main `registry` tags for safety, it all works fine. Keeping one of the two changed records, it again shows as text.

To check it:
- Use current coredev 5.0
- Create a Plone Site.
- Simulate a Plone 5.0.2 site: in portal_setup, Upgrades, select Products.CMFPlone:plone, and run the to502 upgrade profile.
- Go to @@plone-upgrade, optionally select dry-run, and run the upgrade.

Result: it will show as plain text.
BTW, afterwards, all is fine: the migration has succeeded and it looks like all pages show up fine.

Any idea?



Discussion:
BTW, if I copy-paste this plain html in a file and view it with a browser, it shows up just fine. I guess the registry.xml changes trigger a `text/plain` response header.

I can confirm this issue

I had another look. It is actually not `text/plain`, but `application/javascript`. The header is set here:

https://github.com/plone/Products.CMFPlone/blob/master/Products/CMFPlone/resources/browser/configjs.py#L97

With a pdb, this is the stack trace:

```
  /Users/maurits/community/plone-coredev/5.0/src/plone.app.upgrade/plone/app/upgrade/v50/final.py(97)to503()
-> loadMigrationProfile(context, 'profile-plone.app.upgrade.v50:to503')
  /Users/maurits/community/plone-coredev/5.0/src/plone.app.upgrade/plone/app/upgrade/utils.py(134)loadMigrationProfile()
-> context.runAllImportStepsFromProfile(profile, purge_old=False)
  /Users/maurits/shared-eggs/Products.GenericSetup-1.8.2-py2.7.egg/Products/GenericSetup/tool.py(379)runAllImportStepsFromProfile()
-> dependency_strategy=dependency_strategy)
  /Users/maurits/shared-eggs/Products.GenericSetup-1.8.2-py2.7.egg/Products/GenericSetup/tool.py(1414)_runImportStepsFromContext()
-> message = self._doRunImportStep(step, context)
  /Users/maurits/shared-eggs/Products.GenericSetup-1.8.2-py2.7.egg/Products/GenericSetup/tool.py(1226)_doRunImportStep()
-> return handler(context)
  /Users/maurits/community/plone-coredev/5.0/src/Products.CMFPlone/Products/CMFPlone/resources/exportimport/bundles.py(19)combine()
-> combine_bundles(site)
  /Users/maurits/community/plone-coredev/5.0/src/Products.CMFPlone/Products/CMFPlone/resources/browser/combine.py(107)combine_bundles()
-> write_js(context, production_folder, 'default')
  /Users/maurits/community/plone-coredev/5.0/src/Products.CMFPlone/Products/CMFPlone/resources/browser/combine.py(59)write_js()
-> registry.records['plone.resources.configjs'].value))
  /Users/maurits/community/plone-coredev/5.0/src/Products.CMFPlone/Products/CMFPlone/resources/browser/combine.py(43)get_resource()
-> return resource()
  /Users/maurits/community/plone-coredev/5.0/src/Products.CMFPlone/Products/CMFPlone/resources/browser/configjs.py(97)__call__()
-> "application/javascript")
```

So when the bundles import step needs to do something (as in the condition in this line: https://github.com/plone/Products.CMFPlone/blob/master/Products/CMFPlone/resources/exportimport/bundles.py#L17) it has the side effect of making the plone-upgrade result page show up as plain text.

@ebrehault is this something you can take a look at, since this is part of plip #1277?
Maybe pass an extra parameter around that prevents calling `setHeader`?

I wondered why I do not see this when doing the same upgrade in portal_setup. The reason is simple. I can see with a pdb that the header is set to `application/javascript` as well, but then GenericSetup does a redirect to the `manage_upgrades` page, and on this new request the header is normal again.


Resolving patch:
diff --git a/Products/CMFPlone/resources/exportimport/bundles.py b/Products/CMFPlone/resources/exportimport/bundles.py
--- a/Products/CMFPlone/resources/exportimport/bundles.py
+++ b/Products/CMFPlone/resources/exportimport/bundles.py
@@ -1,5 +1,6 @@
 from plone.registry.interfaces import IRegistry
 from zope.component import queryUtility
+from zope.globalrequest import getRequest
 
 from ..browser.combine import combine_bundles
 
@@ -16,4 +17,20 @@ def combine(context):
     body = context.readDataFile('registry.xml')
     if body and "IBundleRegistry" in body:
         site = context.getSite()
+        # Calling combine_bundles will have as side effect that the
+        # Content-Type header of the response is set to application/javascript,
+        # which we do not want.  So we reset it to the original at the end.
+        site = context.getSite()
+        request = getattr(site, 'REQUEST', getRequest())
+        if request is not None:
+            # Easily happens in tests.
+            orig_header = request.response.getHeader('Content-Type')
         combine_bundles(site)
+        if request is not None:
+            new_header = request.response.getHeader('Content-Type')
+            if new_header != orig_header:
+                if orig_header is None:
+                    # Setting it to None would result in the string 'None'.
+                    # So pick a saner one.
+                    orig_header = 'text/html'
+                request.response.setHeader('Content-Type', orig_header)


Test patch: