Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

HotFix Issue #58 Add URL Encoding for Keys in Table Batch Operations #59

Merged
merged 1 commit into from

2 participants

@joeg

Signed-off-by: Joe Giardino joegiard@microsoft.com

Joe Giardino Issue #Add URL Encoding for Keys in Table Batch Operations
Signed-off-by: Joe Giardino <joegiard@microsoft.com>
74aaf66
@jcookems

Signed off by: Jason Cooke jcooke@microsoft.com

@jcookems jcookems merged commit c4d5b88 into Azure:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 30, 2012
  1. Issue #Add URL Encoding for Keys in Table Batch Operations

    Joe Giardino authored
    Signed-off-by: Joe Giardino <joegiard@microsoft.com>
This page is out of date. Refresh to see the latest.
View
2  ...i/src/main/java/com/microsoft/windowsazure/services/table/client/QueryTableOperation.java
@@ -183,7 +183,7 @@ public TableResult execute(final CloudTableClient client, final QueryTableOperat
final OperationContext opContext) throws Exception {
final HttpURLConnection request = TableRequest.query(client.getEndpoint(), tableName,
- generateRequestIdentity(isTableEntry, operation.getPartitionKey()),
+ generateRequestIdentity(isTableEntry, operation.getPartitionKey(), false),
options.getTimeoutIntervalInMs(), null/* Query Builder */, null/* Continuation Token */,
options, opContext);
View
25 ...re-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableOperation.java
@@ -257,7 +257,7 @@ public TableResult execute(final CloudTableClient client, final TableOperation o
final OperationContext opContext) throws Exception {
final HttpURLConnection request = TableRequest.delete(client.getEndpoint(), tableName,
- generateRequestIdentity(isTableEntry, tableIdentity), operation.getEntity().getEtag(),
+ generateRequestIdentity(isTableEntry, tableIdentity, false), operation.getEntity().getEtag(),
options.getTimeoutIntervalInMs(), null, options, opContext);
client.getCredentials().signRequestLite(request, -1L, opContext);
@@ -324,7 +324,7 @@ private TableResult performInsert(final CloudTableClient client, final String ta
public TableResult execute(final CloudTableClient client, final TableOperation operation,
final OperationContext opContext) throws Exception {
final HttpURLConnection request = TableRequest.insert(client.getEndpoint(), tableName,
- generateRequestIdentity(isTableEntry, tableIdentity),
+ generateRequestIdentity(isTableEntry, tableIdentity, false),
operation.opType != TableOperationType.INSERT ? operation.getEntity().getEtag() : null,
operation.opType.getUpdateType(), options.getTimeoutIntervalInMs(), null, options, opContext);
@@ -411,7 +411,7 @@ public TableResult execute(final CloudTableClient client, final TableOperation o
final OperationContext opContext) throws Exception {
final HttpURLConnection request = TableRequest.merge(client.getEndpoint(), tableName,
- generateRequestIdentity(false, null), operation.getEntity().getEtag(),
+ generateRequestIdentity(false, null, false), operation.getEntity().getEtag(),
options.getTimeoutIntervalInMs(), null, options, opContext);
client.getCredentials().signRequestLite(request, -1L, opContext);
@@ -477,7 +477,7 @@ public TableResult execute(final CloudTableClient client, final TableOperation o
final OperationContext opContext) throws Exception {
final HttpURLConnection request = TableRequest.update(client.getEndpoint(), tableName,
- generateRequestIdentity(false, null), operation.getEntity().getEtag(),
+ generateRequestIdentity(false, null, false), operation.getEntity().getEtag(),
options.getTimeoutIntervalInMs(), null, options, opContext);
client.getCredentials().signRequestLite(request, -1L, opContext);
@@ -577,10 +577,15 @@ else if (this.getOperationType() == TableOperationType.RETRIEVE) {
* @param entryName
* The entry name to use as the request identity if the <code>isSingleIndexEntry</code> parameter is
* <code>true</code>.
+ * @param encodeKeys
+ * Pass <code>true</code> to url encode the partition & row keys
* @return
* A <code>String</code> containing the formatted request identity string.
+ * @throws StorageException
+ * If a storage service error occurred.
*/
- protected String generateRequestIdentity(boolean isSingleIndexEntry, final String entryName) {
+ protected String generateRequestIdentity(boolean isSingleIndexEntry, final String entryName, boolean encodeKeys)
+ throws StorageException {
if (isSingleIndexEntry) {
return String.format("'%s'", entryName);
}
@@ -602,22 +607,24 @@ protected String generateRequestIdentity(boolean isSingleIndexEntry, final Strin
rk = this.getEntity().getRowKey();
}
- return String.format("%s='%s',%s='%s'", TableConstants.PARTITION_KEY, pk, TableConstants.ROW_KEY, rk);
+ return String.format("%s='%s',%s='%s'", TableConstants.PARTITION_KEY, encodeKeys ? Utility.safeEncode(pk)
+ : pk, TableConstants.ROW_KEY, encodeKeys ? Utility.safeEncode(rk) : rk);
}
}
/**
* Reserved for internal use. Generates the request identity string for the specified table. The request identity
* string combines the table name with the PartitionKey and RowKey from the operation to identify specific table
- * entities.
+ * entities. This request identity is already UrlEncoded.
*
* @param tableName
* A <code>String</code> containing the name of the table.
* @return
* A <code>String</code> containing the formatted request identity string for the specified table.
+ * @throws StorageException
*/
- protected String generateRequestIdentityWithTable(final String tableName) {
- return String.format("/%s(%s)", tableName, generateRequestIdentity(false, null));
+ protected String generateRequestIdentityWithTable(final String tableName) throws StorageException {
+ return String.format("/%s(%s)", tableName, generateRequestIdentity(false, null, true));
}
/**
View
52 ...pi/src/test/java/com/microsoft/windowsazure/services/table/client/TableEscapingTests.java
@@ -28,12 +28,12 @@
public class TableEscapingTests extends TableTestBase {
@Test
public void emptyString() throws StorageException {
- doEscapeTest("", false);
+ doEscapeTest("", false, true);
}
@Test
public void emptyStringBatch() throws StorageException {
- doEscapeTest("", true);
+ doEscapeTest("", true, true);
}
@Test
@@ -47,6 +47,18 @@ public void randomCharsBatch() throws StorageException {
}
@Test
+ @Ignore
+ public void percent25() throws StorageException {
+ // Disabled Until Double Percent decoding issue is fixed for single entity operations
+ // doEscapeTest("foo%25", false, true);
+ }
+
+ @Test
+ public void percent25Batch() throws StorageException {
+ doEscapeTest("foo%25", true, true);
+ }
+
+ @Test
public void regularPKInQuery() throws StorageException {
doQueryEscapeTest("data");
}
@@ -63,18 +75,18 @@ public void specialCharsBatch() throws StorageException {
@Test
public void unicode() throws StorageException {
- doEscapeTest("\u00A9\u770b\u5168\u90e8", false);
- doEscapeTest("char中文test", false);
- doEscapeTest("char中文test", false);
- doEscapeTest("世界你好", false);
+ doEscapeTest("\u00A9\u770b\u5168\u90e8", false, true);
+ doEscapeTest("char中文test", false, true);
+ doEscapeTest("char中文test", false, true);
+ doEscapeTest("世界你好", false, true);
}
@Test
public void unicodeBatch() throws StorageException {
- doEscapeTest("\u00A9\u770b\u5168\u90e8", true);
- doEscapeTest("char中文test", true);
- doEscapeTest("char中文test", true);
- doEscapeTest("世界你好", true);
+ doEscapeTest("\u00A9\u770b\u5168\u90e8", true, true);
+ doEscapeTest("char中文test", true, true);
+ doEscapeTest("char中文test", true, true);
+ doEscapeTest("世界你好", true, true);
}
@Test
@@ -87,12 +99,12 @@ public void unicodeInQuery() throws StorageException {
@Test
public void whiteSpaceOnly() throws StorageException {
- doEscapeTest(" ", false);
+ doEscapeTest(" ", false, true);
}
@Test
public void whiteSpaceOnlyBatch() throws StorageException {
- doEscapeTest(" ", true);
+ doEscapeTest(" ", true, true);
}
@Test
@@ -119,10 +131,14 @@ public void xmlTestBatch() throws StorageException {
}
private void doEscapeTest(String data, boolean useBatch) throws StorageException {
+ doEscapeTest(data, useBatch, false);
+ }
+
+ private void doEscapeTest(String data, boolean useBatch, boolean includeInKey) throws StorageException {
class1 ref = new class1();
ref.setA(data);
- ref.setPartitionKey("temp");
+ ref.setPartitionKey(includeInKey ? "temp" + data : "temp");
ref.setRowKey(UUID.randomUUID().toString());
if (useBatch) {
TableBatchOperation batch = new TableBatchOperation();
@@ -147,6 +163,7 @@ private void doEscapeTest(String data, boolean useBatch) throws StorageException
class1 retObj = res.getResultAsType();
Assert.assertEquals(ref.getA(), retObj.getA());
+ Assert.assertEquals(ref.getPartitionKey(), retObj.getPartitionKey());
ref.setEtag(retObj.getEtag());
ref.setB(data);
@@ -202,6 +219,15 @@ private void doEscapeTest(String data, boolean useBatch) throws StorageException
Assert.assertEquals(ref.getA(), retObj.getA());
Assert.assertEquals(ref.getB(), retObj.getB());
Assert.assertEquals(ref.getC(), retObj.getC());
+
+ if (useBatch) {
+ TableBatchOperation batch = new TableBatchOperation();
+ batch.delete(retObj);
+ res = tClient.execute(testSuiteTableName, batch).get(0);
+ }
+ else {
+ res = tClient.execute(testSuiteTableName, TableOperation.delete(retObj));
+ }
}
private void doQueryEscapeTest(String data) throws StorageException {
Something went wrong with that request. Please try again.