question

chadriddle avatar image
chadriddle asked

HEAD request with ThruCDN=false is Forbidden

I am working with the CDN for storing various content for both an admin tool and client application.

I understand that the CDN will be cached and may take up to 24 hours to propagate. For most client scenarios this is fine and I am able to use the following code to check if a newer version of an asset is available by using the LAST-MODIFIED in the response headers.

var request = new GetContentDownloadUrlRequest
            {
                HttpMethod = "HEAD",
                Key = remotePath
            };

For the admin tool and in a few case in the client I would like to be able to check the LAST-MODIFIED directly using the ThruCDN=false property like:

var request = new GetContentDownloadUrlRequest
            {
                HttpMethod = "HEAD",
                Key = remotePath,
                ThruCDN = false
            };

However, setting the ThruCDN=false cause S3 to return a 403 Forbidden error with the following message:

<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>

Is there any reason why a HEAD request does not work directly against the CDN?

Thanks

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1 Answer

·
brendan avatar image
brendan answered

In general, the best way to manage your CDN content is by having a "version" in the filename (the key in the lookup). That way, when you update to a new version, it is distinct, allowing you to test it without disrupting active players, and the TTL isn't an issue since it's a new file. You could then store a "manifest" in a key/value pair in Title Data, so that the client can use that to determine the keys (filenames) to use.

For the 403 issue, can you send us the code snippet showing how you're attempting to download the data?

14 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

chadriddle avatar image chadriddle commented ·

I understand your suggestion of the best way to manage the content using file versioning. However, this also leads to a higher maintenance cost. For us, an image (or other asset) will be referenced by multiple places within multiple scripts and content files. If we need to update an image to correct a simple issue like cropping or coloring we do not want to introduce additional risk by updating every instance across all content files. There are more elaborate ways, like asset mapping of some type and we may get to that in the near future. But the simplest solution is to just update the file and let the client grab the latest version.

Here is the testing code that I am using to get the HEAD data. If I leave ThruCDN commented out, all is good. If I un-comment that line then I get the 403 error.

           

0 Likes 0 ·
chadriddle avatar image chadriddle commented ·
            var request = new GetContentDownloadUrlRequest
            {
                HttpMethod = "HEAD",
                Key = remotePath,
                //ThruCDN = false
            };


            PlayFabClientAPI.GetContentDownloadUrl(request, r =>
            {
                Debug.Log(r.URL);
                var www = new WWW(r.URL);
                while (!www.isDone)
                {
                }


                foreach (var header in www.responseHeaders)
                {
                    Debug.Log(header.Key + ", " + header.Value);
                }


            }, e =>
            {
                m_inProcess.Remove(assetName);
                PlayFabErrorHandler.HandlePlayFabError(e);
            });

0 Likes 0 ·
brendan avatar image brendan chadriddle commented ·

Ah, I see. So what's happening is this:

When you call GetContentDownloadUrl with ThruCDN set to true (or not set, since that's the default), you're getting a URL from CloudFront, which doesn't care if you're querying HEAD or GET - it'll return you the info.

But when you call it with ThruCDN set to false, you're going to S3 directly and getting a pre-signed URL. At that point, the signature takes precedence, and if your subsequent query against that URL doesn't match what you asked for, you get a 403. In this case, WWW is doing a GET against the URL (its default - you can make WWW do a POST, but I don't believe you can make it generate a HEAD call). That won't work, because you asked for a HEAD URL, which requires a HEAD call to get the results. If you use Postman to test against the URL with a HEAD call, you'll see that it correctly returns a 200 OK for content that exists in your S3 bucket.

0 Likes 0 ·
chadriddle avatar image chadriddle commented ·

Thanks for your reply, that makes a lot of sense.

I have done some more testing and have found that if I use a standard .Net HttpWebRequest:

                    var webrequest = (HttpWebRequest)WebRequest.Create(r.URL);
                    webrequest.Method = "HEAD";
                    var response = webrequest.GetResponse()

When ThruCDN=false it fails with the following error:

System.Net.WebException: Error getting response stream (Write: The authentication or decryption has failed.)

This appears to be an issue with the underlying Mono implementations handling of certificates.

However, when ThruCDN=true then it will succeed and I can get the headers properly.

I also discovered the UnityHttpRequest class that can be used instead of the WWW class.

Using the following code I am able to make successful calls with ThruCDN set to both true and false:

 		var uReq = UnityWebRequest.Head(r.URL);
                uReq.Send();
                while (!uReq.isDone) { }

I believe that using UnityHttpRequest I should be able to accomplish what I need to.

Thanks.

0 Likes 0 ·
Anthony Demanuele avatar image Anthony Demanuele commented ·

I am getting a [403 Forbidden] error too.
ThruCDN is not set (left as default). My code is exactly the same as @chadriddle here.

Is there another else we can try please?

Thanks.

0 Likes 0 ·
brendan avatar image brendan Anthony Demanuele commented ·

Can you give us the Title ID, and the details of the values passed into the parameters?

0 Likes 0 ·
Anthony Demanuele avatar image Anthony Demanuele commented ·

@Brendan details here:

TitleID: 818B

var request =new GetContentDownloadUrlRequest
{Key= filePath};
0 Likes 0 ·
brendan avatar image brendan Anthony Demanuele commented ·

Thanks, but what was actually in the string "filePath"? What was the value?

0 Likes 0 ·
Show more comments

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.