Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter by tags tablequeryway and iftags conditions #2372

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
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
105 changes: 82 additions & 23 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,22 @@
"request": "launch",
"name": "Azurite Service - Loki",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"args": ["${workspaceFolder}/src/azurite.ts", "-d", "debug.log"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/src/azurite.ts",
"-d",
"debug.log"
],
"env": {
"AZURITE_ACCOUNTS": ""
},
"skipFiles": ["node_modules/*/**", "<node_internals>/*/**"],
"skipFiles": [
"node_modules/*/**",
"<node_internals>/*/**"
],
"outputCapture": "std"
},
{
Expand All @@ -35,8 +45,16 @@
"request": "launch",
"name": "Azurite Service - Loki, Loose",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"args": ["${workspaceFolder}/src/azurite.ts", "-d", "debug.log", "-L"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/src/azurite.ts",
"-d",
"debug.log",
"-L"
],
"env": {
"AZURITE_ACCOUNTS": ""
},
Expand All @@ -47,7 +65,10 @@
"request": "launch",
"name": "Azurite Service - Loki, Loose, HTTPS, OAuth",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/src/azurite.ts",
"-L",
Expand All @@ -70,7 +91,10 @@
"request": "launch",
"name": "Azurite Queue Service - Loki, HTTPS, OAuth",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/src/queue/main.ts",
"-d",
Expand All @@ -92,7 +116,10 @@
"request": "launch",
"name": "Azurite Blob Service - Loki, HTTPS, OAuth",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/src/blob/main.ts",
"-d",
Expand All @@ -114,8 +141,15 @@
"request": "launch",
"name": "Azurite Blob Service - SQL",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"args": ["${workspaceFolder}/src/blob/main.ts", "-d", "debug.log"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/src/blob/main.ts",
"-d",
"debug.log"
],
"env": {
"AZURITE_DB": "mysql://root:my-secret-pw@127.0.0.1:3306/azurite_blob",
"AZURITE_ACCOUNTS": ""
Expand All @@ -127,8 +161,15 @@
"request": "launch",
"name": "Azurite Table Service - Loki",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"args": ["${workspaceFolder}/src/table/main.ts", "-d", "debug.log"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/src/table/main.ts",
"-d",
"debug.log"
],
"env": {
"AZURITE_ACCOUNTS": ""
},
Expand All @@ -139,16 +180,24 @@
"request": "launch",
"name": "Current TS File",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"args": ["${workspaceFolder}/${relativeFile}"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/${relativeFile}"
],
"outputCapture": "std"
},
{
"type": "node",
"request": "launch",
"name": "Current Mocha TS File - Loki",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/node_modules/mocha/bin/_mocha",
"-u",
Expand All @@ -162,7 +211,7 @@
"AZURITE_ACCOUNTS": "",
"AZURE_TABLE_STORAGE": "",
"DATATABLES_ACCOUNT_NAME": "<name of your storage account>",
"DATATABLES_ACCOUNT_KEY" : "<account key for your storage account>",
"DATATABLES_ACCOUNT_KEY": "<account key for your storage account>",
"AZURE_DATATABLES_STORAGE_STRING": "https://<your account name>.table.core.windows.net",
"AZURE_DATATABLES_SAS": "?<sas query string>",
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
Expand All @@ -175,15 +224,18 @@
"request": "launch",
"name": "EXE Mocha TS File - Loki",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/node_modules/mocha/bin/_mocha",
"-u",
"tdd",
"--timeout",
"999999",
"--colors",
"${workspaceFolder}/tests/exe.test.ts",
"${workspaceFolder}/tests/exe.test.ts",
"--exit"
],
"env": {
Expand All @@ -199,7 +251,10 @@
"request": "launch",
"name": "Current Mocha TS File - SQL",
"cwd": "${workspaceFolder}",
"runtimeArgs": ["-r", "ts-node/register"],
"runtimeArgs": [
"-r",
"ts-node/register"
],
"args": [
"${workspaceFolder}/node_modules/mocha/bin/_mocha",
"-u",
Expand All @@ -211,7 +266,7 @@
],
"env": {
"AZURITE_ACCOUNTS": "",
"AZURITE_TEST_DB": "mysql://root:my-secret-pw@127.0.0.1:3306/azurite_blob_test",
"AZURITE_TEST_DB": "mysql://root:!!123abc@127.0.0.1:3306/azurite_blob",
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
},
"internalConsoleOptions": "openOnSessionStart",
Expand Down Expand Up @@ -250,9 +305,13 @@
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "npm: watch"
}
]
}
}
3 changes: 3 additions & 0 deletions src/blob/conditions/ConditionResourceAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { BlobModel, ContainerModel } from "../persistence/IBlobMetadataStore";
import IConditionResource from "./IConditionResource";
import { BlobTags } from "../generated/artifacts/models";

export default class ConditionResourceAdapter implements IConditionResource {
public exist: boolean;
public etag: string;
public lastModified: Date;
public tags?: BlobTags;

public constructor(resource: BlobModel | ContainerModel | undefined | null) {
if (
Expand All @@ -20,6 +22,7 @@ export default class ConditionResourceAdapter implements IConditionResource {

this.exist = true;
this.etag = resource.properties.etag;
this.tags = (resource as BlobModel)?.blobTags;

if (this.etag.length < 3) {
throw new Error(
Expand Down
3 changes: 3 additions & 0 deletions src/blob/conditions/ConditionalHeadersAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default class ConditionalHeadersAdapter implements IConditionalHeaders {
public ifUnmodifiedSince?: Date;
public ifMatch?: string[];
public ifNoneMatch?: string[];
public ifTags?: string;

public constructor(
context: Context,
Expand Down Expand Up @@ -43,5 +44,7 @@ export default class ConditionalHeadersAdapter implements IConditionalHeaders {
if (this.ifUnmodifiedSince) {
this.ifUnmodifiedSince.setMilliseconds(0); // Precision to seconds
}

this.ifTags = modifiedAccessConditions.ifTags;
}
}
7 changes: 7 additions & 0 deletions src/blob/conditions/IConditionResource.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { BlobTags } from "../generated/artifacts/models";

export default interface IConditionResource {
/**
* Whether resource exists or not.
Expand All @@ -13,4 +15,9 @@ export default interface IConditionResource {
* last modified time for container or blob.
*/
lastModified: Date;

/**
* optional resource blog tags.
*/
tags?: BlobTags;
}
1 change: 1 addition & 0 deletions src/blob/conditions/IConditionalHeaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export interface IConditionalHeaders {
* If-None-Match etag list without quotes.
*/
ifNoneMatch?: string[];
ifTags?: string;
}
38 changes: 38 additions & 0 deletions src/blob/conditions/IfTagsHeaderValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Context from "../generated/Context";
import { IConditionalHeaders } from "./IConditionalHeaders";
import IConditionResource from "./IConditionResource";
import StorageErrorFactory from "../errors/StorageErrorFactory";
import { generateQueryBlobWithTagsWhereFunction } from "../persistence/QueryInterpreter/QueryInterpreter";

export function validateIfTagsHeader(
context: Context,
conditionalHeaders: IConditionalHeaders,
resource: IConditionResource
): void {
const evaluateBlobWithTagsFunction = generateQueryOrThrowInvalidHeader(
context,
conditionalHeaders
);
if (resource.exist) {
const tagsMeetConditions = evaluateBlobWithTagsFunction(resource);
if (!resource?.tags || tagsMeetConditions.length === 0) {
throw StorageErrorFactory.getConditionNotMet(context.contextId!);
}
}
// if it doesn't exist, BlobNotFound is thrown on caller (IBlobMetadataStore)
return;
}

function generateQueryOrThrowInvalidHeader(
context: Context,
conditionalHeaders: IConditionalHeaders
) {
try {
return generateQueryBlobWithTagsWhereFunction(conditionalHeaders.ifTags);
} catch (error) {
throw StorageErrorFactory.getInvalidHeaderValue(context.contextId!, {
HeaderName: "x-ms-if-tags",
HeaderValue: conditionalHeaders.ifTags!
});
}
}
7 changes: 6 additions & 1 deletion src/blob/conditions/ReadConditionalHeadersValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ConditionResourceAdapter from "./ConditionResourceAdapter";
import { IConditionalHeaders } from "./IConditionalHeaders";
import { IConditionalHeadersValidator } from "./IConditionalHeadersValidator";
import IConditionResource from "./IConditionResource";
import { validateIfTagsHeader } from "./IfTagsHeaderValidator";

export function validateReadConditions(
context: Context,
Expand All @@ -22,7 +23,8 @@ export function validateReadConditions(

// tslint:disable: max-line-length
export default class ReadConditionalHeadersValidator
implements IConditionalHeadersValidator {
implements IConditionalHeadersValidator
{
/**
* Validate Conditional Headers for Blob Service Read Operations in Version 2013-08-15 or Later.
* @link https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations#specifying-conditional-headers-for-blob-service-read-operations-in-version-2013-08-15-or-later
Expand All @@ -36,6 +38,9 @@ export default class ReadConditionalHeadersValidator
conditionalHeaders: IConditionalHeaders,
resource: IConditionResource
): void {
if (conditionalHeaders?.ifTags) {
validateIfTagsHeader(context, conditionalHeaders, resource);
}
// If-Match && If-Unmodified-Since && (If-None-Match || If-Modified-Since)

// Read against a non exist resource
Expand Down
7 changes: 6 additions & 1 deletion src/blob/conditions/WriteConditionalHeadersValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ConditionResourceAdapter from "./ConditionResourceAdapter";
import { IConditionalHeaders } from "./IConditionalHeaders";
import { IConditionalHeadersValidator } from "./IConditionalHeadersValidator";
import IConditionResource from "./IConditionResource";
import { validateIfTagsHeader } from "./IfTagsHeaderValidator";

export function validateSequenceNumberWriteConditions(
context: Context,
Expand Down Expand Up @@ -71,7 +72,8 @@ export function validateWriteConditions(

// tslint:disable: max-line-length
export default class WriteConditionalHeadersValidator
implements IConditionalHeadersValidator {
implements IConditionalHeadersValidator
{
/**
* Validate conditional Headers for Read Operations in Versions Prior to 2013-08-15,
* and for Write Operations (All Versions).
Expand All @@ -87,6 +89,9 @@ export default class WriteConditionalHeadersValidator
resource: IConditionResource
): void {
this.validateCombinations(context, conditionalHeaders);
if (conditionalHeaders?.ifTags) {
validateIfTagsHeader(context, conditionalHeaders, resource);
}
if (!resource.exist) {
if (
conditionalHeaders.ifNoneMatch &&
Expand Down
Loading