I have an S3 bucket as an origin, and a CloudFront distribution serving streaming a/v from it.
I also have an EC2 instance serving a web page from a test domain that uses videojs to display the video as a test.
If I start the VLC media player and use the CloudFront URL to view the video, I both see and hear the media. So, this configuration does serve the content, if I do not have to deal with CORS.
However, when I attempt to view the content from my EC2 instance's web page, I run into CORS issues.
Using Firefox, and observing the Network tab in the developer tools, I see that Firefox fetches the initial .mpd URL without issue. However, the subsequent files (*.cmfv, *.cmfa, all embedded in the .mpd XML) show "CORS Missing Allow Origin" for the preflight check (the OPTIONS method call). The GET requests that evoked the OPTIONS requests then error with NS_ERROR_DOM_BAD_URI, and are never sent.
Using curl, I mimic the request from Firefox thusly:
curl -H "origin: https://my.happy.url" -H "referer: https://my.happy.url" -H "Access-Control-Request-Headers: range" -H "Access-Control-Request-Method: GET" -X OPTIONS -v https://gobbledygook.cloudfront.net/content/10%20Minutes%20Of%20Coding%20Torture_6.cmfv
And I get this response:
> OPTIONS /content/10%20Minutes%20Of%20Coding%20Torture_6.cmfv HTTP/2
> Host: gobbledygook.cloudfront.net
> user-agent: curl/7.79.1
> accept: */*
> origin: https://my.happy.url
> referer: https://my.happy.url
> access-control-request-headers: range
> access-control-request-method: GET
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
< content-length: 0
< date: Tue, 16 Nov 2021 19:25:54 GMT
< server: AmazonS3
< vary: Origin,Access-Control-Request-Headers,Access-Control-Request-Method
< x-cache: Hit from cloudfront
< via: 1.1 aaaaaaaiiiiiiiggggghhhhh.cloudfront.net (CloudFront)
< x-amz-cf-pop: IUD69-C2
< x-amz-cf-id: pHptphptmQ2lILrG9dpKVZIXT7Dhm_HSDVnBPijf7KcS7ZsLkKA==
< age: 1603
<
* Connection #0 to host gobbledygook.cloudfront.net left intact
... where I see a distinct lack of Access-Control-Allow-Origin, a complaint I see in the JavaScript console logging.
Yet, if I use curl to mimic the initial GET request with this:
curl -H "origin: https://my.happy.url" -H "referer: https://my.happy.url" -H "range: bytes=658-4657" -v https://gobbledygook.cloudfront.net/content/10%20Minutes%20Of%20Coding%20Torture_6.cmfv
... I get this:
> Host: gobbledygook.cloudfront.net
> user-agent: curl/7.79.1
> accept: */*
> origin: https://my.happy.url
> referer: https://my.happy.url
> range: bytes=658-4657
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 206
< content-type: video/mp4
< content-length: 4000
< date: Wed, 17 Nov 2021 11:54:27 GMT
< last-modified: Wed, 10 Nov 2021 15:36:31 GMT
< etag: "a2155000203fcc7e173acdc053a75cd1"
< x-amz-version-id: mfCll81lDxmeTyDIYmsoKFINElW2AmE1
< accept-ranges: bytes
< server: AmazonS3
< vary: Origin,Access-Control-Request-Headers,Access-Control-Request-Method
< content-range: bytes 658-4657/8320198
< access-control-allow-origin: *
< x-cache: Miss from cloudfront
< via: 1.1 aaaaaaaiiiiiiiggggghhhhh.cloudfront.net (CloudFront)
< x-amz-cf-pop: IAD66-C2
< x-amz-cf-id: hd-iBmLikeSmoNEYznT3SoWKNDERIGHE-gtjH2U3JlQDlwccL6SdQ==
<
Note the inclusion of the access-control-allow-origin: *
header that went missing for OPTIONS. It did actually fetch the contents. So the only thing holding this up appears, to me, to be the missing access-control-allow-origin header for the OPTIONS query. Unless I am missing something (which is possible at this point... I've spent perhaps too much time on this, and could be tunnel-visioned from seeing the solution).
The CloudFront distribution's behavior is set to allow GET, HEAD, and OPTIONS methods, and the 'Cache HTTP methods' OPTIONS checkbox is enabled, so it should cache OPTIONS.
The Cache policy for the distribution's behavior includes the following headers:
- Origin
- Access-Control-Request-Method
- Access-Control-Allow-Origin
- Access-Control-Request-Headers
and all cookies are enabled (not that this matters for this situation).
The TTL settings are set for a minimum of 0 and a maximum of 31536000, with a default of 86400, but I doubt this matters.
The Origin request policy for the distribution's behavior includes the following headers:
- Origin
- Access-Control-Request-Headers
- Access-Control-Request-Method
This is the CORS-S3Origin managed policy.
The Response headers policy for the distribution's behavior has 'Configure CORS' enabled, with the following:
- Access-Control-Allow-Origin: All origins
- Access-Control-Allow-Headers: All headers
- Access-Control-Allow-Methods: All HTTP methods
- Access-Control-Expose-Headers: All headers
- Access-Control-Max-Age: 600
- Origin override is checked
The S3 bucket has the CORS settings within its Permissions tab:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"ETag",
"Access-Control-Allow-Origin",
"Connection",
"Content-Length"
],
"MaxAgeSeconds": 3000
}
]
The web page uses the following code (with a small dot of PHP) to play the content (in a script tag):
const dashjsCallback = (player, mediaPlayer) => {
if (videojs && videojs.log) {
mediaPlayer.getDebug().setLogTimestampVisible(false);
}
};
videojs.Html5DashJS.hook('beforeinitialize', dashjsCallback);
const el = document.getElementsByTagName('video')[0];
const manifest = "/content/<?php echo $policy_stream_name ?>";
const mimeType = "application/dash+xml";
const player = videojs(el, {
"controls":true,
"autoplay":true,
"preload":"auto",
"fluid":"true",
});
player.src({
src: 'https://gobbledygook.cloudfront.net' + manifest,
type: mimeType,
});
player.play();
with the following HTML in the document:
<video
id="my-video"
class="video-js vjs-default-skin"
controls
preload="auto"
height="480"
data-setup="{}"
crossorigin="anonymous"
>
<p class="vjs-no-js">This video requires JavaScript.</p>
</video>
I have also invalidated the cache contents of the distribution with these settings, and waited 24 hours before attempting a view again, but I still cannot stream the video through the videojs player. I've exhausted my Google-fu and now turn to you, gentle reader, for help. How may I convince videojs to play this content that plays perfectly fine within VLC?
--disable-web-security
parameter and view the content without issue. But that isn't how I want this to work.