Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit 09772c2

Browse files
committed
Added support for static websites
1 parent cf04b31 commit 09772c2

File tree

9 files changed

+378
-14
lines changed

9 files changed

+378
-14
lines changed

ChangeLog.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
XXXX.XX.XX Version X.X.X
2+
* Support for 2018-03-28 REST version. Please see our REST API documentation and blogs for information about the related added features.
3+
* Added support for static website properties.
4+
15
2018.05.22 Version 7.1.0
26
* Support for 2017-11-09 REST version. Please see our REST API documentation and blogs for information about the related added features.
37
* Added OAuth token support for authentication with HTTPS requests.

microsoft-azure-storage-test/src/com/microsoft/azure/storage/ServicePropertiesTests.java

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import com.microsoft.azure.storage.TestRunners.CloudTests;
2424
import com.microsoft.azure.storage.TestRunners.DevFabricTests;
2525
import com.microsoft.azure.storage.TestRunners.DevStoreTests;
26-
import com.microsoft.azure.storage.TestRunners.SlowTests;
2726

2827
import org.junit.Test;
2928
import org.junit.experimental.categories.Category;
@@ -49,6 +48,7 @@ public void testAnalyticsDisable() throws StorageException, InterruptedException
4948
ServiceClient client = TestHelper.createCloudBlobClient();
5049
ServiceProperties props = new ServiceProperties();
5150
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
51+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
5252
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
5353
testAnalyticsDisable(client, props);
5454

@@ -93,6 +93,7 @@ public void testAnalyticsDefaultServiceVersion() throws StorageException, Interr
9393
ServiceClient client = TestHelper.createCloudBlobClient();
9494
ServiceProperties props = new ServiceProperties();
9595
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
96+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
9697
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
9798
testAnalyticsDefaultServiceVersion(client, props);
9899

@@ -154,6 +155,7 @@ public void testAnalyticsLoggingOperations() throws StorageException, Interrupte
154155
ServiceClient client = TestHelper.createCloudBlobClient();
155156
ServiceProperties props = new ServiceProperties();
156157
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
158+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
157159
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
158160
testAnalyticsLoggingOperations(client, props);
159161

@@ -196,6 +198,7 @@ public void testAnalyticsHourMetricsLevel() throws StorageException, Interrupted
196198
ServiceProperties props = new ServiceProperties();
197199
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
198200
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
201+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
199202
testAnalyticsHourMetricsLevel(client, props, null);
200203

201204
client = TestHelper.createCloudQueueClient();
@@ -264,6 +267,7 @@ public void testAnalyticsMinuteMetricsLevel() throws StorageException, Interrupt
264267
ServiceClient client = TestHelper.createCloudBlobClient();
265268
ServiceProperties props = new ServiceProperties();
266269
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
270+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
267271
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
268272
testAnalyticsMinuteMetricsLevel(client, props, null);
269273

@@ -333,6 +337,7 @@ public void testAnalyticsRetentionPolicies() throws StorageException, Interrupte
333337
ServiceClient client = TestHelper.createCloudBlobClient();
334338
ServiceProperties props = new ServiceProperties();
335339
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
340+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
336341
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
337342
testAnalyticsRetentionPolicies(client, props);
338343

@@ -434,6 +439,7 @@ private void testValidDeleteRetentionPolicy(ServiceClient client, boolean enable
434439
ServiceProperties expectedServiceProperties = new ServiceProperties();
435440
expectedServiceProperties.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
436441
expectedServiceProperties.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
442+
expectedServiceProperties.setStaticWebsiteProperties(new StaticWebsiteProperties());
437443

438444
if (enabled) {
439445
expectedServiceProperties.getDeleteRetentionPolicy().setEnabled(true);
@@ -532,6 +538,7 @@ public void testEmptyDeleteRetentionPolicy() throws StorageException, Interrupte
532538
ServiceProperties currentServiceProperties = new ServiceProperties();
533539
currentServiceProperties.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
534540
currentServiceProperties.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
541+
currentServiceProperties.setStaticWebsiteProperties(new StaticWebsiteProperties());
535542
currentServiceProperties.getDeleteRetentionPolicy().setEnabled(true);
536543
currentServiceProperties.getDeleteRetentionPolicy().setRetentionIntervalInDays(5);
537544
callUploadServiceProps(client, currentServiceProperties, null);
@@ -554,6 +561,79 @@ public void testEmptyDeleteRetentionPolicy() throws StorageException, Interrupte
554561
}
555562
}
556563

564+
@Test
565+
public void testValidStaticWebsiteProperties() throws StorageException, InterruptedException {
566+
ServiceClient client = TestHelper.createCloudBlobClient();
567+
// average setting
568+
testValidStaticWebsiteProperties(client, true, "index.html", "errors/error/404error.html");
569+
570+
// disabled setting
571+
testValidStaticWebsiteProperties(client, false, "index.html", "errors/error/404error.html");
572+
}
573+
574+
private void testValidStaticWebsiteProperties(ServiceClient client, boolean enabled, String index, String pathTo404) throws InterruptedException, StorageException {
575+
try {
576+
ServiceProperties expectedServiceProperties = new ServiceProperties();
577+
expectedServiceProperties.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
578+
expectedServiceProperties.setStaticWebsiteProperties(new StaticWebsiteProperties());
579+
expectedServiceProperties.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
580+
581+
if (enabled) {
582+
expectedServiceProperties.getStaticWebsiteProperties().setEnabled(true);
583+
expectedServiceProperties.getStaticWebsiteProperties().setIndexDocument(index);
584+
expectedServiceProperties.getStaticWebsiteProperties().setErrorDocument404Path(pathTo404);
585+
callUploadServiceProps(client, expectedServiceProperties, null);
586+
} else {
587+
// index document and error document path will be ignored by the service when the properties are not enabled.
588+
ServiceProperties propertiesToUpload = new ServiceProperties();
589+
propertiesToUpload.setStaticWebsiteProperties(new StaticWebsiteProperties());
590+
propertiesToUpload.getStaticWebsiteProperties().setIndexDocument(index);
591+
propertiesToUpload.getStaticWebsiteProperties().setErrorDocument404Path(pathTo404);
592+
593+
expectedServiceProperties.getStaticWebsiteProperties().setEnabled(false);
594+
callUploadServiceProps(client, propertiesToUpload, null);
595+
}
596+
597+
// verify
598+
assertServicePropertiesAreEqual(expectedServiceProperties, callDownloadServiceProperties(client));
599+
}
600+
finally {
601+
// disable the static websites
602+
ServiceProperties disabledStaticWebsiteProperties = new ServiceProperties();
603+
disabledStaticWebsiteProperties.setStaticWebsiteProperties(new StaticWebsiteProperties());
604+
callUploadServiceProps(client, disabledStaticWebsiteProperties, null);
605+
}
606+
}
607+
608+
@Test
609+
public void testEmptyStaticWebsiteProperties() throws StorageException, InterruptedException {
610+
ServiceClient client = TestHelper.createCloudBlobClient();
611+
612+
// set up initial static website properties
613+
ServiceProperties currentServiceProperties = new ServiceProperties();
614+
StaticWebsiteProperties properties = new StaticWebsiteProperties();
615+
properties.setEnabled(true);
616+
properties.setIndexDocument("index.html");
617+
properties.setErrorDocument404Path("path/to/404");
618+
currentServiceProperties.setStaticWebsiteProperties(properties);
619+
currentServiceProperties.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
620+
currentServiceProperties.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
621+
callUploadServiceProps(client, currentServiceProperties, null);
622+
623+
// verify
624+
assertServicePropertiesAreEqual(currentServiceProperties, callDownloadServiceProperties(client));
625+
626+
// try to upload empty properties
627+
ServiceProperties emptyServiceProperties = new ServiceProperties();
628+
emptyServiceProperties.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
629+
emptyServiceProperties.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
630+
emptyServiceProperties.setStaticWebsiteProperties(new StaticWebsiteProperties());
631+
callUploadServiceProps(client, emptyServiceProperties, null);
632+
633+
// verify
634+
assertServicePropertiesAreEqual(emptyServiceProperties, callDownloadServiceProperties(client));
635+
}
636+
557637
/**
558638
* Test CORS with different rules.
559639
*
@@ -565,6 +645,7 @@ public void testCloudValidCorsRules() throws StorageException, InterruptedExcept
565645
ServiceClient client = TestHelper.createCloudBlobClient();
566646
ServiceProperties props = new ServiceProperties();
567647
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
648+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
568649
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
569650
testCloudValidCorsRules(client, props, null);
570651

@@ -689,6 +770,7 @@ public void testCorsExpectedExceptions() throws StorageException {
689770
ServiceClient client = TestHelper.createCloudBlobClient();
690771
ServiceProperties props = new ServiceProperties();
691772
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
773+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
692774
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
693775
testCorsExpectedExceptions(client, props, null);
694776

@@ -753,6 +835,7 @@ public void testCorsMaxOrigins() throws StorageException, InterruptedException {
753835
ServiceClient client = TestHelper.createCloudBlobClient();
754836
ServiceProperties props = new ServiceProperties();
755837
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
838+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
756839
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
757840
testCorsMaxOrigins(client, props, null);
758841

@@ -805,6 +888,7 @@ public void testCorsMaxHeaders() throws StorageException, InterruptedException {
805888
ServiceClient client = TestHelper.createCloudBlobClient();
806889
ServiceProperties props = new ServiceProperties();
807890
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
891+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
808892
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
809893
testCorsMaxHeaders(client, props, null);
810894

@@ -909,6 +993,7 @@ public void testOptionalServiceProperties() throws StorageException, Interrupted
909993
ServiceClient client = TestHelper.createCloudBlobClient();
910994
ServiceProperties props = new ServiceProperties();
911995
props.setDeleteRetentionPolicy(new DeleteRetentionPolicy());
996+
props.setStaticWebsiteProperties(new StaticWebsiteProperties());
912997
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
913998
testOptionalServiceProperties(client, props);
914999

@@ -991,7 +1076,7 @@ else if (client.getClass().equals(CloudFileClient.class)) {
9911076
else {
9921077
fail();
9931078
}
994-
1079+
9951080
// It may take up to 30 seconds for the settings to take effect, but the new properties are immediately
9961081
// visible when querying service properties.
9971082
}
@@ -1144,6 +1229,16 @@ private static void assertServicePropertiesAreEqual(ServiceProperties propsA, Se
11441229
assertNull(propsA.getDeleteRetentionPolicy());
11451230
assertNull(propsB.getDeleteRetentionPolicy());
11461231
}
1232+
1233+
if (propsA.getStaticWebsiteProperties() != null && propsB.getStaticWebsiteProperties() != null) {
1234+
assertEquals(propsA.getStaticWebsiteProperties().getEnabled(), propsB.getStaticWebsiteProperties().getEnabled());
1235+
assertEquals(propsA.getStaticWebsiteProperties().getIndexDocument(), propsB.getStaticWebsiteProperties().getIndexDocument());
1236+
assertEquals(propsA.getStaticWebsiteProperties().getErrorDocument404Path(), propsB.getStaticWebsiteProperties().getErrorDocument404Path());
1237+
}
1238+
else {
1239+
assertNull(propsA.getStaticWebsiteProperties());
1240+
assertNull(propsB.getStaticWebsiteProperties());
1241+
}
11471242
}
11481243

11491244
/**

microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,7 @@
2121
import java.net.HttpURLConnection;
2222
import java.net.URISyntaxException;
2323
import java.security.InvalidKeyException;
24-
import java.util.Calendar;
25-
import java.util.Date;
26-
import java.util.EnumSet;
27-
import java.util.GregorianCalendar;
28-
import java.util.HashMap;
29-
import java.util.Iterator;
30-
import java.util.List;
31-
import java.util.Random;
32-
import java.util.TimeZone;
33-
import java.util.UUID;
24+
import java.util.*;
3425

3526
import org.junit.After;
3627
import org.junit.Before;
@@ -88,6 +79,7 @@ public void testCloudBlobContainerNameValidation()
8879
NameValidator.validateContainerName("middle-dash");
8980
NameValidator.validateContainerName("$root");
9081
NameValidator.validateContainerName("$logs");
82+
NameValidator.validateContainerName("$web");
9183

9284
invalidContainertTestHelper(null, "Null containers invalid.", "Invalid container name. The name may not be null, empty, or whitespace only.");
9385
invalidContainertTestHelper("$ROOT", "Root container case sensitive.", "Invalid container name. Check MSDN for more information about valid naming.");
@@ -917,4 +909,94 @@ private static void assertCreatedAndListedBlobsEquivalent(CloudBlockBlob created
917909
assertEquals(Long.valueOf(length), state2.getTotalBytes());
918910
}
919911
}
912+
913+
private void validateWebContainer(CloudBlobContainer webContainer) throws URISyntaxException, StorageException, IOException {
914+
CloudBlockBlob blob0 = webContainer.getBlockBlobReference("blob");
915+
// Content type is important for the $web container
916+
blob0.getProperties().setContentType("multipart/form-data; boundary=thingz");
917+
CloudBlockBlob blob1 = webContainer.getBlockBlobReference("blob/abcd");
918+
blob1.getProperties().setContentType("image/gif");
919+
CloudBlockBlob blob2 = webContainer.getBlockBlobReference("blob/other.html");
920+
blob2.getProperties().setContentType("text/html; charset=utf-8");
921+
922+
List<CloudBlockBlob> expectedBlobs = Arrays.asList(blob0, blob1, blob2);
923+
List<String> texts = Arrays.asList("blob0text", "blob1text", "blob2text");
924+
for(int i=0; i<3; i++) {
925+
expectedBlobs.get(i).uploadText(texts.get(i));
926+
}
927+
Iterable<ListBlobItem> blobs = webContainer.listBlobs("", true);
928+
int i = 0;
929+
for (ListBlobItem blob : blobs) {
930+
CloudBlob cloudBlob = (CloudBlob)blob;
931+
assertEquals(expectedBlobs.get(i).getName(), cloudBlob.getName());
932+
assertEquals(expectedBlobs.get(i).getProperties().getContentType(), cloudBlob.getProperties().getContentType());
933+
assertEquals(texts.get(i), ((CloudBlockBlob)cloudBlob).downloadText());
934+
i++;
935+
}
936+
assertEquals(expectedBlobs.size(), i);
937+
}
938+
939+
@Test
940+
@Category({ DevFabricTests.class, DevStoreTests.class })
941+
public void testCloudBlobContainerWebContainer() throws StorageException, URISyntaxException, InterruptedException, IOException, InvalidKeyException {
942+
// Test operations with Shared Key
943+
CloudBlobClient blobClient = TestHelper.createCloudBlobClient();
944+
CloudBlobContainer webContainer = blobClient.getContainerReference("$web");
945+
try {
946+
webContainer.deleteIfExists();
947+
assertFalse(webContainer.exists());
948+
long now = System.currentTimeMillis();
949+
950+
while(true) {
951+
try{
952+
if (webContainer.createIfNotExists() || (System.currentTimeMillis()-now)/1000 < 30) {
953+
break;
954+
}
955+
}
956+
catch (Exception e){
957+
Thread.sleep(1000);
958+
}
959+
}
960+
assertTrue(webContainer.exists());
961+
boolean webContainerFound = false;
962+
for(CloudBlobContainer container :blobClient.listContainers("$")) {
963+
if (container.getName().equals(webContainer.getName())) {
964+
webContainerFound = true;
965+
}
966+
}
967+
assertTrue(webContainerFound);
968+
969+
validateWebContainer(webContainer);
970+
971+
// Clearing out the old data is faster than deleting/recreating.
972+
for (ListBlobItem blob : webContainer.listBlobs("", true)) {
973+
CloudBlob cloudBlob = (CloudBlob)blob;
974+
cloudBlob.delete();
975+
}
976+
977+
// Test operations with SAS
978+
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
979+
cal.setTime(new Date());
980+
cal.add(Calendar.SECOND, 60);
981+
SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy();
982+
policy.setSharedAccessExpiryTime(cal.getTime());
983+
policy.setPermissions(EnumSet.of(SharedAccessBlobPermissions.READ, SharedAccessBlobPermissions.WRITE, SharedAccessBlobPermissions.LIST,
984+
SharedAccessBlobPermissions.DELETE));
985+
String sas = webContainer.generateSharedAccessSignature(policy, null);
986+
CloudBlobContainer sasContainer = new CloudBlobContainer(webContainer.getUri(), new StorageCredentialsSharedAccessSignature(sas));
987+
validateWebContainer(sasContainer);
988+
webContainer.delete();
989+
990+
webContainerFound = false;
991+
for(CloudBlobContainer container :blobClient.listContainers("$")) {
992+
if (container.getName().equals(webContainer.getName())) {
993+
webContainerFound = true;
994+
}
995+
}
996+
assertFalse(webContainerFound);
997+
}
998+
finally {
999+
webContainer.deleteIfExists();
1000+
}
1001+
}
9201002
}

microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,21 @@ public static class AnalyticsConstants {
203203
*/
204204
public static final String RETENTION_POLICY_ELEMENT = "RetentionPolicy";
205205

206+
/**
207+
* The XML element for Static Website.
208+
*/
209+
public static final String STATIC_WEBSITE_ELEMENT = "StaticWebsite";
210+
211+
/**
212+
* The XML element for IndexDocument
213+
*/
214+
public static final String STATIC_WEBSITE_INDEX_DOCUMENT_ELEMENT = "IndexDocument";
215+
216+
/**
217+
* THe XML element for ErroDocument404PathName.
218+
*/
219+
public static final String STATIC_WEBSITE_ERROR_DOCUMENT_404_PATH_ELEMENT = "ErrorDocument404Path";
220+
206221
/**
207222
* The XML element for the StorageServiceProperties
208223
*/
@@ -655,7 +670,7 @@ public static class HeaderConstants {
655670
/**
656671
* The current storage version header value.
657672
*/
658-
public static final String TARGET_STORAGE_VERSION = "2017-11-09";
673+
public static final String TARGET_STORAGE_VERSION = "2018-03-28";
659674

660675
/**
661676
* The header that specifies the next visible time for a queue message.

0 commit comments

Comments
 (0)