From 960abc52657ddc33dca10f6e38a019721eae2d38 Mon Sep 17 00:00:00 2001 From: Jason Cooke Date: Thu, 8 Mar 2012 10:22:38 -0800 Subject: [PATCH 1/3] Fix #252 --- .../table/implementation/SharedKeyFilter.java | 2 +- .../services/table/implementation/TableRestProxy.java | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyFilter.java index ba12447147c8..7e2e95bb88f9 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyFilter.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyFilter.java @@ -77,7 +77,7 @@ public void sign(ClientRequest cr) { private String getCanonicalizedResource(ClientRequest cr) { String result = "/" + this.getAccountName(); - result += cr.getURI().getPath(); + result += cr.getURI().getRawPath(); List queryParams = SharedKeyUtils.getQueryParams(cr.getURI().getQuery()); for (QueryParam p : queryParams) { diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java index bfeddfdb5c80..e9a5dbc84649 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java @@ -159,7 +159,16 @@ private List encodeODataURIValues(List values) { } private String getEntityPath(String table, String partitionKey, String rowKey) { - return table + "(" + "PartitionKey='" + partitionKey + "',RowKey='" + rowKey + "')"; + String ret = "error"; + try { + ret = table + "(" + "PartitionKey='" + + URLEncoder.encode(partitionKey, "UTF-8").replace("+", "%20").replace("'", "%27") + "',RowKey='" + + URLEncoder.encode(rowKey, "UTF-8").replace("+", "%20").replace("'", "%27") + "')"; + System.out.println("ret : " + ret); + } + catch (UnsupportedEncodingException e) { + } + return ret; } private WebResource addOptionalQueryParam(WebResource webResource, String key, Object value) { From 2116310239a320d9083fc33256948479209212ce Mon Sep 17 00:00:00 2001 From: Jason Cooke Date: Tue, 3 Apr 2012 14:14:02 -0700 Subject: [PATCH 2/3] Added unit test Changed catch statement to perform a reasonable fallback if the URLEncoder call fails. Added missing imports statements. --- .../table/implementation/TableRestProxy.java | 15 ++++++----- .../table/TableServiceIntegrationTest.java | 26 +++++++++++++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java index e9a5dbc84649..10c343b87bb9 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java @@ -18,7 +18,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.net.URI; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; @@ -159,16 +161,17 @@ private List encodeODataURIValues(List values) { } private String getEntityPath(String table, String partitionKey, String rowKey) { - String ret = "error"; + return table + "(" + "PartitionKey='" + safeEncode(partitionKey) + "',RowKey='" + safeEncode(rowKey) + "')"; + } + + private String safeEncode(String input) { + String fixSingleQuotes = input.replace("'", "''"); try { - ret = table + "(" + "PartitionKey='" - + URLEncoder.encode(partitionKey, "UTF-8").replace("+", "%20").replace("'", "%27") + "',RowKey='" - + URLEncoder.encode(rowKey, "UTF-8").replace("+", "%20").replace("'", "%27") + "')"; - System.out.println("ret : " + ret); + return URLEncoder.encode(fixSingleQuotes, "UTF-8").replace("+", "%20"); } catch (UnsupportedEncodingException e) { + return fixSingleQuotes; } - return ret; } private WebResource addOptionalQueryParam(WebResource webResource, String key, Object value) { diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java index 4a4146a5055d..7a7de013076c 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java @@ -437,6 +437,32 @@ public void deleteEntityWorks() throws Exception { // Assert } + @Test + public void deleteEntityTroublesomeKeyWorks() throws Exception { + System.out.println("deleteEntityTroublesomeKeyWorks()"); + + // Arrange + Configuration config = createConfiguration(); + TableContract service = TableService.create(config); + Entity entity1 = new Entity().setPartitionKey("001").setRowKey("key with spaces"); + Entity entity2 = new Entity().setPartitionKey("001").setRowKey("key'with'quotes"); + Entity entity3 = new Entity().setPartitionKey("001").setRowKey("keyWithUnicode \uB2E4"); + Entity entity4 = new Entity().setPartitionKey("001").setRowKey("key 'with'' \uB2E4"); + + // Act + InsertEntityResult result1 = service.insertEntity(TEST_TABLE_2, entity1); + InsertEntityResult result2 = service.insertEntity(TEST_TABLE_2, entity2); + InsertEntityResult result3 = service.insertEntity(TEST_TABLE_2, entity3); + InsertEntityResult result4 = service.insertEntity(TEST_TABLE_2, entity4); + + service.deleteEntity(TEST_TABLE_2, result1.getEntity().getPartitionKey(), result1.getEntity().getRowKey()); + service.deleteEntity(TEST_TABLE_2, result2.getEntity().getPartitionKey(), result2.getEntity().getRowKey()); + service.deleteEntity(TEST_TABLE_2, result3.getEntity().getPartitionKey(), result3.getEntity().getRowKey()); + service.deleteEntity(TEST_TABLE_2, result4.getEntity().getPartitionKey(), result4.getEntity().getRowKey()); + + // Assert + } + @Test public void deleteEntityWithETagWorks() throws Exception { System.out.println("deleteEntityWithETagWorks()"); From bea4d6ce2e7a87b429b56623d0518ff0028c328b Mon Sep 17 00:00:00 2001 From: Jason Cooke Date: Wed, 4 Apr 2012 09:22:55 -0700 Subject: [PATCH 3/3] Adding more validation to unit test --- .../table/TableServiceIntegrationTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java index 7a7de013076c..aca02d15bc3b 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java @@ -461,6 +461,27 @@ public void deleteEntityTroublesomeKeyWorks() throws Exception { service.deleteEntity(TEST_TABLE_2, result4.getEntity().getPartitionKey(), result4.getEntity().getRowKey()); // Assert + try { + service.getEntity(TEST_TABLE_2, result1.getEntity().getPartitionKey(), result1.getEntity().getRowKey()); + assertFalse("Expect an exception when getting an entity that does not exist", true); + } + catch (ServiceException e) { + assertEquals("expect getHttpStatusCode", 404, e.getHttpStatusCode()); + + } + + QueryEntitiesResult assertResult2 = service.queryEntities( + TEST_TABLE_2, + new QueryEntitiesOptions().setQuery(new Query().setFilter(Filter.eq(Filter.litteral("RowKey"), + Filter.constant("key'with'quotes"))))); + + assertEquals(0, assertResult2.getEntities().size()); + + QueryEntitiesResult assertResult3 = service.queryEntities(TEST_TABLE_2); + for (Entity entity : assertResult3.getEntities()) { + assertFalse("Entity3 should be removed from the table", entity3.getRowKey().equals(entity.getRowKey())); + assertFalse("Entity4 should be removed from the table", entity4.getRowKey().equals(entity.getRowKey())); + } } @Test