iOS 12 Safari : XMLHttpRequest cannot load due to access control checks - javascript

I'm trying to use EPSON TM L-90 printer for printing labels from Javascript SDK 4.1.0. The XHR post call with following header works well in iOS 11 but fails in iOS 12.
The 'access control allow origin' is set as * from EPSON printer.
Both preflight and POST request fails with this error.
EPSON Javascript Library has following code.
xhr.open("POST", address, true);
xhr.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xhr.setRequestHeader("If-Modified-Since", "Thu, 01 Jan 1970 00:00:00 GMT");
xhr.setRequestHeader("SOAPAction", '""');
xhr.onreadystatechange = function() {
// Check response
}
Any idea what could be the issue.?

Related

Stop image that is linked to in XHR response from being cached

I am using XHR to get some HTML. The HTML response contains an img-element, and this image is for some reason cached.
The server serves the image along with the following headers:
cache-control: no-cache, must-revalidate
content-security-policy: default-src 'self'; ...
content-type: image/png
date: Mon, 08 Oct 2018 03:41:00 GMT
expires: Sat, 26 Jul 1997 05:00:00 GMT
server: nginx (Ubuntu)
status: 200
strict-transport-security: max-age=30879000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
And XHR is used like this:
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
addToPage(xmlHttp.responseText);
}
};
xmlHttp.open("GET", url, true);
xmlHttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xmlHttp.send();
Example XHR response:
<h1>Title</h1>
<p>Stuff</p>
<img src="/captcha-generator">
It works as expected when not using XHR. For some reason the image gets cached when it's linked to from within the XHR response.
Why is the image cached, and how do I force the browser to fetch the new image?
I can of course append a unique parameters to break the cache,(eg. /captcha-generator?r={random-string} but I would like to avoid that.
In case of Development mode it is happing .So Incase of google crome go to right top
corner click on costomize and control google crome .then open with New inconginto window
for development mode

PhoneGap XHR responseText empty, status 0, CORS?

I have Android 4.0.4 and a PhoneGap 3.6.3 app that makes a synchronous XmlHttpRequest:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://myserver/myapp/api/ProgramOptions', false);
xhr.setRequestHeader("Accept","application/json");
xhr.send(null);
window.alert(xhr.responseType);
window.alert(xhr.readyState);
window.alert(xhr.statusText);
window.alert(xhr.status);
window.alert(xhr.responseText);
window.alert(xhr.getAllResponseHeaders());
When loading the web app in the browser, I get
""
4
"OK"
200
"{"success":true,data:[/*snip*/]}"
"Pragma:no-cache
Date:Tue, 17 Feb 2015 09:40:45 GMT
Content-Encoding:gzip
WWW-Authenticate:Negotiate oYG2MIGz/*snip*/
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
Persistent-Auth:false
Vary:Accept-Encoding
Content-Type:application/json; charset=utf-8
Access-Control-Allow-Origin:*
Cache-Control:no-cache
Content-Length:10586
Expires:-1"
When loading the phonegap app, I get
""
4
""
0
""
""
Does anyone know why that is? I already searched for status 0, but there's helluva lot of reasons, and none I found - except the cross-origin requests - comes with an empty responseText. But then, the config.xml contains <access origin="*" />, and, as you can see, the server also sends a Access-Control-Allow-Origin header, so there should be no issue with CORS!?

Msxml2.XMLHTTP.6.0 and HTTP 301 Moved Permanently Redirects

I am told that MsXML2 follows redirects. However I get a "HTTP 0" error from the script when accessing a URL that has moved.
The reason I need to make it work is because this is a Windows (Sidebar) Gadget used by 300 000 users. And I am moving the website, and want all calls for old versions to still go through.
This is the code simplified:
function MyHttpCall() {
var httpReq = new ActiveXObject("Msxml2.XMLHTTP.6.0");
httpReq.onreadystatechange = function() {
if (httpReq.readyState < 4) return;
if (httpReq.status != 200) alert("HTTP " + httpReq.status);
alert ("Houston we have contact");
}
httpReq.open("GET", myURL, true);
httpReq.setRequestHeader("Cache-Control", "no-store, no-cache, must-revalidate");
httpReq.setRequestHeader("Cache-Control", "post-check=0, pre-check=0");
httpReq.setRequestHeader("Pragma", "no-cache");
httpReq.setRequestHeader("If-Modified-Since", "Tue, 01 Jan 2008 00:00:00 GMT");
httpReq.send();
}
I assume this has to do with httpReq.status != 200, but I thought the readystatechange is continously firing events once state changes. Fire one for HTTP 301, and another one for HTTP 200.
Accoarding to a Microsoft article, cross-domain redirects are not allowed in MsXML. That could most possibly be the case.

How to modify Cookie from Ajax call

I have this code:
window.onload = function() {
document.cookie = 'foo=bar; expires=Sun, 01 Jan 2012 00:00:00 +0100; path=/';
var xhr = new XMLHttpRequest();
xhr.open("GET", "/showcookie.php",true);
xhr.setRequestHeader("Cookie", "foo=quux");
xhr.setRequestHeader("Foo", "Bar");
xhr.setRequestHeader("Foo", "Baz");
xhr.withCredentials = true;
var pre = document.getElementById('output');
xhr.onreadystatechange = function() {
if (4 == xhr.readyState) {
pre.innerHTML += xhr.responseText + "\n";
}
};
xhr.send(null);
};
and this /showcookie.php
<?php
print_r($_COOKIE);
?>
and it always show
Array
(
[Host] => localhost
[User-Agent] =>
[Accept] =>
[Accept-Language] => pl,en-us;q=0.7,en;q=0.3
[Accept-Encoding] => gzip,deflate
[Accept-Charset] => ISO-8859-2,utf-8;q=0.7,*;q=0.7
[Keep-Alive] => 115
[Connection] => keep-alive
[foo] => Baz
[Referer] =>
[Cookie] => foo=bar
)
Array
(
[foo] => bar
)
I'm using Firefox 3.6.13, Opera 11.00 and Chromium 9.0 on Ubuntu.
Is anybody have the same problem or maybe it's impossible to modify Cookie header.
The Cookie header is one of several which cannot be modified in an XMLHttpRequest. From the specification:
Terminate [execution of the setRequestHeader method] if header is a
case-insensitive match for one of the
following headers:
Accept-Charset
Accept-Encoding
Connection
Content-Length
Cookie
Cookie2
Content-Transfer-Encoding
Date
Expect
Host
Keep-Alive
Referer
TE
Trailer
Transfer-Encoding
Upgrade
User-Agent
Via
… or if the start of header is a
case-insensitive match for Proxy- or
Sec- (including when header is just
Proxy- or Sec-).
The above headers are controlled by
the user agent to let it control those
aspects of transport. This guarantees
data integrity to some extent. Header
names starting with Sec- are not
allowed to be set to allow new headers
to be minted that are guaranteed not
to come from XMLHttpRequest.
I think this might be a hard constraint on the XHR functionality.
Setting the clientside document.cookie caused the Cookie header to be sent in requests as expected. If you want to pass a cookie value in an an ajax request this might be the way to go.
A workaround is to send a custom header to the php script with the cookie string you want to set:
// in the js...
xhr.open("GET", "showcookie.php",true);
//xhr.setRequestHeader("Cookie", "foo=quux");
xhr.setRequestHeader("X-Set-Cookie", "foo2=quux");
xhr.withCredentials = true;
Then in your showcookie.php you can grab the custom header value and fire a set-cookie response header:
$cookie = $_SERVER['HTTP_X_SET_COOKIE'];
// NOTE: really should sanitise the cookie input.
header('Set-Cookie: ' . $cookie);
print_r($_COOKIE);
Note that you wont see a cookie header until the response is parsed by the browser. Also please make sure you sanitise the contents of the X_SET_COOKIE header - this is a proof of concept only:)

Please help test a CORS issue in Firefox jQuery ajax when 401

this is driving me nutters.
jQuery 1.4.2, windows XP sp3
Here is my test.
Load firefox 3.5+
http://plungjan.name/test/testcors.html
works
Save the file to harddisk and run from there
From my office the external works and the internal does not
What is also interesting is that I cannot run both in one go.
Background:
I do a GET to an internal web service that uses CORS.
Please do NOT post any answers about FF not handling cross domain request when it does since v3.5 as detailed here and here
It works in IE8 and FF3.6.6 from one server to the other and now almost from file system (file:///) to service.
Only from file system and only when FF 3.6.6 needs to negotiate (the user is already logged in, authorised and sends the credentials!) do I not get the data after negotiation. jQuery xhr returns status 0 and no data/responseText or whatever
Seems to me, jQuery reacts and saves the xhr from the 401 rather than from the 200 OK later
Here is the result I get at the end of the communication when I alert the XHR object:
Status:success
Data:[]
XHR:
some native functions,
readyState:4
status:0
responseXML:null
responseText:
withCredentials:true
if I make a call to the same server but without needing credentials, the data is returned just fine cross domain
So the communication is as follows:
GET /restapplicationusingcors/authenticationneeded-internal/someid
Accept: application/json
Accept-Language: en
.
.
Origin: null
Cookie: LtpaToken=...
the return is
HTTP/1.1 401 Unauthorized
Server: Apache
Pragma: No-cache
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 01:00:00 CET
WWW-Authenticate: Negotiate
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
Then FF sends
GET /restapplicationusingcors/authenticationneeded-internal/someid HTTP/1.1
Host: myhost.myintranet.bla
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6
Accept: application/json
Accept-Language: en
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: null
Cookie: LtpaToken=....
Authorization: Negotiate ....
and is rewarded with the file I need, but cannot get at in FF:
HTTP/1.1 200 OK
Date: Tue, 20 Jul 2010 12:08:39 GMT
Pragma: No-cache
Cache-Control: no-cache, max-age=600, s-maxage=3600
Expires: Thu, 01 Jan 1970 01:00:00 CET
X-Powered-By: ...
Content-Disposition: inline;filename=nnnnnn.json
Content-Language: en
Access-Control-Allow-Origin: ...
Keep-Alive: timeout=6, max=70
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
THE DATA SENT FROM THE SERVER IS NOT IN THE XHR OBJECT
Here is my code
function getJSON(url,func,lang) {
accept = 'application/json';
lang=lang?lang:"*";
// gruesome hack to handle that APPENDS the mime header to */* !!!
// NOW HANDLED by first setting Accept to "" !!!
// if ($.browser.msie && url.indexOf('serveAsMime')==-1) {
// url+= '?serveAsMime='+accept;
// }
if (currentRequest != null) currentRequest.abort();
var requestObjectJSON = {
url : url,
// dataType: "json",
method : 'get',
beforeSend: function(xhr){
xhr.setRequestHeader('Accept', ""); // IE hack
xhr.setRequestHeader('Accept', accept);
xhr.setRequestHeader('Accept-Language', lang);
if (url.indexOf('-internal') !=-1) {
try {
xhr.withCredentials = true;
alert('set credentials')
}
catch(e) {
alert('cannot set xhr with credentials')
}
}
},
success: function(data,status,xhr) {
var responseText = xhr.responseText;
var responseJSON = xhr.responseJSON;
var t = "";
try{
for (var o in xhr) t += '\n'+o+':'+xhr[o];
}
catch(e) {
if (e.message.indexOf('.channel')==-1)alert(e.message);
}
alert('Status:'+status+'\nData:['+data+']\nXHR:'+t);
func(responseText);
},
}
currentRequest = $.ajax(requestObjectJSON);
}
This is a stab in the dark since I don't fully understand your problem, but I think you might be having a problem with file: URLs, which are not treated as having any origin. I'm not sure it's even possible to authorize CORS from a file URL.
So you need to set an ajax prefilter in your model/collection in order to use CORS. Otherwise it doesn't send the cookie.
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.xhrFields = {
withCredentials: true
};
});
I put this in my Model/Collection initialize function.
These are the conditions to be met to make CORS working with secured services:
Service response should contain header Access-Control-Allow-Credentials: true (see Requests with credentials and Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true).
Service response header Access-Control-Allow-Origin should not be *. The idea is to return the value passed by client in header Origin (see examples in this post).
According to specification, OPTIONS method should return HTTP code 200, thus it cannot be secured (see The CORS).
For methods PUT/POST that need to pass certain request headers to service (like Content-Type or Accept), these headers need to be listed in Access-Control-Allow-Headers (see jQuery AJAX fails to work when headers are specified)
JavaScript should set this XMLHttpRequest property: xhr.withCredentials = true; (as answered by Kirby)
Altogether configuration for Apache:
# Static content:
SetEnvIf Request_URI ".*" no-jk
# RESTful service:
SetEnvIf Request_URI "^/backend/" !no-jk
SetEnvIf Request_Method "OPTIONS" no-jk
# Fallback value:
SetEnv http_origin "*"
SetEnvIf Origin "^https?://(localhost|.*\.myconpany\.org)(:[0-9]+)?$" http_origin=$0
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Origin "%{http_origin}e"
Header set Access-Control-Allow-Methods "GET,POST,PUT,DELETE"
Header set Access-Control-Allow-Headers "Content-Type, Accept"
JkMount /* loadbalancer
CORS with file://
If you have problems by allowing origins from the file:// protocol, according to The Web Origin Concept it should be done the same way as any other origins. I could not find information about the browser support, but I think every browser which is supporting CORS does support this one either.
The Web Origin Concept tells us the following about the file URI scheme:
4. If uri-scheme is "file", the implementation MAY return an
implementation-defined value.
NOTE: Historically, user agents have granted content from the
file scheme a tremendous amount of privilege. However,
granting all local files such wide privileges can lead to
privilege escalation attacks. Some user agents have had
success granting local files directory-based privileges, but
this approach has not been widely adopted. Other user agents
use globally unique identifiers for each file URI, which is
the most secure option.
According to wikipedia the domain by the file URI scheme is localhost. It is omittable by the address bar, but I don't think it is omittable in the allow origin headers. So if your browser implementation allows origin with a file URI scheme, then you should add file://localhost to your allowed origins, and everything should work properly after that.
This was how it should work, now meet reality:
I tested with current firefox 29.0.1, and it did not work. However the file:// protocol is transformed into null origin by this implementation. So by firefox the null works. I tried with a wider domain list, but I did not manage to allow multiple domains. It seems like firefox does not support a list with multiple domains currently.
I tested with chrome 35.0.1916, it works the same way as firefox did.
I tested with msie 11.0.9600. By request from the file protocol it always shows an allow blocked content button, even by not allowing the null origin. By other domains it works the same way as the previous browsers.
HTTP basic auth:
The credentials part I tried out with PHP and HTTP basic auth.
http://test.loc
Displays :-) when logged in and :-( when unauthorized.
<?php
function authorized()
{
if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW']))
return false;
return ($_SERVER['PHP_AUTH_USER'] == 'username' && $_SERVER['PHP_AUTH_PW'] == 'password');
}
function unauthorized()
{
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Basic realm="Restricted Area"');
echo ':-(';
}
if (!isset($_GET['logout']) && authorized()) {
echo ':-)';
} else
unauthorized();
So this code changes the location by login and logout.
Cross domain CORS with HTTP basic auth
http://todo.loc
Gets the content of http://test.loc with cross domain XHR and displays it.
cross domain ajax<br />
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', "http://test.loc", true);
xhr.withCredentials = true;
xhr.onreadystatechange = function (){
if (xhr.readyState==4) {
document.body.innerHTML += xhr.responseText;
}
};
xhr.send();
</script>
Requires headers by http://test.loc:
Access-Control-Allow-Origin: http://todo.loc
Access-Control-Allow-Credentials: true
Cross scheme CORS with HTTP basic auth
file:///path/x.html
Gets the content of http://test.loc with cross scheme XHR and displays it.
cross scheme ajax<br />
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', "http://test.loc", true);
xhr.withCredentials = true;
xhr.onreadystatechange = function (){
if (xhr.readyState==4) {
document.body.innerHTML += xhr.responseText;
}
};
xhr.send();
</script>
Requires headers by http://test.loc:
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
Conclusion:
I tested cross-sheme CORS with credentials called from file:// and it works pretty well in firefox, chrome and msie.

Categories