Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

## Upcoming Release

Blob:

- Changed charaters validation against tag key in filtering blobs with tags to align with service side behavior. (issue #2561)

## 2025.07 Version 3.35.0

General:
Expand Down
35 changes: 13 additions & 22 deletions src/blob/persistence/QueryInterpreter/QueryParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,16 +314,23 @@ class QueryParser {
this.query.throw('expecting tag value');
}

private ContainsInvalidTagKeyCharacter(key: string): boolean {
private validateTagCharacter(key: string) {
for (let c of key) {
if (!(c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9' ||
c == '_')) {
return true;
c == ' ' ||
c == '+' ||
c == '-' ||
c == '.' ||
c == '/' ||
c == ':' ||
c == '=' ||
c == '_'
)) {
this.query.throw(`'${c}' not permitted in tag name or value`);
}
}
return false;
}

private validateKey(key: string) {
Expand All @@ -342,30 +349,14 @@ class QueryParser {
if (!this.conditionHeader && ((key.length == 0) || (key.length > 128))) {
this.query.throw('tag must be between 1 and 128 characters in length');
}
if (this.ContainsInvalidTagKeyCharacter(key)) {
this.query.throw(`unexpected '${key}'`);
}
this.validateTagCharacter(key);
}

private validateValue(value: string) {
if (!this.conditionHeader && (value.length > 256)) {
this.query.throw(`tag value must be between 0 and 256 characters in length`);
}
for (let c of value) {
if (!(c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9' ||
c == ' ' ||
c == '+' ||
c == '-' ||
c == '.' ||
c == '/' ||
c == ':' ||
c == '=' ||
c == '_')) {
this.query.throw(`'${c}' not permitted in tag name or value`);
}
}
this.validateTagCharacter(value);
}

/**
Expand Down
13 changes: 13 additions & 0 deletions tests/blob/apis/blob.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2434,6 +2434,19 @@ describe("BlobAPIs", () => {
assert.deepStrictEqual(outputTags1, tags);
});

it("get blob tag with ifTags condition - key with special chars @loki @sql", async () => {
let tags: Tags = {
" key 1 +-.:=_/": '1a',
key2: 'a1'
};
await blobClient.setTags(tags);

let queryString = `" key 1 +-.:=_/"='1a'`;
let outputTags = (await blobClient.getTags({ conditions: { tagConditions: queryString } })).tags;
assert.deepStrictEqual(outputTags, tags);
});


it("get blob tag with long ifTags condition @loki @sql", async () => {
const tags = {
tag1: "val1",
Expand Down
Loading