Hello,
I have a need to integrate the services module in a mobile app I am currently buried in. First, let me say just how amazing it is that so much hard work has been done to the nginx config to support specific modules and caching. It's absolutely incredible.
Anyway, I need to make cross-domain requests to my barracuda instance, and these requests will be handled by the server. However, I cannot get my barracuda instance to allow other domains via CORS. I have tried multiple nginx configs, but I believe this is as close as I have come.
First, I see that nginx is denying OPTIONS requests. So I added OPTIONS to the list of allowed request methods by changing:
if ( $request_method !~ ^(?:GET|HEAD|POST|<strong>OPTIONS</strong>)$ ) {
return 444;
}
Then, under "location /", I modified it to read:
###
### Catch all unspecified requests.
###
location / {
if ( $http_user_agent ~* wget ) {
return 444;
}
try_files $uri @cache;
# For CORS
if ($request_method = OPTIONS ) {
add_header Access-Control-Allow-Origin "*"; ### <<< I hope it accepts wildcards
add_header Access-Control-Allow-Methods "POST, GET, OPTIONS"; ###<<< Is this overwriting the previous directive?
add_header Access-Control-Allow-Headers "Authorization"; ### <<< Not sure if I need this
add_header Access-Control-Allow-Credentials "true"; ### <<< Once again, might need it later.
add_header Content-Length 0; ### <<< ???
add_header Content-Type text/plain; ### <<< ??? Isn't json/jsonp application/json?
return 200;
}
}
Has anyone been able to, well, enable this on a barracuda instance before? I think this is going to become more common in the future, as we can already see certain browsers needing their hand held for @font-face and other cross-domain requests.
Just in case, my actual error in chrome's console is:
XMLHttpRequest cannot load http://www.DOMAIN.TLD/system/connect.jsonp. Origin http://localhost is not allowed by Access-Control-Allow-Origin
Thanks.
| Comment | File | Size | Author |
|---|---|---|---|
| #15 | nginx_modification_for_CORS-1524738-15.patch | 1 KB | flexgrip |
Comments
Comment #1
omega8cc commentedThe problem is not only missing header (or headers), but the fact that you can use add_header only in the
locationcontext, so it will never work inside anif{}block. Maybe just try to add onlyadd_header Access-Control-Allow-Origin "*";directly there, outside ofif{}first and see if that helps.Comment #2
flexgrip commentedThanks for the quick response.
I just tried breaking the add_header directive out of the if statement, like so.
Unfortunately I cannot get it to work. Just to be clear, I saw that /var/aegir/config/includes/nginx_modern_include.conf was being included in all of my vhosts, so that is where I am putting it. After ever save of that nginx_modern_include.conf file, I am doing an nginx reload, stop, and start.
But no matter what I try, this is the error from Chrome:
XMLHttpRequest cannot load http://domain.tld/wineries/system/connect.jsonp. Origin http://localhost is not allowed by Access-Control-Allow-Origin.Is there somewhere else I need to be putting this for each vhost as well, since that is a global file? Is there any other place it could be being overridden?
Comment #3
omega8cc commentedCould you post the result of:
curl -I http://domain.tld/wineries/system/connect.jsonpThanks.
Comment #4
omega8cc commentedNote that there are also separate locations for
systemandjsonso depending on where the rewrites etc terminate, you may need to add it also there. Thecurl -Itest will show you if the expected header has been sent as expected.Comment #5
omega8cc commentedAlso, you should do that only it this one include file, which is included in the affected vhosts.
Comment #6
omega8cc commentedProbably related: #1472460: Nginx configuration denies HTTP request methods PUT DELETE and OPTIONS.
Comment #7
flexgrip commentedAlthough the result in two different browsers is the same error... Returns 301 w/ "Origin http://localhost is not allowed by Access-Control-Allow-Origin"
I looked through that other ticket. It would seem that my OPTIONS method is being blocked by something. However, I see exactly where you guys are doing that in the nginx config. I added OPTIONS as an allowed method.
I'm completely baffled at this point. It must be being overridden somewhere. My experience with nginx is literally this server. So I'm pretty fresh. I knew Apache well enough to get this solved a long time ago.
Comment #8
omega8cc commentedThanks. This result suggests that it is terminated in this location:
location ~* /(?:external|system|files/imagecache|files/styles)/Please try to add that required header there and reload Nginx.
Comment #9
flexgrip commentedNo dice.
I was looking at the different config files... modern, advanced, compact.
Is the add_header option smart enough to know if I add the same headers twice, to only include it once? Or is it truly split by each location *?
Comment #10
omega8cc commentedIt should be only in one location and you should see it in the header response.
You could try to add it outside of any location, just at the top of the include file.
Comment #11
flexgrip commentedI think I got it!
Add OPTIONS to the allowed request methods...
And then in the /index.php section (I still can't figure out why it needs to be added here, I tried almost every relevant section and this was the only one that worked.)
Now, after all of this, I still don't think this is the "right" way to do it. There is no reason it should be in the index.php section. At least with the way I am thinking of it, it should be in the ~* section and also something would have to change in the section where you control "system" paths because the services module uses /servicename/system/ for connections.
Any thoughts?
Comment #12
omega8cc commentedIf this is the location where it works, then this is the final location where request arrives. It could be terminated in some of above locations only when it is not send internally to @drupal and finally to /index.php, but if it is, then any headers added above will be always ignored.
I will submit a patch shortly.
Thanks for debugging!
Comment #13
flexgrip commentedI actually made a patch against STABLE for it. Although I'm unsure if anything has changed in HEAD.
Comment #14
omega8cc commentedPlease try your patch with head then and submit for review. Thanks!
Comment #15
flexgrip commentedHere is the patch that adds OPTIONS as an allowed request method (I think that should be on by default, but its up to you) and the header for origin and the "X-Requested-With" in the right section. Those are commented out by default, because after thinking about it, its obviously not a good idea to turn on cross-origin requests by default. The X-Requested-With flag is there because, if they are turning on CORS, there is a 99% change they are going to need and use X-Requested-With. Especially since I've heard chatter of Mozilla requiring it soon.
I'm not sure about your comment styles... I tried to match them. Hope this helps.
Comment #16
omega8cc commentedWe can add
OPTIONSas allowed by default, but the rest will not be really useful when included as commented out because then the (default) result will be the same as it is now, and any changes will be overwritten on upgrade or server node re-verify.We could introduce another include, as we did already above: http://drupalcode.org/project/barracuda.git/blob/HEAD:/aegir/conf/nginx_... so any extra config there will survive during upgrade.
Or maybe we could add some extra locations trick with local termination to pass correct headers only when they are really required/expected, but then how to define such location? Is there any regex matching we could use? I have no idea if all URLs requiring those headers end with
.jsonpalways?Comment #17
flexgrip commentedNo they don't always end with .jsonp. In fact, even among the services module they can have multiple different ways of formatting the url.
Also, another HUGE problem. My patch above is worthless in multiple ways. Not only is it not formatted right, but it doesn't even work. Something was going on the day I tested it, and it seemed to be spitting out jsonp the way I needed it to. But I found out that it wasn't the case. In the services module, when I enable the rest server, I still get a screwed up return error saying that Origin http://localhost is not allowed by Access-Control-Allow-Origin. So I'm back to square one.
I will continue to mess with it, but for now, I'm going to change the development environment for this app so I can at least continue working on it and do not have to wait to enable CORS.
At this point, I've added the config options to just about every spot in that nginx_modern_config. And its simply not working. I am open to ideas, but I feel kind of like it is being overwritten or blocked somewhere else.
Comment #18
omega8cc commentedWe will at least change the main config to allow services/REST specific request methods: #1472460: Nginx configuration denies HTTP request methods PUT DELETE and OPTIONS.
It is not overwritten anywhere, so you will be able to test this setup further, I hope. Let us know when you will find the source of the problem.
Comment #19
flexgrip commentedJust throwing this out there. It may be a bad idea so fire away if so. But I was thinking about this, and a few other configuration options that I needed to change specific to the services api in drupal (I am running into some issues with nginx caching json responses with services api... yeah I know it doesn't make sense but it seems to be happening). But most of these changes really don't need to be on by default, for security's sake.
So what if I made a stand-alone module, or forked provision/barracuda, that would allow you to turn these options on on a per-site basis while, well, provisioning them. That, or at least some functionality for the entire platform to adjust the settings accordingly. Even if it was platform specific, and we just had an installation profile for it.
Maybe I'm wrong, but I see more and more use for cross-origin requests, and usable services api with these mobile apps and even new html5 specs (we already saw it with IE and fonts). I don't think that every site you provision on aegir needs to have these options, but it would be a nice thing to have when you are using octopus to slam out a bunch of instances and platforms that will be doing advanced ajax and cross-origin stuff.
Just an idea... As always, I'm more worried about where to put it than how to implement it.
Comment #20
omega8cc commentedWhat we need to know is: do we need to add the ability to include extra config in the
/index.phplocation as we did already for other locations/rewrites here: http://drupalcode.org/project/barracuda.git/blob/HEAD:/aegir/conf/nginx_... ? I think yes, but since your results were inconsistent, I'm not sure if this helps or not. Maybe the already existing ability to add extra locations above is enough, as you can do whatever you want there, but maybe it is not enough.Comment #21
omega8cc commentedComment #22
omega8cc commentedClosing due to the lack of feedback for a long time. Feel free to reopen if you see fit.