From 0e5ffbbcf53fac75243be7a30ad561c6da5bf29a Mon Sep 17 00:00:00 2001 From: pemari-msft Date: Fri, 1 Aug 2014 11:23:39 -0700 Subject: [PATCH] aXSCL 0.3.0 --- ChangeLog.txt | 7 +- README.md | 4 +- .../AndroidManifest.xml | 2 +- .../AndroidManifest.xml | 2 +- .../analytics/CloudAnalyticsClientTests.java | 7 +- .../storage/blob/CloudBlobContainerTests.java | 37 ++++ .../storage/blob/CloudBlockBlobTests.java | 32 +++ .../storage/file/CloudFileDirectoryTests.java | 36 ++++ .../storage/file/CloudFileShareTests.java | 34 ++++ .../azure/storage/file/CloudFileTests.java | 36 ++++ .../azure/storage/queue/CloudQueueTests.java | 50 ++++- .../azure/storage/table/TableTests.java | 39 +++- microsoft-azure-storage/AndroidManifest.xml | 2 +- microsoft-azure-storage/pom.xml | 2 +- .../microsoft/azure/storage/Constants.java | 2 +- .../azure/storage/NameValidator.java | 184 ++++++++++++++++++ .../analytics/LogRecordStreamReader.java | 4 +- .../com/microsoft/azure/storage/core/SR.java | 12 ++ .../storage/file/CloudFileDirectory.java | 2 +- .../azure/storage/file/FileRange.java | 4 +- 20 files changed, 474 insertions(+), 24 deletions(-) create mode 100644 microsoft-azure-storage/src/com/microsoft/azure/storage/NameValidator.java diff --git a/ChangeLog.txt b/ChangeLog.txt index 9ba93de..fcac14f 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,7 +1,12 @@ +2014.08.01 Version 0.3.0 + * Added the NameValidator class which contains helpers that check to see if resource names are valid. + * Fixed a bug where the RequestUrl of a LogRecord was not correctly HTML4 decoded. + * Made FileRange class and ListFilesAndDirectories method in the CloudFileDirectory class public. + 2014.07.02 Version 0.2.0 * Added File Service support. The File Service and the associated SDK APIs are in preview. * Added CloudAnalyticsClient and related methods to simplify Storage Analytics logging and metrics use case scenarios. * Fixed a bug where an empty file would be left over during the downloadToFile error case. * Updated StorageErrorCodeStrings class. * Requests made using SAS credentials have the api-version query parameter appended to the URI. - * Fixed a null pointer exception that resulted when the first request was made with a blob created using the uri-only constructor (no sas creds appended). \ No newline at end of file + * Fixed a null pointer exception that resulted when the first request was made with a blob created using the uri-only constructor (no sas creds appended). diff --git a/README.md b/README.md index 0fca610..7985765 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ First, add mavenCentral to your repositories by adding the following to your gra Then, add a dependency by adding the following to your gradle build file: dependencies { - compile 'com.microsoft.azure.android:azure-storage-android:0.2.1@aar' + compile 'com.microsoft.azure.android:azure-storage-android:0.3.0@aar' } ###Option 4: aar via Maven @@ -55,7 +55,7 @@ To get the binaries of this library as distributed by Microsoft, ready for use w com.microsoft.azure.android azure-storage-android - 0.2.1 + 0.3.0 aar ``` diff --git a/microsoft-azure-storage-samples/AndroidManifest.xml b/microsoft-azure-storage-samples/AndroidManifest.xml index ef2aeae..cb50939 100644 --- a/microsoft-azure-storage-samples/AndroidManifest.xml +++ b/microsoft-azure-storage-samples/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:versionName="0.3.0" > + android:versionName="0.3.0" > logRecordsIterator = (this.client.listLogRecords(StorageService.BLOB, startTime.getTime(), null, null, null)).iterator(); @@ -314,6 +314,7 @@ public void testCloudAnalyticsClientParseProdLogs() throws ParseException, URISy // Makes sure there's no exceptions thrown and that no records are null. // Primarily a sanity check. LogRecord rec = logRecordsIterator.next(); + System.out.println(rec.getRequestUrl()); assertNotNull(rec); } } diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java index dd3c66c..9fcf67f 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java @@ -30,6 +30,7 @@ import junit.framework.TestCase; import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.ResultContinuation; import com.microsoft.azure.storage.ResultSegment; @@ -55,6 +56,42 @@ public void setUp() throws Exception { public void tearDown() throws Exception { this.container.deleteIfExists(); } + + /** + * Test container name validation. + */ + public void testCloudBlobContainerNameValidation() + { + NameValidator.validateContainerName("alpha"); + NameValidator.validateContainerName("4lphanum3r1c"); + NameValidator.validateContainerName("middle-dash"); + NameValidator.validateContainerName("$root"); + NameValidator.validateContainerName("$logs"); + + invalidContainertTestHelper(null, "Null containers invalid.", "Invalid container name. The name may not be null, empty, or whitespace only."); + invalidContainertTestHelper("$ROOT", "Root container case sensitive.", "Invalid container name. Check MSDN for more information about valid naming."); + invalidContainertTestHelper("double--dash", "Double dashes not allowed.", "Invalid container name. Check MSDN for more information about valid naming."); + invalidContainertTestHelper("-start-dash", "Start dashes not allowed.", "Invalid container name. Check MSDN for more information about valid naming."); + invalidContainertTestHelper("CapsLock", "Lowercase only.", "Invalid container name. Check MSDN for more information about valid naming."); + invalidContainertTestHelper("illegal$char", "Only alphanumeric and hyphen characters.", "Invalid container name. Check MSDN for more information about valid naming."); + invalidContainertTestHelper("illegal!char", "Only alphanumeric and hyphen characters.", "Invalid container name. Check MSDN for more information about valid naming."); + invalidContainertTestHelper("white space", "Only alphanumeric and hyphen characters.", "Invalid container name. Check MSDN for more information about valid naming."); + invalidContainertTestHelper("2c", "Root container case sensitive.", "Invalid container name length. The name must be between 3 and 63 characters long."); + invalidContainertTestHelper(new String(new char[64]).replace("\0", "n"), "Between 3 and 64 characters.", "Invalid container name length. The name must be between 3 and 63 characters long."); + } + + private void invalidContainertTestHelper(String containerName, String failMessage, String exceptionMessage) + { + try + { + NameValidator.validateContainerName(containerName); + fail(failMessage); + } + catch (IllegalArgumentException e) + { + assertEquals(exceptionMessage, e.getMessage()); + } + } /** * Validate container references diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java index 93703a6..fe2f9f6 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java @@ -39,6 +39,7 @@ import com.microsoft.azure.storage.AccessCondition; import com.microsoft.azure.storage.Constants; +import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.RetryNoRetry; import com.microsoft.azure.storage.SendingRequestEvent; @@ -66,6 +67,37 @@ public void tearDown() throws StorageException { this.container.deleteIfExists(); } + /** + * Test blob name validation. + */ + public void testCloudBlobNameValidation() + { + NameValidator.validateBlobName("alpha"); + NameValidator.validateBlobName("4lphanum3r1c"); + NameValidator.validateBlobName("CAPSLOCK"); + NameValidator.validateBlobName("white space"); + NameValidator.validateBlobName("th3r(h@racter$"); + NameValidator.validateBlobName(new String(new char[253]).replace("\0", "a/a")); + + invalidBlobTestHelper("", "No empty strings.", "Invalid blob name. The name may not be null, empty, or whitespace only."); + invalidBlobTestHelper(null, "No null strings.", "Invalid blob name. The name may not be null, empty, or whitespace only."); + invalidBlobTestHelper(new String(new char[1025]).replace("\0", "n"), "Maximum 1024 characters.", "Invalid blob name length. The name must be between 1 and 1024 characters long."); + invalidBlobTestHelper(new String(new char[254]).replace("\0", "a/a"), "Maximum 254 path segments.", "The count of URL path segments (strings between '/' characters) as part of the blob name cannot exceed 254."); + } + + private void invalidBlobTestHelper(String blobName, String failMessage, String exceptionMessage) + { + try + { + NameValidator.validateBlobName(blobName); + fail(failMessage); + } + catch (IllegalArgumentException e) + { + assertEquals(exceptionMessage, e.getMessage()); + } + } + public void testBlobUriOnlyConstructors() throws URISyntaxException, StorageException, InvalidKeyException { URI blobURI = new URI(container.getUri().toString() + "/anonblob"); CloudBlockBlob blob = new CloudBlockBlob(blobURI); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java index 68f3d8e..8810d1f 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileDirectoryTests.java @@ -22,6 +22,7 @@ import junit.framework.TestCase; +import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.ResultSegment; import com.microsoft.azure.storage.SendingRequestEvent; @@ -47,6 +48,41 @@ public void setUp() throws URISyntaxException, StorageException { public void tearDown() throws StorageException { this.share.deleteIfExists(); } + + /** + * Test directory name validation. + */ + public void testCloudFileDirectoryNameValidation() + { + NameValidator.validateDirectoryName("alpha"); + NameValidator.validateDirectoryName("4lphanum3r1c"); + NameValidator.validateDirectoryName("middle-dash"); + NameValidator.validateDirectoryName("CAPS"); + NameValidator.validateDirectoryName("$root"); + NameValidator.validateDirectoryName(".."); + NameValidator.validateDirectoryName("CLOCK$"); + NameValidator.validateDirectoryName("endslash/"); + + invalidDirectoryTestHelper(null, "No null.", "Invalid directory name. The name may not be null, empty, or whitespace only."); + invalidDirectoryTestHelper("middle/slash", "Slashes only at the end.", "Invalid directory name. Check MSDN for more information about valid naming."); + invalidDirectoryTestHelper("illegal\"char", "Illegal character.", "Invalid directory name. Check MSDN for more information about valid naming."); + invalidDirectoryTestHelper("illegal:char?", "Illegal character.", "Invalid directory name. Check MSDN for more information about valid naming."); + invalidDirectoryTestHelper("", "Between 1 and 255 characters.", "Invalid directory name. The name may not be null, empty, or whitespace only."); + invalidDirectoryTestHelper(new String(new char[256]).replace("\0", "n"), "Between 1 and 255 characters.", "Invalid directory name length. The name must be between 1 and 255 characters long."); + } + + private void invalidDirectoryTestHelper(String directoryName, String failMessage, String exceptionMessage) + { + try + { + NameValidator.validateDirectoryName(directoryName); + fail(failMessage); + } + catch (IllegalArgumentException e) + { + assertEquals(exceptionMessage, e.getMessage()); + } + } private boolean CloudFileDirectorySetup(CloudFileShare share) throws URISyntaxException, StorageException { try { diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java index 77a481b..aabff44 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileShareTests.java @@ -19,6 +19,7 @@ import junit.framework.TestCase; +import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.SendingRequestEvent; import com.microsoft.azure.storage.StorageErrorCodeStrings; @@ -43,6 +44,39 @@ public void setUp() throws StorageException, URISyntaxException { public void tearDown() throws StorageException { this.share.deleteIfExists(); } + + /** + * Test share name validation. + */ + public void testCloudShareNameValidation() + { + NameValidator.validateShareName("alpha"); + NameValidator.validateShareName("4lphanum3r1c"); + NameValidator.validateShareName("middle-dash"); + + invalidShareTestHelper(null, "Null not allowed.", "Invalid share name. The name may not be null, empty, or whitespace only."); + invalidShareTestHelper("$root", "Alphanumeric or dashes only.", "Invalid share name. Check MSDN for more information about valid naming."); + invalidShareTestHelper("double--dash", "No double dash.", "Invalid share name. Check MSDN for more information about valid naming."); + invalidShareTestHelper("CapsLock", "Lowercase only.", "Invalid share name. Check MSDN for more information about valid naming."); + invalidShareTestHelper("illegal$char", "Alphanumeric or dashes only.", "Invalid share name. Check MSDN for more information about valid naming."); + invalidShareTestHelper("illegal!char", "Alphanumeric or dashes only.", "Invalid share name. Check MSDN for more information about valid naming."); + invalidShareTestHelper("white space", "Alphanumeric or dashes only.", "Invalid share name. Check MSDN for more information about valid naming."); + invalidShareTestHelper("2c", "Between 3 and 63 characters.", "Invalid share name length. The name must be between 3 and 63 characters long."); + invalidShareTestHelper(new String(new char[64]).replace("\0", "n"), "Between 3 and 63 characters.", "Invalid share name length. The name must be between 3 and 63 characters long."); + } + + private void invalidShareTestHelper(String shareName, String failMessage, String exceptionMessage) + { + try + { + NameValidator.validateShareName(shareName); + fail(failMessage); + } + catch (IllegalArgumentException e) + { + assertEquals(exceptionMessage, e.getMessage()); + } + } /** * Validate share references diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java index ff360d3..0172163 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/CloudFileTests.java @@ -31,6 +31,7 @@ import junit.framework.TestCase; +import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.RetryNoRetry; import com.microsoft.azure.storage.SendingRequestEvent; @@ -56,6 +57,41 @@ public void tearDown() throws StorageException { this.share.deleteIfExists(); } + /** + * Test file name validation. + */ + public void CloudFileNameValidation() + { + NameValidator.validateFileName("alpha"); + NameValidator.validateFileName("4lphanum3r1c"); + NameValidator.validateFileName("middle-dash"); + NameValidator.validateFileName("CAPS"); + NameValidator.validateFileName("$root"); + + invalidFileTestHelper(null, "No null.", "Invalid file name. The name may not be null, empty, or whitespace only."); + invalidFileTestHelper("..", "Reserved.", "Invalid file name. This name is reserved."); + invalidFileTestHelper("Clock$", "Reserved.", "Invalid file name. This name is reserved."); + invalidFileTestHelper("endslash/", "No slashes.", "Invalid file name. Check MSDN for more information about valid naming."); + invalidFileTestHelper("middle/slash", "No slashes.", "Invalid file name. Check MSDN for more information about valid naming."); + invalidFileTestHelper("illegal\"char", "Illegal characters.", "Invalid file name. Check MSDN for more information about valid naming."); + invalidFileTestHelper("illegal:char?", "Illegal characters.", "Invalid file name. Check MSDN for more information about valid naming."); + invalidFileTestHelper("", "Between 1 and 255 characters.", "Invalid file name. The name may not be null, empty, or whitespace only."); + invalidFileTestHelper(new String(new char[256]).replace("\0", "n"), "Between 1 and 255 characters.", "Invalid file name length. The name must be between 1 and 255 characters long."); + } + + private void invalidFileTestHelper(String fileName, String failMessage, String exceptionMessage) + { + try + { + NameValidator.validateFileName(fileName); + fail(failMessage); + } + catch (IllegalArgumentException e) + { + assertEquals(exceptionMessage, e.getMessage()); + } + } + /** * Test file creation and deletion. * diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java index c679d3c..22d2eed 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/queue/CloudQueueTests.java @@ -32,6 +32,7 @@ import com.microsoft.azure.storage.AuthenticationScheme; import com.microsoft.azure.storage.LocationMode; +import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.RetryNoRetry; import com.microsoft.azure.storage.SendingRequestEvent; @@ -60,6 +61,39 @@ public void tearDown() throws StorageException { this.queue.deleteIfExists(); } + /** + * Tests queue name validation. + */ + public void testCloudQueueNameValidation() + { + NameValidator.validateQueueName("alpha"); + NameValidator.validateQueueName("4lphanum3r1c"); + NameValidator.validateQueueName("middle-dash"); + + invalidQueueTestHelper(null, "Null not allowed.", "Invalid queue name. The name may not be null, empty, or whitespace only."); + invalidQueueTestHelper("$root", "Alphanumeric or dashes only.", "Invalid queue name. Check MSDN for more information about valid naming."); + invalidQueueTestHelper("double--dash", "No double dash.", "Invalid queue name. Check MSDN for more information about valid naming."); + invalidQueueTestHelper("CapsLock", "Lowercase only.", "Invalid queue name. Check MSDN for more information about valid naming."); + invalidQueueTestHelper("illegal$char", "Alphanumeric or dashes only.", "Invalid queue name. Check MSDN for more information about valid naming."); + invalidQueueTestHelper("illegal!char", "Alphanumeric or dashes only.", "Invalid queue name. Check MSDN for more information about valid naming."); + invalidQueueTestHelper("white space", "Alphanumeric or dashes only.", "Invalid queue name. Check MSDN for more information about valid naming."); + invalidQueueTestHelper("2c", "Between 3 and 63 characters.", "Invalid queue name length. The name must be between 3 and 63 characters long."); + invalidQueueTestHelper(new String(new char[64]).replace("\0", "n"), "Between 3 and 63 characters.", "Invalid queue name length. The name must be between 3 and 63 characters long."); + } + + private void invalidQueueTestHelper(String queueName, String failMessage, String exceptionMessage) + { + try + { + NameValidator.validateQueueName(queueName); + fail(failMessage); + } + catch (IllegalArgumentException e) + { + assertEquals(exceptionMessage, e.getMessage()); + } + } + /** * Get permissions from string */ @@ -640,14 +674,14 @@ public void testAddMessage() throws StorageException { assertEquals(message.getMessageContentAsString(), msgContent); assertEquals(msgFromRetrieve1.getMessageContentAsString(), msgContent); } - - public void testAddMessageUnicode() throws StorageException { + + public void testAddMessageUnicode() throws StorageException { ArrayList messages = new ArrayList(); - messages.add("Le débat sur l'identité nationale, l'idée du président Nicolas Sarkozy de déchoir des personnes d'origine étrangère de la nationalité française ... certains cas et les récentes mesures prises contre les Roms ont choqué les experts, qui rendront leurs conclusions le 27 août."); - messages.add("�’�°Ñˆ �»�¾�³�¸�½ Yahoo! �´�°�µÑ‚ �´�¾Ñ�ту�¿ �º Ñ‚�°�º�¸�¼ �¼�¾Ñ‰�½Ñ‹�¼ �¸�½Ñ�тру�¼�µ�½Ñ‚�°�¼ Ñ��²Ñ��·�¸, �º�°�º Ñ��»�µ�ºÑ‚Ñ€�¾�½�½�°Ñ� �¿�¾Ñ‡Ñ‚�°, �¾Ñ‚�¿Ñ€�°�²�º�° �¼�³�½�¾�²�µ�½�½Ñ‹Ñ… Ñ��¾�¾�±Ñ‰�µ�½�¸�¹, фу�½�ºÑ†�¸�¸ �±�µ�·�¾�¿�°Ñ��½�¾Ñ�Ñ‚�¸, �² ч�°Ñ�Ñ‚�½�¾Ñ�Ñ‚�¸, �°�½Ñ‚�¸�²�¸Ñ€ÑƒÑ��½Ñ‹�µ Ñ�Ñ€�µ�´Ñ�Ñ‚�²�° �¸ �±�»�¾�º�¸Ñ€�¾�²Ñ‰�¸�º �²Ñ��¿�»Ñ‹�²�°ÑŽÑ‰�µ�¹ Ñ€�µ�º�»�°�¼Ñ‹, �¸ �¸�·�±Ñ€�°�½�½�¾�µ, �½�°�¿Ñ€�¸�¼�µÑ€, Ñ„�¾Ñ‚�¾ �¸ �¼Ñƒ�·Ñ‹�º�° �² Ñ��µÑ‚�¸ � �²Ñ��µ �±�µÑ��¿�»�°Ñ‚"); - messages.add("�新�社8月12æâ€â€�¥ç�µ 8月11æâ€â€�¥æ™šï¼ŒèˆŸæ›²å¢ƒå†…å†�次出现强é™�雨天æ°â€�,使特大山洪泥石æµ�ç�¾æƒ…雪上加霜。白龙江水在梨å��å­�æ�‘的交汇地带形æˆ�一个新的堰塞湖,水ä½�æ¯â€�å¹³æâ€â€�¶é«˜å‡º3米。çâ€�˜è‚ƒçœ�国土资æº�厅副厅长张国å�Žå½“æâ€â€�Â¥22æâ€â€�¶è®¸åœ¨æ–°éâ€â€�»å�‘布会上介ç»�,截至12æâ€â€�Â¥21æâ€â€�¶50分,舟曲堰塞湖堰塞体已消除,溃�险情已消除,目�针对堰塞湖的主�工作是�通河�。"); - messages.add("ל כול�\", �ד�י� יעלון, ויישר קו ע� �עדות שמסר ר�ש �ממשל�, בנימין נתני�ו, לוועדת טירקל. לדבריו, �כן �שרי� דנו רק ב�יבטי� �תקשורתיי� של עצירת �משט: \"בשביעיי� ל� �תקיי� דיון על ��לטרנטיבות. עסקנו ב�יבטי� "); - messages.add("Prozent auf 0,5 Prozent. Im Vergleich zum Vorjahresquartal wuchs die deutsche Wirtschaft von Januar bis März um 2,1 Prozent. Auch das ist eine Korrektur nach oben, ursprünglich waren es hier 1,7 Prozent"); + messages.add("Le débat sur l'identité nationale, l'idée du président Nicolas Sarkozy de déchoir des personnes d'origine étrangère de la nationalité française ... certains cas et les récentes mesures prises contre les Roms ont choqué les experts, qui rendront leurs conclusions le 27 août."); + messages.add("Ваш логин Yahoo! дает доступ к таким мощным инструментам связи, как электронная почта, отправка мгновенных сообщений, функции безопасности, в частности, антивирусные средства и блокировщик всплывающей рекламы, и избранное, например, фото и музыка в сети — все бесплат"); + messages.add("据新华社8月12日电 8月11日晚,舟曲境内再次出现强降雨天气,使特大山洪泥石流灾情雪上加霜。白龙江水在梨坝子村的交汇地带形成一个新的堰塞湖,水位比平时高出3米。甘肃省国土资源厅副厅长张国华当日22时许在新闻发布会上介绍,截至12日21时50分,舟曲堰塞湖堰塞体已消除,溃坝险情已消除,目前针对堰塞湖的主要工作是疏通河道。"); + messages.add("ל כולם\", הדהים יעלון, ויישר קו עם העדות שמסר ראש הממשלה, בנימין נתניהו, לוועדת טירקל. לדבריו, אכן השרים דנו רק בהיבטים התקשורתיים של עצירת המשט: \"בשביעייה לא התקיים דיון על האלטרנטיבות. עסקנו בהיבטים "); + messages.add("Prozent auf 0,5 Prozent. Im Vergleich zum Vorjahresquartal wuchs die deutsche Wirtschaft von Januar bis März um 2,1 Prozent. Auch das ist eine Korrektur nach oben, ursprünglich waren es hier 1,7 Prozent"); messages.add("\n\n\n\n Computer Parts\n \n Motherboard\n ASUS\n " + "P3B-F\n 123.00\n \n \n Video Card\n ATI\n All-in-Wonder Pro\n 160.00\n \n \n Sound Card\n " + "Creative Labs\n Sound Blaster Live\n 80.00\n \n \n inch Monitor\n LG Electronics\n 995E\n 290.00\n \n"); @@ -719,7 +753,7 @@ public void testAddMessageToNonExistingQueue() throws StorageException, URISynt public void testQueueUnicodeAndXmlMessageTest() throws StorageException { - String msgContent = "好"; + String msgContent = "好"; final CloudQueueMessage message = new CloudQueueMessage(msgContent); this.queue.addMessage(message); CloudQueueMessage msgFromRetrieve1 = this.queue.retrieveMessage(); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTests.java index b6467ee..e7972db 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/table/TableTests.java @@ -31,6 +31,7 @@ import com.microsoft.azure.storage.CloudStorageAccount; import com.microsoft.azure.storage.LocationMode; +import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.RetryNoRetry; import com.microsoft.azure.storage.SendingRequestEvent; @@ -44,6 +45,43 @@ public class TableTests extends TestCase { + /** + * Tests name validation of tables. + */ + public void testCloudTableNameValidation() + { + NameValidator.validateTableName("alpha"); + NameValidator.validateTableName("alphanum3r1c"); + NameValidator.validateTableName("CapsLock"); + NameValidator.validateTableName("$MetricsTransactionsBlob"); + NameValidator.validateTableName("$MetricsHourPrimaryTransactionsTable"); + NameValidator.validateTableName("$MetricsMinuteSecondaryTransactionsQueue"); + NameValidator.validateTableName("tables"); + NameValidator.validateTableName("$MetricsCapacityBlob"); + + invalidTableTestHelper(null, "Null not allowed.", "Invalid table name. The name may not be null, empty, or whitespace only."); + invalidTableTestHelper("1numberstart", "Must start with a letter.", "Invalid table name. Check MSDN for more information about valid naming."); + invalidTableTestHelper("middle-dash", "Alphanumeric only.", "Invalid table name. Check MSDN for more information about valid naming."); + invalidTableTestHelper("illegal$char", "Alphanumeric only.", "Invalid table name. Check MSDN for more information about valid naming."); + invalidTableTestHelper("illegal!char", "Alphanumeric only.", "Invalid table name. Check MSDN for more information about valid naming."); + invalidTableTestHelper("white space", "Alphanumeric only.", "Invalid table name. Check MSDN for more information about valid naming."); + invalidTableTestHelper("cc", "Between 3 and 63 characters.", "Invalid table name length. The name must be between 3 and 63 characters long."); + invalidTableTestHelper(new String(new char[64]).replace("\0", "n"), "Between 3 and 63 characters.", "Invalid table name length. The name must be between 3 and 63 characters long."); + } + + private void invalidTableTestHelper(String tableName, String failMessage, String exceptionMessage) + { + try + { + NameValidator.validateTableName(tableName); + fail(failMessage); + } + catch (IllegalArgumentException e) + { + assertEquals(exceptionMessage, e.getMessage()); + } + } + public void testIsUsePathStyleUri() throws InvalidKeyException, URISyntaxException, StorageException { // normal account StorageCredentials creds = new StorageCredentialsAccountAndKey("testAccountName", @@ -96,7 +134,6 @@ private static void testIsUsePathStyleUri(StorageCredentials creds, String table /** * Get permissions from string */ - public void testTablePermissionsFromString() { Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); Date start = cal.getTime(); diff --git a/microsoft-azure-storage/AndroidManifest.xml b/microsoft-azure-storage/AndroidManifest.xml index 4595b34..b604911 100644 --- a/microsoft-azure-storage/AndroidManifest.xml +++ b/microsoft-azure-storage/AndroidManifest.xml @@ -11,7 +11,7 @@ + android:versionName="0.3.0" > diff --git a/microsoft-azure-storage/pom.xml b/microsoft-azure-storage/pom.xml index 3712392..4292696 100644 --- a/microsoft-azure-storage/pom.xml +++ b/microsoft-azure-storage/pom.xml @@ -10,7 +10,7 @@ 4.0.0 com.microsoft.azure.android azure-storage-android - 0.2.1 + 0.3.0 aar Microsoft Azure Storage Android Client SDK diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java index c5d1b93..a6e1b8b 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java @@ -515,7 +515,7 @@ public static class HeaderConstants { /** * Specifies the value to use for UserAgent header. */ - public static final String USER_AGENT_VERSION = "0.2.1"; + public static final String USER_AGENT_VERSION = "0.3.0"; /** * The default type for content-type and accept diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/NameValidator.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/NameValidator.java new file mode 100644 index 0000000..b736015 --- /dev/null +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/NameValidator.java @@ -0,0 +1,184 @@ +/** + * Copyright Microsoft Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.microsoft.azure.storage; + +import java.util.regex.Pattern; + +import com.microsoft.azure.storage.core.SR; +import com.microsoft.azure.storage.core.Utility; + +/** + * Provides helpers to validate resource names across the Microsoft Azure + * Storage Services. + */ +public class NameValidator { + private static final int BLOB_FILE_DIRECTORY_MIN_LENGTH = 1; + private static final int CONTAINER_SHARE_QUEUE_TABLE_MIN_LENGTH = 3; + private static final int CONTAINER_SHARE_QUEUE_TABLE_MAX_LENGTH = 63; + private static final int FILE_DIRECTORY_MAX_LENGTH = 255; + private static final int BLOB_MAX_LENGTH = 1024; + private static final Pattern FILE_DIRECTORY_REGEX = Pattern.compile("^[^\"\\/:|<>*?]*/{0,1}"); + private static final Pattern SHARE_CONTAINER_QUEUE_REGEX = Pattern.compile("^[a-z0-9]+(-[a-z0-9]+)*$"); + private static final Pattern TABLE_REGEX = Pattern.compile("^[A-Za-z][A-Za-z0-9]*$"); + private static final Pattern METRICS_TABLE_REGEX = Pattern.compile("^\\$Metrics(HourPrimary|MinutePrimary|HourSecondary|MinuteSecondary)?(Transactions)(Blob|Queue|Table)$"); + private static final String[] RESERVED_FILE_NAMES = { ".", "..", "LPT1", + "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", + "COM9", "PRN", "AUX", "NUL", "CON", "CLOCK$" }; + + /** + * Checks if a container name is valid. + * + * @param containerName + * A String representing the container name to validate. + */ + public static void validateContainerName(String containerName) { + if (!("$root".equals(containerName) || "$logs".equals(containerName))) { + NameValidator.validateShareContainerQueueHelper(containerName, SR.CONTAINER); + } + } + + /** + * Checks if a queue name is valid. + * + * @param queueName + * A String representing the queue name to validate. + */ + public static void validateQueueName(String queueName) { + NameValidator.validateShareContainerQueueHelper(queueName, SR.QUEUE); + } + + /** + * Checks if a share name is valid. + * + * @param shareName + * A String representing the share name to validate. + */ + public static void validateShareName(String shareName) { + NameValidator.validateShareContainerQueueHelper(shareName, SR.SHARE); + } + + private static void validateShareContainerQueueHelper(String resourceName, + String resourceType) { + if (Utility.isNullOrEmptyOrWhitespace(resourceName)) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.RESOURCE_NAME_EMPTY, resourceType)); + } + + if (resourceName.length() < NameValidator.CONTAINER_SHARE_QUEUE_TABLE_MIN_LENGTH || resourceName.length() > NameValidator.CONTAINER_SHARE_QUEUE_TABLE_MAX_LENGTH) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.INVALID_RESOURCE_NAME_LENGTH, resourceType, NameValidator.CONTAINER_SHARE_QUEUE_TABLE_MIN_LENGTH, NameValidator.CONTAINER_SHARE_QUEUE_TABLE_MAX_LENGTH)); + } + + if (!NameValidator.SHARE_CONTAINER_QUEUE_REGEX.matcher(resourceName).matches()) + { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.INVALID_RESOURCE_NAME, resourceType)); + } + } + + /** + * Checks if a blob name is valid. + * + * @param blobName + * A String representing the blob name to validate. + */ + public static void validateBlobName(String blobName) { + if (Utility.isNullOrEmptyOrWhitespace(blobName)) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.RESOURCE_NAME_EMPTY, SR.BLOB)); + } + + if (blobName.length() < NameValidator.BLOB_FILE_DIRECTORY_MIN_LENGTH || blobName.length() > NameValidator.BLOB_MAX_LENGTH) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.INVALID_RESOURCE_NAME_LENGTH, SR.BLOB, NameValidator.BLOB_FILE_DIRECTORY_MIN_LENGTH, NameValidator.BLOB_MAX_LENGTH)); + } + + int slashCount = 0; + for (int i = 0; i < blobName.length(); i++) + { + if (blobName.charAt(i) == '/') + { + slashCount++; + } + } + + if (slashCount >= 254) + { + throw new IllegalArgumentException(SR.TOO_MANY_PATH_SEGMENTS); + } + } + + /** + * Checks if a file name is valid. + * + * @param fileName + * A String representing the file name to validate. + */ + public static void validateFileName(String fileName) { + NameValidator.ValidateFileDirectoryHelper(fileName, SR.FILE); + + if (fileName.endsWith("/")) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.INVALID_RESOURCE_NAME, SR.FILE)); + } + + for (String s : NameValidator.RESERVED_FILE_NAMES) { + if (s.equalsIgnoreCase(fileName)) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.INVALID_RESOURCE_RESERVED_NAME, SR.FILE)); + } + } + } + + /** + * Checks if a directory name is valid. + * + * @param directoryName + * A String representing the directory name to validate. + */ + public static void validateDirectoryName(String directoryName) { + NameValidator.ValidateFileDirectoryHelper(directoryName, SR.DIRECTORY); + } + + private static void ValidateFileDirectoryHelper(String resourceName, String resourceType) { + if (Utility.isNullOrEmptyOrWhitespace(resourceName)) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.RESOURCE_NAME_EMPTY, resourceType)); + } + + if (resourceName.length() < NameValidator.BLOB_FILE_DIRECTORY_MIN_LENGTH || resourceName.length() > NameValidator.FILE_DIRECTORY_MAX_LENGTH) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.INVALID_RESOURCE_NAME_LENGTH, resourceType, NameValidator.BLOB_FILE_DIRECTORY_MIN_LENGTH, NameValidator.FILE_DIRECTORY_MAX_LENGTH )); + } + + if (!NameValidator.FILE_DIRECTORY_REGEX.matcher(resourceName).matches()) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.INVALID_RESOURCE_NAME, resourceType)); + } + } + + /** + * Checks if a table name is valid. + * + * @param tableName + * A String representing the table name to validate. + */ + public static void validateTableName(String tableName) { + if (Utility.isNullOrEmptyOrWhitespace(tableName)) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.RESOURCE_NAME_EMPTY, SR.TABLE)); + } + + if (tableName.length() < NameValidator.CONTAINER_SHARE_QUEUE_TABLE_MIN_LENGTH || tableName.length() > NameValidator.CONTAINER_SHARE_QUEUE_TABLE_MAX_LENGTH) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.INVALID_RESOURCE_NAME_LENGTH, SR.TABLE, NameValidator.CONTAINER_SHARE_QUEUE_TABLE_MIN_LENGTH, NameValidator.CONTAINER_SHARE_QUEUE_TABLE_MAX_LENGTH)); + } + + if (!(NameValidator.TABLE_REGEX.matcher(tableName).matches() + || NameValidator.METRICS_TABLE_REGEX.matcher(tableName).matches() + || tableName.equalsIgnoreCase("$MetricsCapacityBlob"))) { + throw new IllegalArgumentException(String.format(Utility.LOCALE_US, SR.INVALID_RESOURCE_NAME, SR.TABLE)); + } + } +} diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/analytics/LogRecordStreamReader.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/analytics/LogRecordStreamReader.java index 7d92767..3e539c0 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/analytics/LogRecordStreamReader.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/analytics/LogRecordStreamReader.java @@ -25,6 +25,8 @@ import java.util.Date; import java.util.UUID; +import android.text.Html; + import com.microsoft.azure.storage.core.SR; import com.microsoft.azure.storage.core.Utility; @@ -253,7 +255,7 @@ public URI readUri() throws URISyntaxException, IOException { return null; } else { - return new URI(temp); + return new URI(Html.fromHtml(temp).toString()); } } diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/SR.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/SR.java index 5a2de16..bbf6240 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/SR.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/SR.java @@ -23,6 +23,7 @@ public class SR { public static final String ARGUMENT_NULL_OR_EMPTY = "The argument must not be null or an empty string. Argument name: %s."; public static final String ARGUMENT_OUT_OF_RANGE_ERROR = "The argument is out of range. Argument name: %s, Value passed: %s."; public static final String ATTEMPTED_TO_SERIALIZE_INACCESSIBLE_PROPERTY = "An attempt was made to access an inaccessible member of the entity during serialization."; + public static final String BLOB = "blob"; public static final String BLOB_DATA_CORRUPTED = "Blob data corrupted (integrity check failed), Expected value is %s, retrieved %s"; public static final String BLOB_ENDPOINT_NOT_CONFIGURED = "No blob endpoint configured."; public static final String BLOB_HASH_MISMATCH = "Blob hash mismatch (integrity check failed), Expected value is %s, retrieved %s."; @@ -31,12 +32,14 @@ public class SR { public static final String CANNOT_CREATE_SAS_FOR_GIVEN_CREDENTIALS = "Cannot create Shared Access Signature as the credentials does not have account name information. Please check that the credentials provided support creating Shared Access Signature."; public static final String CANNOT_CREATE_SAS_FOR_SNAPSHOTS = "Cannot create Shared Access Signature via references to blob snapshots. Please perform the given operation on the root blob instead."; public static final String CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY = "Cannot create Shared Access Signature unless the Account Key credentials are used by the ServiceClient."; + public static final String CONTAINER = "container"; public static final String CONTENT_LENGTH_MISMATCH = "An incorrect number of bytes was read from the connection. The connection may have been closed."; public static final String CREATING_NETWORK_STREAM = "Creating a NetworkInputStream and expecting to read %s bytes."; public static final String CREDENTIALS_CANNOT_SIGN_REQUEST = "CloudBlobClient, CloudQueueClient and CloudTableClient require credentials that can sign a request."; public static final String CUSTOM_RESOLVER_THREW = "The custom property resolver delegate threw an exception. Check the inner exception for more details."; public static final String DEFAULT_SERVICE_VERSION_ONLY_SET_FOR_BLOB_SERVICE = "DefaultServiceVersion can only be set for the Blob service."; public static final String DELETE_SNAPSHOT_NOT_VALID_ERROR = "The option '%s' must be 'None' to delete a specific snapshot specified by '%s'."; + public static final String DIRECTORY = "directory"; public static final String EDMTYPE_WAS_NULL = "EdmType cannot be null."; public static final String ENUMERATION_ERROR = "An error occurred while enumerating the result, check the original exception for details."; public static final String EMPTY_BATCH_NOT_ALLOWED = "Cannot execute an empty batch operation."; @@ -54,6 +57,7 @@ public class SR { public static final String EXPECTED_START_ELEMENT_TO_EQUAL_ERROR = "Expected START_ELEMENT to equal error."; public static final String EXPECTED_START_OBJECT = "Expected the start of a JSON Object."; public static final String FAILED_TO_PARSE_PROPERTY = "Failed to parse property '%s' with value '%s' as type '%s'"; + public static final String FILE = "file"; public static final String FILE_ENDPOINT_NOT_CONFIGURED = "No file endpoint configured."; public static final String FILE_HASH_MISMATCH = "File hash mismatch (integrity check failed), Expected value is %s, retrieved %s."; public static final String FILE_MD5_NOT_POSSIBLE = "MD5 cannot be calculated for an existing file because it would require reading the existing data. Please disable StoreFileContentMD5."; @@ -84,6 +88,9 @@ public class SR { public static final String INVALID_PAGE_BLOB_LENGTH = "Page blob length must be multiple of 512."; public static final String INVALID_PAGE_START_OFFSET = "Page start offset must be multiple of 512."; public static final String INVALID_RANGE_CONTENT_MD5_HEADER = "Cannot specify x-ms-range-get-content-md5 header on ranges larger than 4 MB. Either use a BlobReadStream via openRead, or disable TransactionalMD5 via the BlobRequestOptions."; + public static final String INVALID_RESOURCE_NAME = "Invalid %s name. Check MSDN for more information about valid naming."; + public static final String INVALID_RESOURCE_NAME_LENGTH = "Invalid %s name length. The name must be between %s and %s characters long."; + public static final String INVALID_RESOURCE_RESERVED_NAME = "Invalid %s name. This name is reserved."; public static final String INVALID_RESPONSE_RECEIVED = "The response received is invalid or improperly formatted."; public static final String INVALID_STORAGE_PROTOCOL_VERSION = "Storage protocol version prior to 2009-09-19 do not support shared key authentication."; public static final String INVALID_STORAGE_SERVICE = "Invalid storage service specified."; @@ -117,8 +124,10 @@ public class SR { public static final String PROPERTY_CANNOT_BE_SERIALIZED_AS_GIVEN_EDMTYPE = "Property %s with Edm Type %s cannot be de-serialized."; public static final String QUERY_PARAMETER_NULL_OR_EMPTY = "Cannot encode a query parameter with a null or empty key."; public static final String QUERY_REQUIRES_VALID_CLASSTYPE_OR_RESOLVER = "Query requires a valid class type or resolver."; + public static final String QUEUE = "queue"; public static final String QUEUE_ENDPOINT_NOT_CONFIGURED = "No queue endpoint configured."; public static final String RELATIVE_ADDRESS_NOT_PERMITTED = "Address %s is a relative address. Only absolute addresses are permitted."; + public static final String RESOURCE_NAME_EMPTY = "Invalid %s name. The name may not be null, empty, or whitespace only."; public static final String RESPONSE_RECEIVED_IS_INVALID = "The response received is invalid or improperly formatted."; public static final String RETRIEVE_MUST_BE_ONLY_OPERATION_IN_BATCH = "A batch transaction with a retrieve operation cannot contain any other operations."; public static final String ROWKEY_MISSING_FOR_DELETE = "Delete requires a row key."; @@ -127,6 +136,7 @@ public class SR { public static final String ROWKEY_MISSING_FOR_INSERT = "Insert requires a row key."; public static final String SCHEME_NULL_OR_EMPTY = "The protocol to use is null. Please specify whether to use http or https."; public static final String SECONDARY_ONLY_COMMAND = "This operation can only be executed against the secondary storage location."; + public static final String SHARE = "share"; public static final String SNAPSHOT_LISTING_ERROR = "Listing snapshots is only supported in flat mode (no delimiter). Consider setting useFlatBlobListing to true."; public static final String SNAPSHOT_QUERY_OPTION_ALREADY_DEFINED = "Snapshot query parameter is already defined in the blob URI. Either pass in a snapshotTime parameter or use a full URL with a snapshot query parameter."; public static final String STORAGE_QUEUE_CREDENTIALS_NULL = "StorageCredentials cannot be null for the Queue service."; @@ -141,9 +151,11 @@ public class SR { public static final String STREAM_LENGTH_GREATER_THAN_4MB = "Invalid stream length, length must be less than or equal to 4 MB in size."; public static final String STREAM_LENGTH_NEGATIVE = "Invalid stream length, specify -1 for unknown length stream, or a positive number of bytes."; public static final String STRING_NOT_VALID = "The String is not a valid Base64-encoded string."; + public static final String TABLE = "table"; public static final String TABLE_ENDPOINT_NOT_CONFIGURED = "No table endpoint configured."; public static final String TABLE_OBJECT_RELATIVE_URIS_NOT_SUPPORTED = "Table Object relative URIs not supported."; public static final String TAKE_COUNT_ZERO_OR_NEGATIVE = "Take count must be positive and greater than 0."; + public static final String TOO_MANY_PATH_SEGMENTS = "The count of URL path segments (strings between '/' characters) as part of the blob name cannot exceed 254."; public static final String TOO_MANY_SHARED_ACCESS_POLICY_IDENTIFIERS = "Too many %d shared access policy identifiers provided. Server does not support setting more than %d on a single container, queue, or table."; public static final String TOO_MANY_SHARED_ACCESS_POLICY_IDS = "Too many %d shared access policy identifiers provided. Server does not support setting more than %d on a single container."; public static final String TYPE_NOT_SUPPORTED = "Type %s is not supported."; diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java index ecfd4a0..704b202 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java @@ -685,7 +685,7 @@ public ResultSegment listFilesAndDirectoriesSegmented() throws Sto * @throws StorageException * If a storage service error occurred. */ - private ResultSegment listFilesAndDirectoriesSegmented(final int maxResults, + public ResultSegment listFilesAndDirectoriesSegmented(final int maxResults, final ResultContinuation continuationToken, FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRange.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRange.java index 5fa9af7..459c796 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRange.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/FileRange.java @@ -15,9 +15,9 @@ package com.microsoft.azure.storage.file; /** - * RESERVED FOR INTERNAL USE. Represents a range of bytes in a file. + * Represents a range of bytes in a file. */ -final class FileRange { +public final class FileRange { /** * Represents the ending offset of the file range. */