Skip to content

Commit

Permalink
Reset the ServicePoint if a ProtocolViolationException occurs when us…
Browse files Browse the repository at this point in the history
…ing chunked encoding (fixes openstacknetsdk#333)
  • Loading branch information
sharwell committed Apr 11, 2014
1 parent 68c2b68 commit 2d40127
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 1 deletion.
23 changes: 22 additions & 1 deletion src/corelib/Providers/Rackspace/ProviderBase`1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Newtonsoft.Json.Linq;
using CancellationToken = System.Threading.CancellationToken;
using Encoding = System.Text.Encoding;
using Thread = System.Threading.Thread;

namespace net.openstack.Providers.Rackspace
{
Expand Down Expand Up @@ -547,7 +548,27 @@ protected Response StreamRESTRequest(CloudIdentity identity, Uri absoluteUri, Ht
initialPosition = null;
}

var response = RestService.Stream(absoluteUri, method, stream, chunkSize, maxReadLength, headers, queryStringParameter, requestSettings, progressUpdated);
Response response;
try
{
response = RestService.Stream(absoluteUri, method, stream, chunkSize, maxReadLength, headers, queryStringParameter, requestSettings, progressUpdated);
}
catch (ProtocolViolationException)
{
ServicePoint servicePoint = ServicePointManager.FindServicePoint(absoluteUri);
if (servicePoint.ProtocolVersion < HttpVersion.Version11)
{
// this is a workaround for issue #333
// https://github.com/openstacknetsdk/openstack.net/issues/333
// http://stackoverflow.com/a/22976809/138304
int maxIdleTime = servicePoint.MaxIdleTime;
servicePoint.MaxIdleTime = 0;
Thread.Sleep(1);
servicePoint.MaxIdleTime = maxIdleTime;
}

response = RestService.Stream(absoluteUri, method, stream, chunkSize, maxReadLength, headers, queryStringParameter, requestSettings, progressUpdated);
}

// on errors try again 1 time.
if (response.StatusCode == HttpStatusCode.Unauthorized && !isRetry && initialPosition != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,32 @@ public void TestStaticWebOnContainer()
provider.DeleteContainer(containerName, deleteObjects: true);
}

/// <summary>
/// This is a regression test for openstacknetsdk/openstack.net#333.
/// </summary>
/// <seealso href="https://github.com/openstacknetsdk/openstack.net/issues/333">Chunked Encoding Issues (#333)</seealso>
[TestMethod]
[TestCategory(TestCategories.User)]
[TestCategory(TestCategories.ObjectStorage)]
public void TestProtocolViolation()
{
try
{
TestTempUrlWithControlCharactersInObjectName();
Assert.Inconclusive("This test relies on the previous call throwing a WebException placing the ServicePoint in a bad state.");
}
catch (WebException ex)
{
Assert.IsNotNull(ex.Response);

ServicePoint servicePoint = ServicePointManager.FindServicePoint(ex.Response.ResponseUri);
if (servicePoint.ProtocolVersion >= HttpVersion.Version11)
Assert.Inconclusive("The ServicePoint must be set to HTTP/1.0 in order to test the ProtocolViolationException handling.");
}

TestTempUrlExpired();
}

[TestMethod]
[TestCategory(TestCategories.User)]
[TestCategory(TestCategories.ObjectStorage)]
Expand Down Expand Up @@ -918,6 +944,49 @@ public void TestTempUrlWithSpecialCharactersInObjectName()
provider.DeleteContainer(containerName, deleteObjects: true);
}

[TestMethod]
[TestCategory(TestCategories.User)]
[TestCategory(TestCategories.ObjectStorage)]
public void TestTempUrlWithControlCharactersInObjectName()
{
IObjectStorageProvider provider = Bootstrapper.CreateObjectStorageProvider();
Assert.IsInstanceOfType(provider, typeof(CloudFilesProvider), "Temp URLs are a Rackspace-specific extension to the Object Storage service.");

string containerName = TestContainerPrefix + Path.GetRandomFileName();
string objectName = "foo\n\rbar";
string fileContents = "File contents!";

Dictionary<string, string> accountMetadata = provider.GetAccountMetaData();
string tempUrlKey;
if (!accountMetadata.TryGetValue(CloudFilesProvider.TempUrlKey, out tempUrlKey))
{
tempUrlKey = Guid.NewGuid().ToString("N");
accountMetadata = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
accountMetadata[CloudFilesProvider.TempUrlKey] = tempUrlKey;
provider.UpdateAccountMetadata(accountMetadata);
}

ObjectStore result = provider.CreateContainer(containerName);
Assert.AreEqual(ObjectStore.ContainerCreated, result);

Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(fileContents));
provider.CreateObject(containerName, stream, objectName);

// verify a future time works
DateTimeOffset expirationTime = DateTimeOffset.Now + TimeSpan.FromSeconds(10);
Uri uri = ((CloudFilesProvider)provider).CreateTemporaryPublicUri(HttpMethod.GET, containerName, objectName, tempUrlKey, expirationTime);
WebRequest request = HttpWebRequest.Create(uri);
using (WebResponse response = request.GetResponse())
{
Stream cdnStream = response.GetResponseStream();
StreamReader reader = new StreamReader(cdnStream, Encoding.UTF8);
string text = reader.ReadToEnd();
Assert.AreEqual(fileContents, text);
}

provider.DeleteContainer(containerName, deleteObjects: true);
}

private static IEnumerable<Container> ListAllContainers(IObjectStorageProvider provider, int? blockSize = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null)
{
if (blockSize <= 0)
Expand Down

0 comments on commit 2d40127

Please sign in to comment.