1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Fixed Use absolute URLs with AJAX requests

Discussion in 'Resolved Bug Reports' started by digitalpoint, Dec 30, 2011.

  1. digitalpoint

    digitalpoint Well-Known Member

    I've successfully set up different parts of XF on different sub-domains without needing to make any file edits... except for one.

    If you are on a sub-domain, AJAX requests will fail (for example when looking at the Alerts drop-down) because XF sets the <base> to be the "primary" sub-domain based on HTTP headers.

    XF seems to always do AJAX requests via a relative URL (which adheres to the <base> tag. The problem is how browsers treat an AJAX request to a different sub-domain the same as a completely different primary domain... so the browser makes an HTTP request to the server with the OPTIONS method to check if it's allowed to make the *actual* request.

    I went down the road of setting the server up to answer the OPTIONS/origins requests properly, but the problem is even when you use the "Access-Control-Allow-Credentials" header, not all browsers support it, so cookies don't get sent with the cross-domain AJAX request (no cookies means no logged in user for that request).

    Thankfully, XF routes all AJAX requests through a single method so I was able to just prepend the *actual* hostname to the AJAX URL to make it work with a single file edit.

    But... considering AJAX will always fail unless it's sent to the current sub-domain the request originated from, wouldn't it make sense to just prepend window.location protocol, and host to the AJAX URL before it's processed? The relative AJAX URLs being routed to the sub-domain specified in <base> won't fail.

    http://en.wikipedia.org/wiki/Same_origin_policy
    https://developer.mozilla.org/En/HTTP_access_control
     
    mrGTB likes this.
  2. Mike

    Mike XenForo Developer Staff Member

    First I should note, that by default, the base tag should be pointing to your sub-domain, unless your web server isn't exposing the correct stuff. Though I'm assuming that you want to override that and have it point to the primary domain.

    window.location won't take into account the "real" XF root (for rewritten URLs), so that won't really work. The only thing we could really do is provide a JS variable that overrides the base tag for URL canonicalization.
     
  3. digitalpoint

    digitalpoint Well-Known Member

    Yes, by default XF always points to the sub-domain you are on because it uses the $_SERVER['HTTP_HOST'] global. In order to get sub-domains working without editing any core XF php files, I'm exploiting a couple things here, so I'll explain exactly what I'm doing...

    The base URL is calculated by XenForo_Application::getRequestPaths(). If HTTP_HOST isn't set, it will fall back to SERVER_NAME.

    Normally routes are calculated based on REQUEST_URI, but Zend_Controller_Request_Http::setRequestUri() first checks a couple other things... in my case, I'm exploiting the fact it looks for HTTP_X_REWRITE_URL first.

    Putting it all together...

    In my config.php file, I'm first checking the sub-domain the request is on... if the sub-domain is not the normal base installation of my XF, I'm doing this:
    PHP:
    $_SERVER['HTTP_X_REWRITE_URL'] = '/subdomain-' $subdomain $_SERVER['REQUEST_URI'];
    So then I can have a route that is named subdomain-xxxxx where xxxxx is the sub-domain, and the route action is the URI. For example http://tools.digitalpoint.com/geovisitors internally is hitting the route of "subdomain-tools/geovisitors".

    In the config.php I also do this:
    PHP:
    unset ($_SERVER['HTTP_HOST']);
    It allows the route calculation to be based on HTTP_X_REWRITE_URL but at the same time allows the base (and links with full URLs) to still be set properly because it will fallback to SERVER_NAME.

    So in the end I have the page generated on the sub-domain with the base set to the primary URL of the XF install (exactly what I want so that links in things like the navigation still work properly).

    The only issue I've run into is the AJAX request stuff being based on BASE instead of window.location (since the nature of AJAX requests will make that fail for security reasons).

    What I did to fix it was in xenforo.js, is exactly that (overriding canonicalization) I changed this:

    Code:
    canonicalizeUrl: function(url)
    {
    	if (url.indexOf('/') == 0)
    	{
    		return url;
    	}
    		else if (url.match(/^https?:/i))
    	{
    		return url;
    	}
    		else
    	{
    		return $('base').attr('href') + url;
    	}
    },
    to this:

    Code:
    canonicalizeUrl: function(url, useWindowLocation)
    	{
    		if (url.indexOf('/') == 0)
    	{
    		return url;
    	}
    	else if (url.match(/^https?:/i))
    	{
    		return url;
    	}
    		else if (useWindowLocation)
    	{
    		return window.location.protocol + '//' + window.location.host + window.location.pathname + url;
    	}
    	else
    	{
    		return $('base').attr('href') + url;
    	}
    },
    Then I'm using XenForo.canonicalizeUrl in the beginning of XenForo.ajax (it appears all URLs passed to XenForo.ajax() are non-canonicalized, so it works.

    Bottom line is that if an AJAX request is *ever* made to something other than window.location, it will fail... it just so happens that *normally* BASE = window.location, so it's okay.

    As it is now, I can get XF stuff 100% working on sub-domains (base being set properly, routes working, etc.) without editing the PHP files. The only edit is the one shown in the JS.
     
  4. Mike

    Mike XenForo Developer Staff Member

    The problem is that window.location.pathname is more specific than the base URL and therefore won't be correct. (View a thread, echo it out, and you'll see what I mean.)

    However, I have created a JS variable XenForo.ajaxBaseHref that you can set and it will override canonicalizing Ajax requests with the base tag URL. It just needs to be set after xenforo.js is included, so you could set it in the JS at the end of the body.
     
    digitalpoint likes this.
  5. digitalpoint

    digitalpoint Well-Known Member

    Very much appreciated.

    I assume XenForo.ajax now spins the URL passed to it through the canonicalize function?
     
  6. Mike

    Mike XenForo Developer Staff Member

    Correct.
     
    digitalpoint likes this.
  7. digitalpoint

    digitalpoint Well-Known Member

    I don't know what the hell I'm going to do if I actually finish all the custom stuff I'm building and there ends up being zero file edits needed. lol
     
    Jeremy and yavuz like this.
  8. Jeremy

    Jeremy XenForo Moderator Staff Member

    Party like its 1699?

    (Anyone tells me that reference would get about 3,000 likes.)
     
  9. digitalpoint

    digitalpoint Well-Known Member

    It's from this:
     
    Jeremy likes this.
  10. Jeremy

    Jeremy XenForo Moderator Staff Member

    You sir, just made my day. Hahaha. I want to like and unlike that 3,000 times now, but won't spam you. :D
     
  11. digitalpoint

    digitalpoint Well-Known Member

    So noticed the quick navigation menu wasn't working on my dev setup (when on sub-domain)... The primary AJAX request was working, but then it was failing with a subsequent AJAX request for the CSS file.

    Will XenForo.ajaxBaseHref be applied to the scriptLoader() and loadCss() methods?
     

Share This Page