Showing posts with label errors. Show all posts
Showing posts with label errors. Show all posts

Monday, November 29, 2010

.NET WebClient 403 Forbidden Error

Wasted 2 hours trying to track down the following error when making a simple WebClient DownloadFile request to an Amazon S3 url:
The remote server returned an error: (403) Forbidden.

Offending code and Url:
Uri uu = new Uri("https://zencoder-live.s3.amazonaws.com:443/add9d5d739193c13fcde60d3d7ff5ba7%2Ffe33f4d52e1cff0ef06592ed4041a7dc.mp4?Signature=b%2FXw9ylREb4up4QDw6Tyv9GyQhU%3D&Expires=1291150754&AWSAccessKeyId=AKIAIIEXNN2J4YDTRUVQ");
using (WebClient wClient = new WebClient())
{
    wClient.DownloadFile(uu, @"C:\output.mp4");
}

I was able to use Fiddler to compare Firefox's request versus my .NET application's request.

Firefox:GET /add9d5d739193c13fcde60d3d7ff5ba7%2Ffe33f4d52e1cff0ef06592ed4041a7dc.mp4?Signature=b%2FXw9ylREb4up4QDw6Tyv9GyQhU%3D&Expires=1291150754&AWSAccessKeyId=AKIAIIEXNN2J4YDTRUVQ HTTP/1.1


.NET WebClient:GET /add9d5d739193c13fcde60d3d7ff5ba7/fe33f4d52e1cff0ef06592ed4041a7dc.mp4?Signature%3Db%2FXw9ylREb4up4QDw6Tyv9GyQhU%3D%26Expires%3D1291150754%26AWSAccessKeyId%3DAKIAIIEXNN2J4YDTRUVQ HTTP/1.1

Notice that .NET is escaping my Url. Particularly the forward slash (%2F). You used to be able to pass a dontEscape parameter to the new Uri constructor but now that parameter is deprecated and is always false.

Luckily I came across a workaround on StackOverflow by Rasmus Faber:
Uri uu = new Uri("https://zencoder-live.s3.amazonaws.com:443/add9d5d739193c13fcde60d3d7ff5ba7%2Ffe33f4d52e1cff0ef06592ed4041a7dc.mp4?Signature=b%2FXw9ylREb4up4QDw6Tyv9GyQhU%3D&Expires=1291150754&AWSAccessKeyId=AKIAIIEXNN2J4YDTRUVQ");
ForceCanonicalPathAndQuery(uu);
using (WebClient wClient = new WebClient())
{
    wClient.DownloadFile(uu, @"C:\output.mp4");
}

void ForceCanonicalPathAndQuery(Uri uri){
  string paq = uri.PathAndQuery; // need to access PathAndQuery
  FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
  ulong flags = (ulong) flagsFieldInfo.GetValue(uri);
  flags &= ~((ulong) 0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
  flagsFieldInfo.SetValue(uri, flags);
}

Now the code downloads the file like without the error!