Skip to content

Commit c0ec11a

Browse files
committed
Merge pull request #199 from sharwell/fix-167
Support custom headers in CreateContainer
2 parents dc6384d + 8c72c2e commit c0ec11a

File tree

3 files changed

+104
-86
lines changed

3 files changed

+104
-86
lines changed

src/corelib/Core/Providers/IObjectStorageProvider.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public interface IObjectStorageProvider
4848
/// Creates a container if it does not already exist.
4949
/// </summary>
5050
/// <param name="container">The container name.</param>
51+
/// <param name="headers">A collection of custom HTTP headers to associate with the container (see <see cref="GetContainerHeader"/>).</param>
5152
/// <param name="region">The region in which to execute this action. If not specified, the user's default region will be used.</param>
5253
/// <param name="useInternalUrl"><c>true</c> to use the endpoint's <see cref="Endpoint.InternalURL"/>; otherwise <c>false</c> to use the endpoint's <see cref="Endpoint.PublicURL"/>.</param>
5354
/// <param name="identity">The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used.</param>
@@ -60,7 +61,11 @@ public interface IObjectStorageProvider
6061
/// </list>
6162
/// </returns>
6263
/// <exception cref="ArgumentNullException">If <paramref name="container"/> is <c>null</c>.</exception>
63-
/// <exception cref="ArgumentException">If <paramref name="container"/> is empty.</exception>
64+
/// <exception cref="ArgumentException">
65+
/// If <paramref name="container"/> is empty.
66+
/// <para>-or-</para>
67+
/// <para>If <paramref name="headers"/> contains two equivalent keys when compared using <see cref="StringComparer.OrdinalIgnoreCase"/>.</para>
68+
/// </exception>
6469
/// <exception cref="ContainerNameException">If <paramref name="container"/> is not a valid container name.</exception>
6570
/// <exception cref="NotSupportedException">
6671
/// If the provider does not support the given <paramref name="identity"/> type.
@@ -76,7 +81,7 @@ public interface IObjectStorageProvider
7681
/// </exception>
7782
/// <exception cref="ResponseException">If the REST API request failed.</exception>
7883
/// <seealso href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/create-container.html">Create Container (OpenStack Object Storage API v1 Reference)</seealso>
79-
ObjectStore CreateContainer(string container, string region = null, bool useInternalUrl = false, CloudIdentity identity = null);
84+
ObjectStore CreateContainer(string container, Dictionary<string, string> headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null);
8085

8186
/// <summary>
8287
/// Deletes a container, and optionally all objects stored in the container.

src/corelib/Providers/Rackspace/CloudFilesProvider.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,11 +234,10 @@ public IEnumerable<Container> ListContainers(int? limit = null, string marker =
234234
return null;
235235

236236
return response.Data;
237-
238237
}
239238

240239
/// <inheritdoc />
241-
public ObjectStore CreateContainer(string container, string region = null, bool useInternalUrl = false, CloudIdentity identity = null)
240+
public ObjectStore CreateContainer(string container, Dictionary<string, string> headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null)
242241
{
243242
if (container == null)
244243
throw new ArgumentNullException("container");
@@ -249,7 +248,7 @@ public ObjectStore CreateContainer(string container, string region = null, bool
249248
_cloudFilesValidator.ValidateContainerName(container);
250249
var urlPath = new Uri(string.Format("{0}/{1}", GetServiceEndpointCloudFiles(identity, region, useInternalUrl), _encodeDecodeProvider.UrlEncode(container)));
251250

252-
var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT);
251+
var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.PUT, headers: headers);
253252

254253
switch (response.StatusCode)
255254
{

src/testing/integration/Providers/Rackspace/UserObjectStorageTests.cs

Lines changed: 95 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,71 @@ public void TestCreateContainer()
247247
provider.DeleteContainer(containerName, deleteObjects: true);
248248
}
249249

250+
[TestMethod]
251+
[TestCategory(TestCategories.User)]
252+
[TestCategory(TestCategories.ObjectStorage)]
253+
public void TestVersionedContainer()
254+
{
255+
IObjectStorageProvider provider = new CloudFilesProvider(Bootstrapper.Settings.TestIdentity);
256+
string containerName = TestContainerPrefix + Path.GetRandomFileName();
257+
string versionsContainerName = TestContainerPrefix + Path.GetRandomFileName();
258+
259+
ObjectStore result = provider.CreateContainer(versionsContainerName);
260+
Assert.AreEqual(ObjectStore.ContainerCreated, result);
261+
262+
result = provider.CreateContainer(containerName, new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { CloudFilesProvider.VersionsLocation, versionsContainerName } });
263+
Assert.AreEqual(ObjectStore.ContainerCreated, result);
264+
265+
Dictionary<string, string> headers = provider.GetContainerHeader(containerName);
266+
string location;
267+
Assert.IsTrue(headers.TryGetValue(CloudFilesProvider.VersionsLocation, out location));
268+
Assert.AreEqual(versionsContainerName, location);
269+
270+
string objectName = Path.GetRandomFileName();
271+
string fileData1 = "first-content";
272+
string fileData2 = "second-content";
273+
274+
/*
275+
* Create the object
276+
*/
277+
278+
using (MemoryStream uploadStream = new MemoryStream(Encoding.UTF8.GetBytes(fileData1)))
279+
{
280+
provider.CreateObject(containerName, uploadStream, objectName);
281+
}
282+
283+
string actualData = ReadAllObjectText(provider, containerName, objectName, Encoding.UTF8);
284+
Assert.AreEqual(fileData1, actualData);
285+
286+
/*
287+
* Overwrite the object
288+
*/
289+
290+
using (MemoryStream uploadStream = new MemoryStream(Encoding.UTF8.GetBytes(fileData2)))
291+
{
292+
provider.CreateObject(containerName, uploadStream, objectName);
293+
}
294+
295+
actualData = ReadAllObjectText(provider, containerName, objectName, Encoding.UTF8);
296+
Assert.AreEqual(fileData2, actualData);
297+
298+
/*
299+
* Delete the object once
300+
*/
301+
302+
provider.DeleteObject(containerName, objectName);
303+
304+
actualData = ReadAllObjectText(provider, containerName, objectName, Encoding.UTF8);
305+
Assert.AreEqual(fileData1, actualData);
306+
307+
/*
308+
* Cleanup
309+
*/
310+
311+
provider.DeleteContainer(versionsContainerName, deleteObjects: true);
312+
provider.DeleteContainer(containerName, deleteObjects: true);
313+
}
314+
250315
[TestMethod]
251316
[TestCategory(TestCategories.User)]
252317
[TestCategory(TestCategories.ObjectStorage)]
@@ -1083,15 +1148,8 @@ public void TestCreateObjectFromFile_UseFileName()
10831148
File.Delete(tempFilePath);
10841149
}
10851150

1086-
using (MemoryStream testStream = new MemoryStream())
1087-
{
1088-
provider.GetObject(containerName, Path.GetFileName(tempFilePath), testStream);
1089-
1090-
testStream.Position = 0;
1091-
StreamReader reader = new StreamReader(testStream, Encoding.UTF8);
1092-
string actualData = reader.ReadToEnd();
1093-
Assert.AreEqual(fileData, actualData);
1094-
}
1151+
string actualData = ReadAllObjectText(provider, containerName, Path.GetFileName(tempFilePath), Encoding.UTF8);
1152+
Assert.AreEqual(fileData, actualData);
10951153

10961154
/* Cleanup
10971155
*/
@@ -1128,15 +1186,8 @@ public void TestCreateObjectFromFile_UseCustomObjectName()
11281186
File.Delete(tempFilePath);
11291187
}
11301188

1131-
using (MemoryStream testStream = new MemoryStream())
1132-
{
1133-
provider.GetObject(containerName, objectName, testStream);
1134-
1135-
testStream.Position = 0;
1136-
StreamReader reader = new StreamReader(testStream, Encoding.UTF8);
1137-
string actualData = reader.ReadToEnd();
1138-
Assert.AreEqual(fileData, actualData);
1139-
}
1189+
string actualData = ReadAllObjectText(provider, containerName, objectName, Encoding.UTF8);
1190+
Assert.AreEqual(fileData, actualData);
11401191

11411192
/* Cleanup
11421193
*/
@@ -1168,15 +1219,8 @@ public void TestCreateObject()
11681219
Assert.IsTrue(progressMonitor.IsComplete, "Failed to notify progress monitor callback of status update.");
11691220
}
11701221

1171-
using (MemoryStream downloadStream = new MemoryStream())
1172-
{
1173-
provider.GetObject(containerName, objectName, downloadStream);
1174-
1175-
downloadStream.Position = 0;
1176-
StreamReader reader = new StreamReader(downloadStream, Encoding.UTF8);
1177-
string actualData = reader.ReadToEnd();
1178-
Assert.AreEqual(fileData, actualData);
1179-
}
1222+
string actualData = ReadAllObjectText(provider, containerName, objectName, Encoding.UTF8);
1223+
Assert.AreEqual(fileData, actualData);
11801224

11811225
/* Cleanup
11821226
*/
@@ -1337,39 +1381,18 @@ public void TestCopyObject()
13371381
provider.CreateObject(containerName, uploadStream, objectName, contentType);
13381382
}
13391383

1340-
using (MemoryStream downloadStream = new MemoryStream())
1341-
{
1342-
provider.GetObject(containerName, objectName, downloadStream);
1343-
1344-
downloadStream.Position = 0;
1345-
StreamReader reader = new StreamReader(downloadStream, Encoding.UTF8);
1346-
string actualData = reader.ReadToEnd();
1347-
Assert.AreEqual(fileData, actualData);
1348-
}
1384+
string actualData = ReadAllObjectText(provider, containerName, objectName, Encoding.UTF8);
1385+
Assert.AreEqual(fileData, actualData);
13491386

13501387
provider.CopyObject(containerName, objectName, containerName, copiedName);
13511388

13521389
// make sure the item is available at the copied location
1353-
using (MemoryStream downloadStream = new MemoryStream())
1354-
{
1355-
provider.GetObject(containerName, copiedName, downloadStream);
1356-
1357-
downloadStream.Position = 0;
1358-
StreamReader reader = new StreamReader(downloadStream, Encoding.UTF8);
1359-
string actualData = reader.ReadToEnd();
1360-
Assert.AreEqual(fileData, actualData);
1361-
}
1390+
actualData = ReadAllObjectText(provider, containerName, copiedName, Encoding.UTF8);
1391+
Assert.AreEqual(fileData, actualData);
13621392

13631393
// make sure the original object still exists
1364-
using (MemoryStream downloadStream = new MemoryStream())
1365-
{
1366-
provider.GetObject(containerName, objectName, downloadStream);
1367-
1368-
downloadStream.Position = 0;
1369-
StreamReader reader = new StreamReader(downloadStream, Encoding.UTF8);
1370-
string actualData = reader.ReadToEnd();
1371-
Assert.AreEqual(fileData, actualData);
1372-
}
1394+
actualData = ReadAllObjectText(provider, containerName, objectName, Encoding.UTF8);
1395+
Assert.AreEqual(fileData, actualData);
13731396

13741397
// make sure the content type was not changed by the copy operation
13751398
Assert.AreEqual(contentType, GetObjectContentType(provider, containerName, objectName));
@@ -1400,15 +1423,8 @@ public void TestMoveObject()
14001423
provider.CreateObject(containerName, uploadStream, objectName);
14011424
}
14021425

1403-
using (MemoryStream downloadStream = new MemoryStream())
1404-
{
1405-
provider.GetObject(containerName, objectName, downloadStream);
1406-
1407-
downloadStream.Position = 0;
1408-
StreamReader reader = new StreamReader(downloadStream, Encoding.UTF8);
1409-
string actualData = reader.ReadToEnd();
1410-
Assert.AreEqual(fileData, actualData);
1411-
}
1426+
string actualData = ReadAllObjectText(provider, containerName, objectName, Encoding.UTF8);
1427+
Assert.AreEqual(fileData, actualData);
14121428

14131429
provider.MoveObject(containerName, objectName, containerName, movedName);
14141430

@@ -1425,15 +1441,8 @@ public void TestMoveObject()
14251441
{
14261442
}
14271443

1428-
using (MemoryStream downloadStream = new MemoryStream())
1429-
{
1430-
provider.GetObject(containerName, movedName, downloadStream);
1431-
1432-
downloadStream.Position = 0;
1433-
StreamReader reader = new StreamReader(downloadStream, Encoding.UTF8);
1434-
string actualData = reader.ReadToEnd();
1435-
Assert.AreEqual(fileData, actualData);
1436-
}
1444+
actualData = ReadAllObjectText(provider, containerName, movedName, Encoding.UTF8);
1445+
Assert.AreEqual(fileData, actualData);
14371446

14381447
/* Cleanup
14391448
*/
@@ -1459,15 +1468,8 @@ public void TestDeleteObject()
14591468
provider.CreateObject(containerName, uploadStream, objectName);
14601469
}
14611470

1462-
using (MemoryStream downloadStream = new MemoryStream())
1463-
{
1464-
provider.GetObject(containerName, objectName, downloadStream);
1465-
1466-
downloadStream.Position = 0;
1467-
StreamReader reader = new StreamReader(downloadStream, Encoding.UTF8);
1468-
string actualData = reader.ReadToEnd();
1469-
Assert.AreEqual(fileData, actualData);
1470-
}
1471+
string actualData = ReadAllObjectText(provider, containerName, objectName, Encoding.UTF8);
1472+
Assert.AreEqual(fileData, actualData);
14711473

14721474
provider.DeleteObject(containerName, objectName);
14731475

@@ -1762,5 +1764,17 @@ private static void CheckMetadataSubset(Dictionary<string, string> expected, Dic
17621764
foreach (var pair in expected)
17631765
Assert.IsTrue(actual.Contains(pair), "Expected metadata item {{ {0} : {1} }} not found.", pair.Key, pair.Value);
17641766
}
1767+
1768+
private static string ReadAllObjectText(IObjectStorageProvider provider, string containerName, string objectName, Encoding encoding, int chunkSize = 65536, Dictionary<string, string> headers = null, string region = null, bool verifyEtag = false, Action<long> progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null)
1769+
{
1770+
using (MemoryStream downloadStream = new MemoryStream())
1771+
{
1772+
provider.GetObject(containerName, objectName, downloadStream, chunkSize, headers, region, verifyEtag, progressUpdated, useInternalUrl, identity);
1773+
1774+
downloadStream.Position = 0;
1775+
StreamReader reader = new StreamReader(downloadStream, encoding);
1776+
return reader.ReadToEnd();
1777+
}
1778+
}
17651779
}
17661780
}

0 commit comments

Comments
 (0)