Skip to content

Commit

Permalink
unify async and synch GetUriStream methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Sixten Otto committed Jul 2, 2018
1 parent 8d258da commit 1bc8c6b
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 64 deletions.
72 changes: 25 additions & 47 deletions Plugins/RemoteReader/RemoteReaderPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -331,37 +331,13 @@ public IEnumerable<IIssue> GetIssues() {
/// <param name="maxRedirects"></param>
/// <returns></returns>
public Stream GetUriStream(Uri uri, int maxRedirects = -1) {
if (maxRedirects == -1) maxRedirects = AllowedRedirects;

HttpWebResponse response = null;
try {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
request.Timeout = 15000; //Default to 15 seconds. Browser timeout is usually 30.
request.UserAgent = "ImageResizer";

//This is IDisposable, but only disposes the stream we are returning. So we can't dispose it, and don't need to
response = request.GetResponse() as HttpWebResponse;
response = CreateWebRequest(uri, maxRedirects).GetResponse() as HttpWebResponse;
return response.GetResponseStream();
} catch (WebException e) {
var resp = e.Response as HttpWebResponse;

if (e.Status == WebExceptionStatus.ProtocolError && resp != null) {
if (resp.StatusCode == HttpStatusCode.NotFound) throw new FileNotFoundException("404 error: \"" + uri.ToString() + "\" not found.", e);

if (resp.StatusCode == HttpStatusCode.Forbidden) throw new HttpException(403, "403 Not Authorized (from remote server) for : \"" + uri.ToString() + "\".", e);
if (resp.StatusCode == HttpStatusCode.Moved ||
resp.StatusCode == HttpStatusCode.Redirect) {
if (maxRedirects < 1) throw new HttpException(500, "Too many redirects, stopped while looking for \"" + uri.ToString() + "\".");
string loc = resp.GetResponseHeader("Location");
if (!string.IsNullOrEmpty(loc) && Uri.IsWellFormedUriString(loc, UriKind.RelativeOrAbsolute)) {
Uri newLoc = Uri.IsWellFormedUriString(loc, UriKind.Absolute) ? new Uri(loc) : new Uri(uri, new Uri(loc));
response.Close(); response = null;
return GetUriStream(newLoc, maxRedirects - 1);
}
}
}
//if (resp != null)resp.Close();
HandleWebResponseException(e, uri);
if (response != null) response.Close();
throw e;
}
Expand All @@ -378,35 +354,37 @@ public Stream GetUriStream(Uri uri, int maxRedirects = -1) {
/// <returns></returns>
public async Task<Stream> GetUriStreamAsync(Uri uri, int maxRedirects = -1)
{
if (maxRedirects == -1) maxRedirects = AllowedRedirects;

HttpWebResponse response = null;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Timeout = 15000; //Default to 15 seconds. Browser timeout is usually 30.
request.AllowAutoRedirect = maxRedirects != 0;
request.MaximumAutomaticRedirections = maxRedirects > 0 ? maxRedirects : 0;
try {
//This is IDisposable, but only disposes the stream we are returning. So we can't dispose it, and don't need to
response = await request.GetResponseAsync() as HttpWebResponse;
response = await CreateWebRequest(uri, maxRedirects).GetResponseAsync() as HttpWebResponse;
return response.GetResponseStream();
}
catch (WebException e)
{
var resp = e.Response as HttpWebResponse;

if (e.Status == WebExceptionStatus.ProtocolError && resp != null)
{
if (resp.StatusCode == HttpStatusCode.NotFound) throw new FileNotFoundException("404 error: \"" + uri.ToString() + "\" not found.", e);

if (resp.StatusCode == HttpStatusCode.Forbidden) throw new HttpException(403, "403 Not Authorized (from remote server) for : \"" + uri.ToString() + "\".", e);
}
//if (resp != null)resp.Close();
} catch (WebException e) {
HandleWebResponseException(e, uri);
if (response != null) response.Close();
throw e;
}
}

private HttpWebRequest CreateWebRequest(Uri uri, int maxRedirects = -1) {
if (maxRedirects == -1) maxRedirects = AllowedRedirects;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
request.Timeout = 15000; //Default to 15 seconds. Browser timeout is usually 30.
request.AllowAutoRedirect = maxRedirects != 0;
request.MaximumAutomaticRedirections = maxRedirects > 0 ? maxRedirects : 0;
request.UserAgent = "ImageResizer";
return request;
}

private void HandleWebResponseException(WebException e, Uri uri) {
var resp = e.Response as HttpWebResponse;
if (e.Status == WebExceptionStatus.ProtocolError && resp != null) {
if (resp.StatusCode == HttpStatusCode.NotFound) throw new FileNotFoundException(String.Format("404 error: \"{0}\" not found.", uri), e);
if (resp.StatusCode == HttpStatusCode.Forbidden) throw new HttpException(403, String.Format("403 Not Authorized (from remote server) for : \"{0}\".", uri), e);
}
}


public Task<bool> FileExistsAsync(string virtualPath, NameValueCollection queryString)
{
Expand Down
87 changes: 70 additions & 17 deletions Tests/ImageResizer.ProviderTests/RemoteReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,34 @@
// No part of this project, including this file, may be copied, modified,
// propagated, or distributed except as permitted in COPYRIGHT.txt.
// Licensed under the Apache License, Version 2.0.
using System;
using System;
using System.Collections.Specialized;
using System.IO;
using System.Web;
using System.Threading.Tasks;
using ImageResizer.Configuration;
using ImageResizer.Plugins;
using ImageResizer.Plugins.RemoteReader;
using Xunit;

namespace ImageResizer.ProviderTests {
public abstract class RemoteReaderTestBase {
/// <summary>
/// A GUID that can be used to represent a file that does not exist.
/// </summary>
protected static readonly Guid dummyDatabaseRecordId = Guid.NewGuid();

protected static readonly string pathPrefix = "/remote/farm7.static.flickr.com/6021/";

/// <summary>
/// Gets a settings object for a <see cref="RemoteReaderPlugin"/>.
/// </summary>
protected NameValueCollection Settings {
get {
return new NameValueCollection();
}
}
}

/// <summary>
/// Test the functionality of the <see cref="RemoteReaderPlugin"/> class.
/// </summary>
Expand All @@ -20,14 +38,7 @@ namespace ImageResizer.ProviderTests {
/// implemented by <see cref="RemoteReaderPlugin"/>. Also The methods
/// implementations of <see cref="IVirtualFile"/>.
/// </remarks>
public class RemoteReaderTest {
/// <summary>
/// A GUID that can be used to represent a file that does not exist.
/// </summary>
private static Guid dummyDatabaseRecordId = Guid.NewGuid();

private static string pathPrefix = "/remote/farm7.static.flickr.com/6021/";

public class RemoteReaderTest : RemoteReaderTestBase {
/// <summary>
/// Instantiate a new <see cref="RemoteReaderPlugin"/> object and test for success.
/// </summary>
Expand Down Expand Up @@ -333,15 +344,57 @@ public void OpenInvalidId() {
Assert.NotNull(actual);
Assert.IsType<FileNotFoundException>(actual);
}
}

/// <summary>
/// Test the functionality of the <see cref="RemoteReaderPlugin"/> class.
/// </summary>
/// <remarks>
/// These tests exercise the methods from <see cref="IVirtualImageProviderAsync"/> as
/// implemented by <see cref="RemoteReaderPlugin"/>. Also The methods
/// implementations of <see cref="IVirtualFileAsync"/>.
/// </remarks>
public class RemoteReaderAsyncTest : RemoteReaderTestBase {
/// <summary>
/// Gets a settings object for a <see cref="RemoteReaderPlugin"/>.
/// Call the GetFile method with the virtual path prefix omitted.
/// </summary>
private NameValueCollection Settings {
get {
var settings = new NameValueCollection();
return settings;
}
[Fact]
public Task GetFileWithoutVirtualPathPrefix() {
// Arrange
string virtualPath = dummyDatabaseRecordId.ToString("B");
IVirtualImageProviderAsync target = new RemoteReaderPlugin();

// Act / Assert
return Assert.ThrowsAsync<FileNotFoundException>(() => target.GetFileAsync(virtualPath, new NameValueCollection()));
}

/// <summary>
/// Call the Open method with a virtualPath to a file that
/// does exist.
/// </summary>
/// <remarks>
/// Requires a file to be present at http://farm7.static.flickr.com/6021/5959854178_1c2ec6bd77_b.jpg
/// </remarks>
[Fact]
public async Task OpenAsync() {
// Arrange
string virtualPath = pathPrefix + "5959854178_1c2ec6bd77_b.jpg";
IVirtualImageProviderAsync reader = new RemoteReaderPlugin();
var rs = new ResizerSection("<resizer><remotereader signingKey=\"ag383ht23sag#laf#lafF#oyfafqewt;2twfqw\" allowAllSignedRequests=\"true\" /></resizer>");
var c = new Config(rs);
((RemoteReaderPlugin)reader).Install(c);
var settings = this.Settings;
settings["hmac"] = "k_RU-UFkOaA";
settings["urlb64"] = "aHR0cDovL2Zhcm03LnN0YXRpYy5mbGlja3IuY29tLzYwMjEvNTk1OTg1NDE3OF8xYzJlYzZiZDc3X2IuanBn";
var target = await reader.GetFileAsync(virtualPath, settings);

// Act
var actual = await target.OpenAsync();

// Assert
Assert.NotNull(actual);
Assert.IsAssignableFrom<Stream>(actual);
Assert.Equal<string>(virtualPath, target.VirtualPath);
}
}
}
}

0 comments on commit 1bc8c6b

Please sign in to comment.