HTML5 Video in Chome, SECURITY_ERR: DOM Exception 18 - javascript

I am trying to have my webpage display a video from my video server. The video server is running on the same host as my webserver, but on a different port.
When I use canvas.toDataURL() to scrape the pixels off the video that is playing on the canvas, I am getting a "Uncaught Error: SECURITY_ERR: DOM Exception 18" on the browser.
I am using Chrome, version 24.
Here is the HTTP header sent with the video page
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: video/x-mp4
Transfer-Encoding: chunked
Date: Mon, 04 Feb 2013 23:28:00 GMT
Server: OizysLight
What am I missing? Shouldn't the "Access-Control-Allow-Origin: *" allow cross origin resource sharing?

You probably need to set the crossOrigin property on the <video> element. You can set it to anonymous if the request for the video resource doesn't need cookies or HTTP auth, or use-credentials otherwise.
Mozilla has a writeup about cross-domain images on a <canvas>, and virtually all of it also applies to videos.

I found the answer. I needed to set the crossOrigin property on my video.
video.crossOrigin = "Anonymous";

Related

Client keeps requesting file from REST API

I have an audio file stored on the server and clients can request these audio files via a REST API. I observed the data requested by the client and I came to the conclusion whenever I play the audio again (repeat), then a new request goes to the server for that specific file. Is there a way to prevent this or cache the data locally?
HTML
<audio controls="controls" autoplay style="width: 100%">
<source src="https://localhost:8080/api/file" type="audio/mpeg">
</audio>
Javascript (Node.js in combination with Express.js)
router.get('/file', (req, res) => {
let audioFile = path.join(__dirname, 'files/audio-book.mp3');
res.sendFile(audioFile);
})
EDIT
I have a local file and a file sent by the REST API. The local file request has HTTP code 304: Not modified and the file from the REST API request is 206: Partial content. I already added max-age and removed last-modified, but no result.
Headers:
Accept-Ranges -> Bytes
Cache-Control -> public, max-age=3600
Connection -> keep-alive
Content-Length -> 7056954
Content-Type -> audio/mpeg
Date -> Sun, 17 Jan 2016 10:16:48 GMT
Etag -> W/"6bae3a-15195a7f2aa"
X-Powered-By → Express
Situation
What happened was that the browser wouldn't cache the file in any way, shape or form. This let to tremendous amounts of traffic.
Solution
I found this article on StackOverflow about requesting files in blobs and letting an audio- or video element play it. Now I XHR the file from the server and store it in a BLOB and when I replay the audio, it retrieves the data from cache and it can work offline now.

MediaElementAudioSource outputs zeroes due to CORS access restrictions

<script>
// Create a new instance of an audio object and adjust some of its properties
var audio = new Audio();
audio.src = 'http://subdomain.domain.org:port/;stream/1';
audio.controls = true;
audio.loop = true;
audio.autoplay = true;
audio.crossorigin="anonymous";
// Establish all variables that your Analyser will use
var canvas, ctx, source, context, analyser, fbc_array, bars, bar_x, bar_width, bar_height;
// Initialize the MP3 player after the page loads all of its HTML into the window
window.addEventListener("load", initMp3Player, false);
function initMp3Player(){
document.getElementById('audio_box').appendChild(audio);
context = new (window.AudioContext || window.webkitAudioContext)(); // AudioContext object instance // AudioContext object instance
analyser = context.createAnalyser(); // AnalyserNode method
canvas = document.getElementById('analyser_render');
ctx = canvas.getContext('2d');
// Re-route audio playback into the processing graph of the AudioContext
source = context.createMediaElementSource(audio);
source.crossOrigin = 'anonymous'
source.connect(analyser);
analyser.connect(context.destination);
frameLooper();
}
// frameLooper() animates any style of graphics you wish to the audio frequency
// Looping at the default frame rate that the browser provides(approx. 60 FPS)
function frameLooper(){
(requestAnimationFrame || webkitRequestAnimationFrame)(frameLooper);
fbc_array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(fbc_array);//get frequency
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
ctx.fillStyle = '#00CCFF'; // Color of the bars
bars = 100;
for (var i = 0; i < bars; i++) {
bar_x = i * 3;
bar_width = 2;
bar_height = -(fbc_array[i] / 2);
// fillRect( x, y, width, height ) // Explanation of the parameters below
ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
}
}
</script>
Audio API gives MediaElementAudioSource outputs zeroes due to CORS access restrictions because I'm trying to play a SHOUTcast URL. I don't know what to do; I have tried all solutions on the internet but nothing worked. Any help will be appreciated.
The URL works perfectly with audio element so its not about the URL; I have even tried something like http://subdomain.domain.org:port/file.mp3. And I found on the internet people using Icecast which is .ogg have same problem. How to fix this?
In my response I will assume the following setup:
Your stream URL is http://stream.radio.com:8000/mount (or http://stream.radio.com:8000/;stream/1 for Shoutcast)
Your paget URL where you place your HTML/JS code URL is http://radio.com/player
To get this working you need:
Set the "Access-Control-Allow-Origin" header of your stream to your domain or *
In javascript, set audio tag crossOrigin property to "anonymous" audio.crossOrigin="anonymous";
Another option it to move you stream URL to the original domain using reverse proxy.
With Icecast you cat set the "Access-Control-Allow-Origin" header using configuration file, just add the following lines to your icecast.xml, I usually add them right after the opening <icecast> tag:
<http-headers>
<header name="Access-Control-Allow-Origin" value="*" />
<header name="Access-Control-Allow-Headers" value="Origin, Accept, X-Requested-With, Content-Type, If-Modified-Since" />
<header name="Access-Control-Allow-Methods" value="GET, OPTIONS, HEAD" />
</http-headers>
Don't forget to restart Icecast after these changes. When your Icecast will be back online you can check the headers with this command:
lynx -head -dump http://stream.radio.com:8000/mount
Response should look something like this:
Server: Icecast 2.4.2
....
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type, If
-Modified-Since
Access-Control-Allow-Methods: GET, OPTIONS, HEAD
As you can see, "Access-Control-Allow-Origin: *" header is present.
Shoutcast
Unfortunately, Shoutcast does not allow you to set HTTP headers (.htaccess is not an option too), but we can create a reverse proxy in web server configuration, this will allow you to host the stream from the main domain - radio.com. I will provide proxy configurations for Nginx and Apache.
Nginx
You can add additional headers with "proxy_set_header", but the basic example is:
server {
listen 80;
server_name radio.com;
....
location /stream {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://stream.radio.com:8000/mount;
}
....
}
Apache
Activate Apache proxy modules, and update radio.com virtual host configuration configuration:
<VirtualHost *:80>
ServerName radio.com
....
ProxyPass /stream http://stream.radio.com:8000/mount
</VirtualHost>
Now you can access your stream using http://radio.com/stream URL and the CORS policy will not apply. This solution also brings some additional perks:
you can convert your http Shoutcast/Icecast stream to https, so the browsers will not complain about accessing unsecure content when you will embed your stream to the page hosted with https. (Icecast supports SSL configuration itself)
8000 port will be replaced with port 80, that will allow listeners with 8000 port behind firewall to access your stream.
That is an HTTP header. You would configure your webserver or webapp to send this header. Perhaps in htaccess or PHP. remove the below line
<header name = "Access-Control-Allow-Origin" value = "*" />
SHOUTcast servers do not support CORS. There is nothing you can do to change this if you are going to continue to use SHOUTcast.
First of all, MediaElementAudioSource doesn't have a property named "crossOrigin".
I just find this problem, and mad with the Message:MediaElementAudioSource outputs zeroes due to CORS access restrictions for. But it's just a message, i can still hear the audio.
And I googled lots of this, think this link will be helpful:http://www.codingforums.com/javascript-programming/342454-audio-api-js.html
The createMediaElementSource method should create an object that uses the MediaElementAudioSourceNode interface. Such objects are subject to Cross-Origin Resource Sharing (CORS) restrictions based on the latest draft of the Web Audio API spec. (Note that this restriction doesn't appear to be in the outdated W3C version of the spec.) According to the spec, silence should be played when CORS restrictions block access to a resource, which would explain the "outputs zeroes" message; presumably, zero is equivalent to no sound.
To lift the restriction, the owner of the page at
http://morebassradio.no-ip.org:8214/;stream/1 would need to configure
their server to output an Access-Control-Allow-Origin header with
either a list of domains (including yours) or the * value to lift it
for all domains. Given that this stream appears to already be
unrestricted, public-facing content, maybe you can convince the owners
to output that header. You can test whether the header is being sent
by pressing Ctrl+Shift+Q in Firefox to open the Network panel, loading
the stream through the address bar, and then inspecting the headers
associated with that HTTP request in the Network panel.
Note that they can't use a meta element here since the audio stream
is, obviously, not an HTML document; that technique only works for
HTML and XHTML documents.
(While you're messing with Firefox panels, you may want to make sure
Security errors and warnings are enabled (by clicking the Security
button or its arrow) in the Console panel (Ctrl+Shift+K). I'm not sure
if there's a corresponding CORS message in Firefox like in Chrome, but
there might be. I wasted a bunch of time wondering why a page wasn't
working one day while troubleshooting a similar technology, Content
Security Policy (CSP), only to find that I had the relevant Firefox
messages hidden.)
You shouldn't need to mess with the crossorigin property/attribute
unless you set crossorigin = "use-credentials" (JavaScript) or
crossorigin="use-credentials" (HTML) somewhere, but you probably
didn't do that because that part of the HTML spec isn't finalized yet,
and it would almost certainly cause your content to "break" after
doing so since credentials would be required at that point.
I'm not familiar with the Web Audio API, so I wasn't able to figure
out how to output a MediaElementAudioSourceNode and trigger an error
message for my own troubleshooting. If I use createMediaElementSource
with an HTMLMediaElement (HTMLAudioElement), the result doesn't seem
to be a MediaElementAudioSourceNode based on testing using the
instanceof operator even though the spec says it should be if I'm
reading it right.
Then in my situation, i get the HTTP response Header:
HTTP/1.1 206 Partial Content
Date: Thu, 02 Jun 2016 06:50:43 GMT
Content-Type: audio/mpeg
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-Log, X-Reqid
Access-Control-Max-Age: 2592000
Content-Disposition: inline; filename="653ab5685893b4bf.mp3"
Content-Transfer-Encoding: binary
Last-Modified: Mon, 16 May 2016 02:00:05 GMT
Server: nginx
Cache-Control: public, max-age=31536000
ETag: "FpGQqtcf_s2Ce8W_4Mv6ZqSVkVTK"
X-Log: mc.g;IO:2/304
X-Reqid: 71cAAFQgUBiJMVQU
X-Qiniu-Zone: 0
Content-Range: bytes 0-1219327/1219328
Content-Length: 1219328
Age: 1
X-Via: 1.1 xinxiazai211:88 (Cdn Cache Server V2.0), 1.1 hn13:8 (Cdn Cache Server V2.0)
Connection: keep-alive
Note that "Access-Control-Allow-Origin: *", i think this just the right thing, but i still get the message. Hope it help you.

Safari on iOS involving stale $http.get results

I've just noticed that Safari on iOS keeps stale $http.get results in cache, that target my server (REST call).
However, Safari claims a status 200 (not 304), even if result is stale... troubling
I confirm that the issue comes from Safari since it's easy to check the real result through a rest call to the server.
What I do to force Safari to refresh its cache is adding a random parameter:
$http.get('myUrl?rnd=' + new Date().getTime())
Is there a better practice? Probably changing the response headers on the server directly?
My server returns this response header:
HTTP/1.1 200 OK
Server: Cowboy
Date: Tue, 11 Nov 2014 23:52:59 GMT
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Content-Length: 495
Via: 1.1 vegur
Your response doesn't have any cache control headers. According to this answer browsers are free to do whatever they want if there are no cache control headers. In your case Safari on iOS has decided to cache the content even though that isn't what you want.
You could keep using your workaround, or you could add cache control headers in the response to tell Safari not to cache your response.
Note that RFC's might say that responses should not be cached if there are no cache control headers. (I haven't checked). But browsers often have non-standard behavior that you have to work around.
As an aside - early on in my computer networking job I thought that it was OK to not support browsers and webservers that didn't follow the RFCs. I was wrong.

How to see what is returned when a remote script is blocked

I'm using Google hosted jQuery in my webapp (//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js) As part of bug diagnostics I have a window.onerror handler which catches any errors I'm not catching locally and lets the server know about them.
So far so good, but... sometimes i get errors like these:
"Script error.","Error loading script","Unexpected token <"
My assumption is that the Google CDN is blocked in these cases (for whatever reason). I do have a local fallback for jQuery, that I'm fairly sure is working well, but I would like to find out what's being returned so that I can test my assumptions and maybe get some of these users on a white list for Google CDN (if it's company firewall blocking it).
But so far I haven't been able to figure out how to retrieve the returned content. Can't retrieve innerText of a SCRIPT tag if it's a file, can't do an ajax request because of cross-domain policy, etc.
Does anyone have any ideas about how this would be possible?
It simply isn't possible to get the content of any file referenced by a <script> tag. This is with good reason: doing so would allow you to circumvent XHR's Same Origin Policy.
Consider:
<script src="https://www.example.com/private/api/getAuthToken" id="s"></script>
If you could access the text of the respnse, you'd be able to do this:
var stolenAuthToken = $('#s').text();
That's obviously bad. Therefore, you're never allowed to read the content of something brought in by <script> tags.
Your particular situation is complicated by a relatively recently introduced change where errors in cross-origin scripts do not report any useful information to your page's onerror handler. (Essentially, this was done to patch an information disclosure security hole that allows a malicious site to infer whether you're logged in to some well-known sites, among other things.)
This means that you get no useful information about errors from CDN-hosted script, so another change was made to allow the use of CORS for a CDN (or other non-same-origin) server to opt in to allowing full error details to pass to an onerror handler.
We (Facebook) need a mechanism for disabling the window.onerror muting behavior implemented in #363897. Our static script resources are served on a CDN under a different domain from the main site. Because these domains differ we're falling afoul of the x-domain logic that prevents us from gathering useful information about browser errors.
This "feature" has been widely enough adopted in in the wild (in Firefox and Webkit browsers) that the majority of uncaught exceptions we see in production now have no actionable information in them.
The crossorigin attribute (originally intended for <img>) allows you to specify that a resource should be loaded with CORS rules. It has been implemented by Mozilla, WebKit, and Chrome.
<script src="http://example.com/xdomainrequest" crossorigin="anonymous"></script>
Unfortunately for you, in my testing, I found that the Google CDN does not send CORS headers.
GET http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js HTTP/1.1
Host: ajax.googleapis.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://fiddle.jshell.net/josh3736/jm2JU/show/
Origin: http://fiddle.jshell.net
Pragma: no-cache
Cache-Control: no-cache
HTTP/1.1 200 OK
Vary: Accept-Encoding
Content-Type: text/javascript; charset=UTF-8
Last-Modified: Tue, 13 Nov 2012 19:53:02 GMT
Date: Wed, 02 Jan 2013 22:54:25 GMT
Expires: Thu, 02 Jan 2014 22:54:25 GMT
X-Content-Type-Options: nosniff
Server: sffe
Content-Length: 93637
X-XSS-Protection: 1; mode=block
Cache-Control: public, max-age=31536000
Age: 169036
...
Note the presence of the Origin header in the request (indicating a CORS request), and the absence of an Access-Control-Allow-Origin header in the response. Thus, even if you put the crossorigin attribute, the CORS check will fail, and your scripts will receive scrubbed error details.
There is a three-year-old issue to enable CORS on the Google CDN server. I wouldn't hold my breath.
tldr: If you want meaningful error messages, you must host all JavaScript yourself, on the same origin.

Need a Way to Disable IE9 Browser Caching

I have a Flash application that sends a getURL request for an image file every 60 seconds.
This works fine in all browsers except IE9 with Internet Option set to automatically check for newer versions of stored pages.
I setup Charles proxy (http://xk72.com) to watch the requests being sent by my flash app and confirmed that the request is being surpressed by IE9 when the setting is set to Auto, but works fine if I change the setting to check everytime I visit the webpage. This, however, is not an option! I need this to work in all browsers regardless of how the options are set.
Even if I do a page refresh (F5), the ASP page does not reload. The only way to get it to reload is close the browser and restart it.
I have tried adding content headers to disable caching but it does not appear to work.
For Example, here is my request headers:
HTTP/1.1 200 OK
Date Sun, 02 Oct 2011 23:58:31 GMT
Server Microsoft-IIS/6.0
X-Powered-By ASP.NET
Expires Tue, 09 Nov 2010 14:59:39 GMT
Cache-control no-cache
max-age 0
Content-Length 9691
Content-Type text/html
Set-Cookie ASPSESSIONIDACQBSACA=ECJPCLHADMFBDLCBHLJFPBPH; path=/
Cache-control private
I have read the Microsoft blog (http://blogs.msdn.com/b/ie/archive/2010/07/14/caching-improvements-in-internet-explorer-9.aspx) which states that if I add the content headers, the browser should respect my request, but it obviously does not.
I don't think this is a Flash issue since the html page that holds the Flash object will not even reload.
You can append a random number to the end of the url.

Categories