Skip to content

Commit c71b220

Browse files
Fixing id encoding issues when using special characters for custome already on ComputeGateway (Azure#22818)
* Fixing id encoding issues when using special characters for customers already on ComputeGateway * Update CHANGELOG.md * Update CHANGELOG.md * Fixing typos
1 parent d30b3ec commit c71b220

File tree

8 files changed

+342
-91
lines changed

8 files changed

+342
-91
lines changed

eng/pipelines/templates/steps/cosmos-integration-public.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ parameters:
33

44
steps:
55
- template: /eng/common/pipelines/templates/steps/cosmos-emulator.yml
6+
parameters:
7+
StartParameters: '/noexplorer /noui /enablepreview /EnableSqlComputeEndpoint /disableratelimiting /enableaadauthentication /partitioncount=50

sdk/cosmosdb/cosmos/CHANGELOG.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
# Release History
22

3-
## 3.16.4 (Unreleased)
4-
5-
### Features Added
6-
7-
### Breaking Changes
3+
## 3.16.4 (2022-08-05)
84

95
### Bugs Fixed
10-
11-
### Other Changes
6+
- Reverts changes of [PR 22548](https://github.com/Azure/azure-sdk-for-js/pull/22548) to avoid possible regression when customers use id with special characters and their account is on ComputeGateway already. - See [PR 22818](https://github.com/Azure/azure-sdk-for-js/pull/22818)
127

138
## 3.16.3 (2022-07-13)
149

sdk/cosmosdb/cosmos/src/client/Item/Item.ts

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,7 @@ export class Item {
2929
* Returns a reference URL to the resource. Used for linking in Permissions.
3030
*/
3131
public get url(): string {
32-
return createDocumentUri(
33-
this.container.database.id,
34-
this.container.id,
35-
encodeURIComponent(this.id)
36-
);
32+
return createDocumentUri(this.container.database.id, this.container.id, this.id);
3733
}
3834

3935
/**
@@ -84,9 +80,8 @@ export class Item {
8480
this.partitionKey = undefinedPartitionKey(partitionKeyDefinition);
8581
}
8682

87-
const resourceUri: string = this.url;
88-
const path = getPathFromLink(resourceUri);
89-
const id = getIdFromLink(resourceUri);
83+
const path = getPathFromLink(this.url);
84+
const id = getIdFromLink(this.url);
9085
let response: Response<T & Resource>;
9186
try {
9287
response = await this.clientContext.read<T>({
@@ -154,9 +149,8 @@ export class Item {
154149
throw err;
155150
}
156151

157-
const resourceUri: string = this.url;
158-
const path = getPathFromLink(resourceUri);
159-
const id = getIdFromLink(resourceUri);
152+
const path = getPathFromLink(this.url);
153+
const id = getIdFromLink(this.url);
160154

161155
const response = await this.clientContext.replace<T>({
162156
body,
@@ -192,9 +186,8 @@ export class Item {
192186
this.partitionKey = undefinedPartitionKey(partitionKeyDefinition);
193187
}
194188

195-
const resourceUri: string = this.url;
196-
const path = getPathFromLink(resourceUri);
197-
const id = getIdFromLink(resourceUri);
189+
const path = getPathFromLink(this.url);
190+
const id = getIdFromLink(this.url);
198191

199192
const response = await this.clientContext.delete<T>({
200193
path,
@@ -230,9 +223,8 @@ export class Item {
230223
this.partitionKey = extractPartitionKey(body, partitionKeyDefinition);
231224
}
232225

233-
const resourceUri: string = this.url;
234-
const path = getPathFromLink(resourceUri);
235-
const id = getIdFromLink(resourceUri);
226+
const path = getPathFromLink(this.url);
227+
const id = getIdFromLink(this.url);
236228

237229
const response = await this.clientContext.patch<T>({
238230
body,

sdk/cosmosdb/cosmos/src/common/helper.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { OperationType, ResourceType } from "./constants";
66
const trimLeftSlashes = new RegExp("^[/]+");
77
const trimRightSlashes = new RegExp("[/]+$");
88
const illegalResourceIdCharacters = new RegExp("[/\\\\?#]");
9+
const illegalItemResourceIdCharacters = new RegExp("[/\\\\#]");
910

1011
/** @hidden */
1112
export function jsonStringifyAndEscapeNonASCII(arg: unknown): string {
@@ -223,7 +224,7 @@ export function isItemResourceValid(resource: { id?: string }, err: { message?:
223224
return false;
224225
}
225226

226-
if (resource.id.indexOf("/") !== -1 || resource.id.indexOf("\\") !== -1) {
227+
if (resource.id.indexOf("/") !== -1 || resource.id.indexOf("\\") !== -1 || resource.id.indexOf("#") !== -1) {
227228
err.message = "Id contains illegal chars.";
228229
return false;
229230
}
@@ -272,12 +273,29 @@ export function trimSlashFromLeftAndRight(inputString: string): string {
272273
export function validateResourceId(resourceId: string): boolean {
273274
// if resourceId is not a string or is empty throw an error
274275
if (typeof resourceId !== "string" || isStringNullOrEmpty(resourceId)) {
275-
throw new Error("Resource Id must be a string and cannot be undefined, null or empty");
276+
throw new Error("Resource ID must be a string and cannot be undefined, null or empty");
276277
}
277278

278279
// if resource id contains illegal characters throw an error
279280
if (illegalResourceIdCharacters.test(resourceId)) {
280-
throw new Error("Illegal characters ['/', '\\'] cannot be used in resourceId");
281+
throw new Error("Illegal characters ['/', '\\', '#', '?'] cannot be used in Resource ID");
282+
}
283+
284+
return true;
285+
}
286+
287+
/**
288+
* @hidden
289+
*/
290+
export function validateItemResourceId(resourceId: string): boolean {
291+
// if resourceId is not a string or is empty throw an error
292+
if (typeof resourceId !== "string" || isStringNullOrEmpty(resourceId)) {
293+
throw new Error("Resource ID must be a string and cannot be undefined, null or empty");
294+
}
295+
296+
// if resource id contains illegal characters throw an error
297+
if (illegalItemResourceIdCharacters.test(resourceId)) {
298+
throw new Error("Illegal characters ['/', '\\', '#'] cannot be used in Resource ID");
281299
}
282300

283301
return true;

sdk/cosmosdb/cosmos/src/common/uriFactory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33
import { Constants } from "./constants";
4-
import { trimSlashFromLeftAndRight, validateResourceId } from "./helper";
4+
import { trimSlashFromLeftAndRight, validateResourceId, validateItemResourceId } from "./helper";
55

66
/**
77
* Would be used when creating or deleting a DocumentCollection
@@ -74,7 +74,7 @@ export function createDocumentUri(
7474
documentId: string
7575
): string {
7676
documentId = trimSlashFromLeftAndRight(documentId);
77-
validateResourceId(documentId);
77+
validateItemResourceId(documentId);
7878

7979
return (
8080
createDocumentCollectionUri(databaseId, collectionId) +

sdk/cosmosdb/cosmos/src/utils/headers.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,6 @@ export async function generateHeaders(
2727
};
2828
}
2929

30-
function getEffectiveResourceIdForSignature(resourceId: string) {
31-
const lastSlashPosition = resourceId.lastIndexOf("/");
32-
if (lastSlashPosition <= 0) {
33-
return resourceId;
34-
}
35-
36-
const prefix: string = resourceId.substring(0, lastSlashPosition);
37-
if (!prefix.endsWith("/docs")) {
38-
return resourceId;
39-
}
40-
41-
return prefix + "/" + decodeURIComponent(resourceId.substring(lastSlashPosition + 1));
42-
}
43-
4430
async function signature(
4531
masterKey: string,
4632
method: HTTPMethod,
@@ -55,7 +41,7 @@ async function signature(
5541
"\n" +
5642
resourceType.toLowerCase() +
5743
"\n" +
58-
getEffectiveResourceIdForSignature(resourceId) +
44+
resourceId +
5945
"\n" +
6046
date.toUTCString().toLowerCase() +
6147
"\n" +

sdk/cosmosdb/cosmos/test/public/common/TestHelpers.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,21 @@ import { masterKey } from "../common/_fakeTestSecrets";
1818
import { DatabaseRequest } from "../../../src";
1919
import { ContainerRequest } from "../../../src";
2020

21-
const defaultClient = new CosmosClient({
21+
const defaultRoutingGatewayPort: string = ":8081";
22+
const defaultComputeGatewayPort: string = ":8903";
23+
24+
export const defaultClient = new CosmosClient({
2225
endpoint,
2326
key: masterKey,
2427
connectionPolicy: { enableBackgroundEndpointRefreshing: false },
2528
});
2629

30+
export const defaultComputeGatewayClient = new CosmosClient({
31+
endpoint: endpoint.replace(defaultRoutingGatewayPort, defaultComputeGatewayPort),
32+
key: masterKey,
33+
connectionPolicy: { enableBackgroundEndpointRefreshing: false },
34+
});
35+
2736
export function addEntropy(name: string): string {
2837
return name + getEntropy();
2938
}

0 commit comments

Comments
 (0)