fiorix / freegeoip

IP geolocation web server
Other
4.94k stars 793 forks source link

Enable CORS on server #170

Closed Moinax closed 7 years ago

Moinax commented 8 years ago

Hi,

I would like to access your public API through a web application written in full JS.

In this case, you need to enable CORS on the server.

See http://enable-cors.org/ for more information.

Do you think you will be able to enable this on your public API ?

Regards,

fiorix commented 8 years ago

It already supports CORS.

Moinax commented 8 years ago

I don't get it, I mean if I call http://freegeoip.net/json/ I don't receive any CORS headers.

I got an error in Chrome console:

XMLHttpRequest cannot load http://freegeoip.net/json/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 405.

The only headers I can see in your response are:

Content-Length:19 Content-Type:text/plain; charset=utf-8 Date:Mon, 02 May 2016 17:55:22 GMT X-Content-Type-Options:nosniff

Thank you in advance for your time

fiorix commented 8 years ago

You have to include the Origin header in the request.

Moinax commented 8 years ago

I always have an Origin Header which is controlled by the browser.

Here you can find all the request headers:

Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:fr,en-US;q=0.8,en;q=0.6
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
Host:freegeoip.net
Origin:http://localhost:3000
Pragma:no-cache
Referer:http://localhost:3000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36

As a public API, you should return this header :

Access-Control-Allow-Origin: *

fiorix commented 8 years ago

https://jsfiddle.net/envf0sku/

Moinax commented 8 years ago

Damn, I see why it was not working on my side.

For our own API, my client has to specify the Content-Type to "application/json", and changing this requires that the server answer with an OPTIONS response, which you don't have on your side of course.

So I just remove the Content-Type for this call only, and it works like a charm.

Sorry for your waste of time and thank you for your prompt answers.

Regards,

fiorix commented 8 years ago

No worries, good luck ;)

alemela commented 8 years ago

@fiorix I'm trying your fiddle with Firefox (both 47 and 48) but doesn't work. Ok with Chrome. How to deal with FF?

fiorix commented 8 years ago

Never tried FF with this, if you have more info I can investigate.

sdn90 commented 8 years ago

I was getting this error because of using the URL without a trailing slash. Added a trailing slash and everything started working fine.

When using the URL without a slash, the server responds with a 301 status code.

apotek commented 8 years ago

If I start the servers with -cors-origin * the server will allow requests from any domain and satisfy the client's security model (chrome and firefox).

If I start the server with -cors-origin www.mydomain.com the server will allow requests from the specified domain and satisfy the client's security model (chrome and firefox).

If I want to limit access to the API (ie, not send a * as allowed origin), but have more than one domain to allow, there seems to be no facility for specifying this. -cors-origin my.domain.comi my.seconddomain.com will not work.

The topic of multiple whitelisted domains is here: http://stackoverflow.com/questions/1653308/access-control-allow-origin-multiple-origin-domains

Clearly, CORS is not intended to be used on the server side as a way of fully blocking access to services, and I suppose what I need to do is set a load balancer in front that drops all requests that don't have the correct origin header (though of course this can be spoofed), but I am tagging along on this thread wondering if there is something in help documentation output of docker run --rm -it fiorix/freegeoip --help I am missing. I would like to be able to set the option like this: -cors-origin *.mydomain1.com *.myseconddomain.com ... and have the freegeoip then implement something along the line of: if incoming_request_origin is in the passed list of -cors-origins, then return header access-control-allows-origin: incoming_request_origin

This would be the nginx implementation:

$http_origin = $_SERVER['HTTP_ORIGIN'];

if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.info")
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

When I look at the config structure it looks like it was built with -cors-origin as a string value only, and I see no place where it would be broken into a list of domains or origins, which is why I assume it's not possible.

akuji1993 commented 7 years ago

In case someone needs another approach, in our case, working with fetch-safe from npm, this works:

let url = 'https://freegeoip.net/json/'; let headers = new Headers({}); fetch(url, {headers}) .then(res => res.json()) }, (err) => { ... });

fiorix commented 7 years ago

This doesn't seem to be going anywhere. We support CORS already.

uris-dev commented 7 years ago

Another reason for the service not to work is the user having installed an ad blocker, since the site is on the exclusion lists to protect user tracking. Firefox returns a similar exception as when CORS headers are missing, but of course it doesn't makes any requests.

fiorix commented 7 years ago

👍

michaelpumo commented 7 years ago

As @uris-dev says - check your adblocker is disabled. I just spent a few hours trying to work this out, only to realise it was uBlock causing the issue. The following should work just fine:

fetch('http://freegeoip.net/json/')
  .then(response => response.json())
  .then(data => {
    console.log(data);
  });
duoduoxia commented 7 years ago

if you have authorization in request header, remove it to avoid preflight. This solved the same problem for me.

zackify commented 7 years ago

Cors error with fetch. Add empty headers object, it works.

let response = await fetch('https://freegeoip.net/json/', { headers: {} });
karendolan commented 4 years ago

I was getting this error because of using the URL without a trailing slash. Added a trailing slash and everything started working fine.

When using the URL without a slash, the server responds with a 301 status code.

Adding the trailing slash to a resource request worked for me to avoid the CORS error with Safari. Why is that? Why does Safari care but Chrome & Firefox don't need the trailing slash?