Ajax.Request fails, while vanilla XHR works fine

216 views
Skip to first unread message

Walter Lee Davis

unread,
Apr 10, 2012, 10:50:10 PM4/10/12
to prototype-s...@googlegroups.com
Same browser (Safari.latest) on the same computer, the Prototype method gives me a security failure (Origin [my host] is not allowed by Access-Control-Allow-Origin.) while the long-hand XHR (inside a Prototype observer) just works without any comment:

Prototype:
$('zip').observe('change',function(evt){
var elm = this;
new Ajax.Request('http://zip.elevenbasetwo.com', {
method: 'get',
parameters: {zip: $F(elm)},
onComplete: function(transport){
var data = responseText.evalJSON();
$('city').setValue(data.city);
$('state').setValue(data.state);
}
});
});

XHR:
$('zip').observe('change',function(evt){
var client = new XMLHttpRequest();
client.open("GET", "http://zip.elevenbasetwo.com?zip=" + $F(this), true);
client.onreadystatechange = function() {
if(client.readyState == 4) {
var data = client.responseText.evalJSON();
$('city').setValue(data.city);
$('state').setValue(data.state);
};
};
client.send();
});

I don't trust this to work in the range of browsers supported by Prototype, naturally, so I'd really like to know what I could do to get it to work in Prototype.

Thanks,

Walter

Walter Lee Davis

unread,
Apr 10, 2012, 10:52:48 PM4/10/12
to prototype-s...@googlegroups.com
Typo, fixed; still fails, same error, before ever reaching this line.

On Apr 10, 2012, at 10:50 PM, Walter Lee Davis wrote:

> var data = responseText.evalJSON();

s/b var data = transport.responseText.evalJSON();

Walter

Jason

unread,
Apr 11, 2012, 9:00:04 PM4/11/12
to Prototype & script.aculo.us

Have you tried to just use

new Ajax.Request('index.php', .........);

vs the full URL

from the Ajax.Request source code

* - url (String): The URL to fetch. When the _same-origin_ policy is
in
* effect (as it is in most cases), `url` **must** be a relative URL or
an
* absolute URL that starts with a slash (i.e., it must not begin with
* `http`).

Walter Lee Davis

unread,
Apr 11, 2012, 11:01:19 PM4/11/12
to prototype-s...@googlegroups.com
I understand the SOP, I was wondering why it worked when I violated SOP from a hard-coded XHR request. Under the hood, it is my understanding that Prototype sets up a very similar XHR request anyway. It doesn't make any sense that the one would work while the other did not. This server is specifically kinked to allow a request such as this, or else the SOP would cause it to fail no matter what. Can anyone point out the flaw in my logic here?

Walter

> --
> You received this message because you are subscribed to the Google Groups "Prototype & script.aculo.us" group.
> To post to this group, send email to prototype-s...@googlegroups.com.
> To unsubscribe from this group, send email to prototype-scripta...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/prototype-scriptaculous?hl=en.
>

Victor

unread,
Apr 12, 2012, 12:14:51 PM4/12/12
to prototype-s...@googlegroups.com
Same browser (Safari.latest) on the same computer, the Prototype method gives me a security failure (Origin [my host] is not allowed by Access-Control-Allow-Origin.) while the long-hand XHR (inside a Prototype observer) just works without any comment:


Two differences I can notice:
1. Prototype sets request headers 'X-Requested-With', 'X-Prototype-Version', 'Accept' with setRequestHeaders() - you don't
2. Prototype calls send with null argument
    this.transport.send(null); // Prototype
vs
    client.send(); // your raw XHR

If you can test your code with these two changes - will it raise error?

  $('zip').observe('change', function(evt) {

    var client = new XMLHttpRequest();
    client.open("GET", "http://zip.elevenbasetwo.com?zip=" + $F(this), true);
    client.onreadystatechange = function() {
      if(client.readyState == 4) {
        var data = client.responseText.evalJSON();
        $('city').setValue(data.city);
        $('state').setValue(data.state);
      };
    };
    client.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    client.setRequestHeader('X-Prototype-Version', '1.7');
    client.setRequestHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
    client.send(null);
  });

Victor

unread,
Apr 12, 2012, 12:20:29 PM4/12/12
to prototype-s...@googlegroups.com
Is header 'Access-Control-Allow-Origin' present in responses for both examples?

Walter Lee Davis

unread,
Apr 12, 2012, 3:57:01 PM4/12/12
to prototype-s...@googlegroups.com

Thanks very much for the suggestion. It looks as though ANY setRequestHeader invocation at all is enough to scuttle the request. I tried commenting one, then two, then all of them out. Without those three lines, the request works fine -- even with the null in the send. But add any one of them back, and the request fails. It seems to be an issue on their server (BaseHTTP/0.3 Python/2.7.1+ according to FireBug). I'll file a bug and see what happens.

Walter

Victor

unread,
Apr 13, 2012, 5:26:06 AM4/13/12
to prototype-s...@googlegroups.com

It seems to be an issue on their server (BaseHTTP/0.3 Python/2.7.1+ according to FireBug). I'll file a bug and see what happens.

XHR without setRequestHeader sends usual 'GET' request:

Request URL: http://zip.elevenbasetwo.com/?zip=a
Request Method: GET
Status Code: 404 Not Found
Request Headers
Accept: */*
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.3
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Connection: keep-alive
Host: zip.elevenbasetwo.com
Origin: https://groups.google.com
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19
Response Headers
Access-Control-Allow-Origin: *
Connection: close
Content-Type: text/plain
Date: Fri, 13 Apr 2012 09:16:07 GMT
Server: BaseHTTP/0.3 Python/2.7.1+

XHR with any setRequestHeader sends first 'OPTIONS' request (so-called preflight):

Request URL: http://zip.elevenbasetwo.com/?zip=a
Request Method: OPTIONS
Status Code: 501 Not Implemented
Request Headers
Accept: */*
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.3
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Access-Control-Request-Headers: x-xxx, origin
Access-Control-Request-Method: GET
Connection: keep-alive
Host: zip.elevenbasetwo.com
Origin: https://groups.google.com
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19
Response Headers
Connection: close
Content-Type: text/html
Date: Fri, 13 Apr 2012 09:20:32 GMT
Server: BaseHTTP/0.3 Python/2.7.1+

It seems that some browsers (like Firefox and WebKit-based) may send CORS requests without preflight for text/plain resources when no additional headers are set. In other cases they send preflighted 'OPTIONS' request, which is not implemented in this 'BaseHTTP/0.3 Python/2.7.1+' server.

Walter Lee Davis

unread,
Apr 13, 2012, 8:28:35 AM4/13/12
to prototype-s...@googlegroups.com
Thanks very much for the added detail. I filed an issue on the Github project for the Python server, and within hours another Githubber had posted a pull request fixing the bug. The server was just not aware of what to do if it got such an OPTIONS request, so it was falling over.

Walter

On Apr 13, 2012, at 5:26 AM, Victor wrote:

> It seems to be an issue on their server (BaseHTTP/0.3 Python/2.7.1+ according to FireBug). I'll file a bug and see what happens.
>
> XHR without setRequestHeader sends usual 'GET' request:
>
> Request URL: http://zip.elevenbasetwo.com/?zip=a
> Request Method: GET

> Status Code: 404 Not Found


> Request Headers
> Accept: */*
> Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.3
> Accept-Encoding: gzip,deflate,sdch
> Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
> Connection: keep-alive
> Host: zip.elevenbasetwo.com
> Origin: https://groups.google.com
> User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19
> Response Headers
> Access-Control-Allow-Origin: *
> Connection: close
> Content-Type: text/plain
> Date: Fri, 13 Apr 2012 09:16:07 GMT
> Server: BaseHTTP/0.3 Python/2.7.1+
>
> XHR with any setRequestHeader sends first 'OPTIONS' request (so-called preflight):
>
> Request URL: http://zip.elevenbasetwo.com/?zip=a
> Request Method: OPTIONS

> Status Code: 501 Not Implemented


> Request Headers
> Accept: */*
> Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.3
> Accept-Encoding: gzip,deflate,sdch
> Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
> Access-Control-Request-Headers: x-xxx, origin
> Access-Control-Request-Method: GET
> Connection: keep-alive
> Host: zip.elevenbasetwo.com
> Origin: https://groups.google.com
> User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19
> Response Headers
> Connection: close
> Content-Type: text/html
> Date: Fri, 13 Apr 2012 09:20:32 GMT
> Server: BaseHTTP/0.3 Python/2.7.1+
>
> It seems that some browsers (like Firefox and WebKit-based) may send CORS requests without preflight for text/plain resources when no additional headers are set. In other cases they send preflighted 'OPTIONS' request, which is not implemented in this 'BaseHTTP/0.3 Python/2.7.1+' server.
>

> --
> You received this message because you are subscribed to the Google Groups "Prototype & script.aculo.us" group.

> To view this discussion on the web visit https://groups.google.com/d/msg/prototype-scriptaculous/-/6xIQrvgSIqsJ.

Reply all
Reply to author
Forward
0 new messages