Warm tip: This article is reproduced from stackoverflow.com, please click
cors http-live-streaming mpeg-dash reddit xmlhttprequest

Request to HLS/DASH URL for Reddit-hosted video through XHR results in “CORS header ‘Access-Control-

发布于 2020-05-25 15:00:31

I'm trying to use the hls.js library for displaying Reddit hosted videos from the HLS/DASH playlist. However, accessing any Reddit HLS/DASH url, such as this one through XHR will fail due to, what the error says is a Same Origin Policy violation:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://v.redd.it/5r0nz8sywgl41/DASHPlaylist.mpd. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

Weird thing is, the request prior GET is an OPTIONS one, which does return the Access-Control-Allow-Origin header with the correct origin url. I can see the response in the developer console, but the request still "fails". If I use the "Allow CORS: Access-Control-Allow-Origin" extension, everything works fine. What am I doing incorrectly?

OPTIONS request headers:

Host: v.redd.it
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0
Accept: */*
Accept-Language: lt,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Referer: http://localhost:3000/
Origin: http://localhost:3000
DNT: 1
Connection: keep-alive
Save-Data: on
Pragma: no-cache
Cache-Control: no-cache
TE: Trailers

OPTIONS response headers:

HTTP/2 200 OK
retry-after: 0
access-control-allow-origin: http://localhost:3000
access-control-allow-headers: authorization
access-control-allow-methods: GET
access-control-max-age: 3000
date: Sun, 08 Mar 2020 18:40:29 GMT
via: 1.1 varnish
x-served-by: cache-hhn4029-HHN
x-cache: HIT
x-cache-hits: 0
x-timer: S1583692829.044409,VS0,VE0
server: snooserv
accept-ranges: bytes
x-cdn-server-region: EU-East
x-cdn-client-region: EU
x-cdn-name: fastly
access-control-expose-headers: x-cdn-server-region, x-cdn-client-region, x-cdn-name
cache-control: public, max-age=604800, s-maxage=86400, must-revalidate
vary: Access-Control-Request-Headers, Access-Control-Request-Method,Origin
content-length: 0
X-Firefox-Spdy: h2

GET request headers:

Host: v.redd.it
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0
Accept: */*
Accept-Language: lt,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br
Referer: http://localhost:3000/
Authorization: Bearer --------------------------- (actual token here)
Origin: http://localhost:3000
DNT: 1
Connection: keep-alive
Save-Data: on
Pragma: no-cache
Cache-Control: no-cache
TE: Trailers

GET response headers:

HTTP/2 200 OK
last-modified: Sun, 08 Mar 2020 15:34:11 GMT
etag: "0abfb243cb8d03188bf34ff29d6d4af8"
content-type: application/dash+xml
via: 1.1 varnish
date: Sun, 08 Mar 2020 18:40:29 GMT
via: 1.1 varnish
x-served-by: cache-bwi5138-BWI, cache-hhn4029-HHN
x-cache: HIT, HIT
x-cache-hits: 2, 34
x-timer: S1583692829.127808,VS0,VE0
server: snooserv
accept-ranges: bytes
x-cdn-server-region: EU-East
x-cdn-client-region: EU
x-cdn-name: fastly
access-control-expose-headers: x-cdn-server-region, x-cdn-client-region, x-cdn-name
cache-control: public, max-age=604800, s-maxage=86400, must-revalidate
vary: Origin
content-length: 1976
X-Firefox-Spdy: h2

GET response:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<MPD mediaPresentationDuration="PT15.034S" minBufferTime="PT1.500S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" type="static" xmlns="urn:mpeg:dash:schema:mpd:2011">
    <Period duration="PT15.034S">
        <AdaptationSet segmentAlignment="true" subsegmentAlignment="true" subsegmentStartsWithSAP="1">
            <Representation bandwidth="1172841" codecs="avc1.4d401f" frameRate="30" height="480" id="VIDEO-1" mimeType="video/mp4" startWithSAP="1" width="720">
                <BaseURL>DASH_480</BaseURL>
                <SegmentBase indexRange="913-992" indexRangeExact="true">
                    <Initialization range="0-912"/>
                </SegmentBase>
            </Representation>
            <Representation bandwidth="784684" codecs="avc1.4d401e" frameRate="30" height="360" id="VIDEO-2" mimeType="video/mp4" startWithSAP="1" width="540">
                <BaseURL>DASH_360</BaseURL>
                <SegmentBase indexRange="915-994" indexRangeExact="true">
                    <Initialization range="0-914"/>
                </SegmentBase>
            </Representation>
            <Representation bandwidth="592784" codecs="avc1.4d401e" frameRate="30" height="240" id="VIDEO-3" mimeType="video/mp4" startWithSAP="1" width="360">
                <BaseURL>DASH_240</BaseURL>
                <SegmentBase indexRange="915-994" indexRangeExact="true">
                    <Initialization range="0-914"/>
                </SegmentBase>
            </Representation>
            <Representation bandwidth="91690" codecs="avc1.4d400a" frameRate="30" height="96" id="VIDEO-4" mimeType="video/mp4" startWithSAP="1" width="144">
                <BaseURL>DASH_96</BaseURL>
                <SegmentBase indexRange="912-991" indexRangeExact="true">
                    <Initialization range="0-911"/>
                </SegmentBase>
            </Representation>
        </AdaptationSet>
    </Period>
</MPD>

Thanks a lot for your help.

Questioner
Emilis Kiškis
Viewed
22
sideshowbarker 2020-03-10 10:59

The problem is just: the response from https://v.redd.it/5r0nz8sywgl41/DASHPlaylist.mpd to the GET request from your code doesn’t include the Access-Control-Allow-Origin response header. Strangely though, it does include the Access-Control-Expose-Headers response header. So the cause is just that the server is misconfigured; it’s not actually properly CORS-enabled.

Specifically: even though the server sends a Access-Control-Allow-Origin header in response to the OPTIONS preflight, that on its own isn’t sufficient to make browsers allow your frontend code to access the response to the actual GET request in your code. For your code to work, the server must also send the Access-Control-Allow-Origin header in response to that GET request too.

But you can actually work around the https://v.redd.it misconfiguration and access Reddit HLS/DASH URLs from your frontend code without needing a browser extension — by making your request through CORS proxy, as in the following example.

const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://v.redd.it/5r0nz8sywgl41/DASHPlaylist.mpd";
fetch(proxyurl + url)
.then(response => response.text())
.then(contents => console.log(contents))

For explanation, see the answer at https://stackoverflow.com/a/43881141/441757.

You can easily run your own proxy using code from https://github.com/Rob--W/cors-anywhere/, and you can quickly deploy your own proxy to Heroku in literally just 2-3 minutes, with 5 commands:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

After running those commands, you’ll end up with your own CORS Anywhere server running at, e.g., https://cryptic-headland-94862.herokuapp.com/. So then rather than prefixing your request URL with https://cors-anywhere.herokuapp.com, prefix it instead with the URL for your own instance; e.g., https://cryptic-headland-94862.herokuapp.com/https://example.com.