Folder_contents not targeting proper site

Hi,

I have two plone 5.2.4 sites.

Site1: http://sites.example.com/
Site2: http://sites.example.com/site2

Everything is working except folder_contents is broken for Site2. On Site2 I can see folder_contents is calling @@getVocabulary on the Site1.

I can see FolderContentsView is calling get_top_site_from_url which is jumping over to site1 instead of staying in site2.

I have virtualhosting setup and as I said, everything else is working perfect. Just not this one thing.

Example:

<VirtualHost *:80>
    ServerName sites.example.com
    ServerSignature On
    AllowEncodedSlashes NoDecode

    Header set X-Frame-Options "SAMEORIGIN"
    Header set Strict-Transport-Security "max-age=15768000; includeSubDomains"
    Header set X-XSS-Protection "1; mode=block"
    Header set X-Content-Type-Options "nosniff"
    Header set Content-Security-Policy-Report-Only "default-src 'self'; img-src *; style-src 'unsafe-inline'; script-src 'unsafe-inline' 'unsafe-eval'"

    ProxyVia On

    # prevent your web server from being used as global HTTP proxy
    <LocationMatch "^[^/]">
        Deny from all
    </LocationMatch>

    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    RewriteEngine on
    RewriteRule ^/(.*) http://localhost:6081/VirtualHostBase/http/%{SERVER_NAME}:80/site1/VirtualHostRoot/$1 [P,L]
    RewriteRule ^/site2(.*) http://localhost:6081/VirtualHostBase/http/%{SERVER_NAME}:80/site2/VirtualHostRoot/$1 [P,L]

    ProxyPreserveHost On

</VirtualHost>

Any ideas? Thanks.

What is site2? A Plone site within a Plone site?

Two plone sites side by side. Not a site within a site.

Exposing site2 under the same domain appears broken. Either you use
siteX.example.com for each site or example.com/siteX. Your problem might be a side-effect of your configuration.

You are missing an expression in your VirtualHostMonster rewrite line. If site2 is mounted in a subfolder on the domain, you need to pass the vh directive as well. Otherwise the url in the pages/content served from Zope will be rewritten to the root level of your domain, where the first site is being served. (which is what you observe in some cases).

From memory, but please look up the correct syntax, I'm not sure if it needs a slash at the end:

    RewriteRule ^/site2(.*) http://localhost:6081/VirtualHostBase/http/%{SERVER_NAME}:80/site2/VirtualHostRoot/_vh_site2 $1 [P,L]
1 Like

Almost surely, this is "Plone should not assume non existence of an "ISite" above a Plone portal · Issue #3157 · plone/Products.CMFPlone · GitHub". Plone (wrongly) assumes the the portal object is a top "site".

First I would like to state I really appreciate you all helping.

I use to have my rewrite rules like that. When I switch the expression in the VHM to what you suggested for site2.

RewriteRule ^/(.*) http://localhost:6081/VirtualHostBase/http/%{SERVER_NAME}:80/site1/VirtualHostRoot/$1 [P,L]    
RewriteRule ^/site2($|/.*) http://localhost:6081/VirtualHostBase/http/%{SERVER_NAME}:80/site2/VirtualHostRoot/_vh_site2$1 [L,P]

The folder_contents is still targeting site1. I then tried both

RewriteRule ^/($|/.*) http://localhost:6081/VirtualHostBase/http/%{SERVER_NAME}:80/site1/VirtualHostRoot/_vh_site1$1 [L,P]
RewriteRule ^/site2($|/.*) http://localhost:6081/VirtualHostBase/http/%{SERVER_NAME}:80/site2/VirtualHostRoot/_vh_site2$1 [L,P]

Now site1 won't load under the domain without a /site1 path.

Thanks,
David

That has to be what I am seeing! Thank goodness it wasn't just me. Everything else in Plone is working fantastic, just the folder_contents is getting messed up because it is assuming the portal object is the top of the path/domain structure.

Looking at the get_top_site_from_url() function in util.py, I could see a simple temporary fix just to confirm the suspicion.

I changed
for idx in range(len(url_path))
to
for idx in reversed(range(len(url_path)))

This was just temporary to make sure it wouldn't assume the first hit was the correct one but backwalk on it. Yep, everything then worked as expected.

I might have to just "monkey patch" that function for now. Not reversed like I tested it, keep it almost 100% original but then check one level deeper to ensure the top site was not the almighty assumed site.

Thanks everyone.

David

UPDATE

I did a small patch on my server on the function in util.py with the code below and it resolved all my issues. If it finds a top site, it just checks once more one level deeper if another exists. I tried to not touch as much of the code as possible to avoid issues.

def get_top_site_from_url(context, request):
"""Find the top-most site, which is still in the url path.
If the current context is within a subsite within a PloneSiteRoot and no
virtual hosting is in place, the PloneSiteRoot is returned.
When at the same context but in a virtual hosting environment with the
virtual host root pointing to the subsite, it returns the subsite instead
the PloneSiteRoot.
For this given content structure:
/Plone/Subsite
It should return the following in these cases:
- No virtual hosting, URL path: /Plone, Returns: Plone Site
- No virtual hosting, URL path: /Plone/Subsite, Returns: Plone
- Virtual hosting roots to Subsite, URL path: /, Returns: Subsite
"""
site = getSite()
try:
    url_path = urlparse(context.absolute_url()).path.split('/')
    
    _site_found = None
    for idx in range(len(url_path)):
        _path = '/'.join(url_path[:idx + 1]) or '/'
        site_path = request.physicalPathFromURL(_path)
        
        if six.PY2:
            site_path = safe_encode('/'.join(site_path)) or '/'
        else:
            site_path = '/'.join(site_path) or '/'
        _site = context.restrictedTraverse(site_path)

        if _site_found:
            if ISite.providedBy(_site):
                _site_found = _site
            break

        if ISite.providedBy(_site):
            _site_found = _site

    if _site_found:
        site = _site_found


except (ValueError, AttributeError):
    # On error, just return getSite.
    # Refs: https://github.com/plone/plone.app.content/issues/103
    # Also, TestRequest doesn't have physicalPathFromURL
    pass
return site

What if you reverse these lines? Like this:

RewriteEngine on
RewriteRule ^/site2(.*) http://localhost:6081/VirtualHostBase/http/%{SERVER_NAME}:80/site2/VirtualHostRoot/$1 [P,L]
RewriteRule ^/(.*) http://localhost:6081/VirtualHostBase/http/%{SERVER_NAME}:80/site1/VirtualHostRoot/$1 [P,L]

also you've to set the vh as suggested above.