Using nginx's proxy_redirect when the response location's domain varies

Posted by Chalky on Server Fault See other posts from Server Fault or by Chalky
Published on 2012-09-16T01:29:59Z Indexed on 2012/09/16 3:40 UTC
Read the original article Hit count: 527

Filed under:

I am making an web app using SoundCloud's API. Requesting an MP3 to stream involves two requests. I'll give an example. Firstly:

http://api.soundcloud.com/tracks/59815100/stream

This returns a 302 with a temporary link to the actual MP3 (which varies each time), for example:

http://ec-media.soundcloud.com/xYZk0lr2TeQf.128.mp3?ff61182e3c2ecefa438cd02102d0e385713f0c1faf3b0339595667fd0907ea1074840971e6330e82d1d6e15dd660317b237a59b15dd687c7c4215ca64124f80381e8bb3cb5&AWSAccessKeyId=AKIAJ4IAZE5EOI7PA7VQ&Expires=1347621419&Signature=Usd%2BqsuO9wGyn5%2BrFjIQDSrZVRY%3D

The issue I had was that I am attempting to load the MP3 via JavaScript's XMLHTTPRequest, and for security reasons the browser can't follow the 302, as ec-media.soundcloud.com does not set a header saying it is safe for the browser to access via XMLHTTPRequest.

So instead of using the SoundCloud URL, I set up two locations in nginx, so the browser only interacts with the server my app is hosted on and no security errors come up:

location /soundcloud/tracks/ {
    # rewrite URL to match api.soundcloud.com's URL structure
    rewrite \/soundcloud\/tracks\/(\d*) /tracks/$1/stream break;
    proxy_set_header Host api.soundcloud.com;
    proxy_pass http://api.soundcloud.com;
    # the 302 will redirect to /soundcloud/media instead of the original domain
    proxy_redirect http://ec-media.soundcloud.com /soundcloud/media;
}

location /soundcloud/media/ {
    rewrite \/soundcloud\/media\/(.*) /$1 break;
    proxy_set_header Host ec-media.soundcloud.com;
    proxy_pass http://ec-media.soundcloud.com;
}

So myserver/soundcloud/tracks/59815100 returns a 302 to /myserver/soundcloud/media/xYZk0lr2TeQf.128.mp3...etc, which then forwards the MP3 on.

This works! However, I have hit a snag. Sometimes the 302 location is not ec-media.soundcloud.com, it's ak-media.soundcloud.com. There are possibly even more servers out there and presumably more could appear at any time. Is there any way I can handle an arbitrary 302 location without having to manually enter each possible variation?

Or is it possible for nginx to handle the redirect and return the response of the second step? So myserver/soundcloud/tracks/59815100 follows the 302 behind the scenes and returns the MP3?

The browser automatically follows the redirect, so I can't do anything with the initial response on the client side.

I am new to nginx and in a bit over my head so apologies if I've missed something obvious, or it's beyond the scope of nginx. Thanks a lot for reading.

© Server Fault or respective owner

Related posts about nginx