From be4cb8f51639be2a36a3f47e014ff4508cc85f69 Mon Sep 17 00:00:00 2001 From: George Arama <50641385+gearama@users.noreply.github.com> Date: Fri, 14 Oct 2022 09:20:05 -0700 Subject: [PATCH 01/21] Update VCPKG Baseline due to zlib (#4027) * override zlib version * shwitch baseline * macro update * override zlib --- vcpkg.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vcpkg.json b/vcpkg.json index 1e586685dd..23cf27ffff 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -22,5 +22,11 @@ "name": "wil", "platform": "windows" } + ], + "overrides": [ + { + "name": "zlib", + "version": "1.2.12#2" + } ] } From 01254a62cd87114d948b3a243acb3ca66c981d50 Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Mon, 17 Oct 2022 16:25:31 -0700 Subject: [PATCH 02/21] Fixed CURL build breaks discovered by newer openssl baselines (#4034) --- sdk/core/azure-core/src/http/curl/curl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/core/azure-core/src/http/curl/curl.cpp b/sdk/core/azure-core/src/http/curl/curl.cpp index 3263b8cc5e..c534b10bed 100644 --- a/sdk/core/azure-core/src/http/curl/curl.cpp +++ b/sdk/core/azure-core/src/http/curl/curl.cpp @@ -37,12 +37,14 @@ #include "curl_session_private.hpp" #if defined(AZ_PLATFORM_POSIX) +#include #include #include #include #include #include #include +#include #include // for poll() #include // for socket shutdown #elif defined(AZ_PLATFORM_WINDOWS) From 5f64eea985c05d5063a3ba93c60d014602021d4d Mon Sep 17 00:00:00 2001 From: George Arama <50641385+gearama@users.noreply.github.com> Date: Tue, 18 Oct 2022 15:37:05 -0700 Subject: [PATCH 03/21] Vcpkg baseline to latest (#4036) * vcpkg baseline * f4b262b259145adb2ab0116a390b08642489d32b * 79fa9d85cb4510b05c2657bd7ec8a6a2cb266dc5 * 6ca56aeb457f033d344a7106cb3f9f1abf8f4e98 * override * 1.4.1` --- cmake-modules/AzureVcpkg.cmake | 2 +- vcpkg.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake-modules/AzureVcpkg.cmake b/cmake-modules/AzureVcpkg.cmake index 2789241fb5..272013686f 100644 --- a/cmake-modules/AzureVcpkg.cmake +++ b/cmake-modules/AzureVcpkg.cmake @@ -22,7 +22,7 @@ macro(az_vcpkg_integrate) if(NOT DEFINED ENV{AZURE_SDK_DISABLE_AUTO_VCPKG}) # GET VCPKG FROM SOURCE # User can set env var AZURE_SDK_VCPKG_COMMIT to pick the VCPKG commit to fetch - set(VCPKG_COMMIT_STRING f0aa678b7471497f1adedcc99f40e1599ad22f69) # default SDK tested commit + set(VCPKG_COMMIT_STRING 6ca56aeb457f033d344a7106cb3f9f1abf8f4e98) # default SDK tested commit if(DEFINED ENV{AZURE_SDK_VCPKG_COMMIT}) set(VCPKG_COMMIT_STRING "$ENV{AZURE_SDK_VCPKG_COMMIT}") # default SDK tested commit endif() diff --git a/vcpkg.json b/vcpkg.json index 23cf27ffff..a76a3ffd38 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,7 +1,7 @@ { "name": "azure-sdk-for-cpp", "version": "1.5.0", - "builtin-baseline": "f0aa678b7471497f1adedcc99f40e1599ad22f69", + "builtin-baseline": "6ca56aeb457f033d344a7106cb3f9f1abf8f4e98", "dependencies": [ { "name": "curl" @@ -25,8 +25,8 @@ ], "overrides": [ { - "name": "zlib", - "version": "1.2.12#2" + "name": "opentelemetry-cpp", + "version": "1.4.1" } ] } From 378ee6cbd4c7d985840e7dc4baa5e5055ae7520b Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Wed, 19 Oct 2022 16:34:24 -0700 Subject: [PATCH 04/21] Removed version override for opentelemetry (#4037) * Removed version override for opentelemetry * Disable deprecation warnings for open telemety tests to guard against future deprecations * Added explanation for 4996 error; removed InMemoryExporter from documentation --- doc/DistributedTracing.md | 6 +----- sdk/core/azure-core-tracing-opentelemetry/README.md | 3 +-- .../test/ut/CMakeLists.txt | 10 ++++++++++ .../test/ut/service_support_test.cpp | 12 ++++++------ vcpkg.json | 4 ---- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/doc/DistributedTracing.md b/doc/DistributedTracing.md index 863f4adac6..2c373d31a9 100644 --- a/doc/DistributedTracing.md +++ b/doc/DistributedTracing.md @@ -52,11 +52,7 @@ in-memory logger. opentelemetry::nostd::shared_ptr CreateOpenTelemetryProvider() { -#if USE_MEMORY_EXPORTER - auto exporter = std::make_unique(); -#else - auto exporter = std::make_unique(); -#endif + auto exporter = std::make_unique(); // simple processor auto simple_processor = std::unique_ptr( diff --git a/sdk/core/azure-core-tracing-opentelemetry/README.md b/sdk/core/azure-core-tracing-opentelemetry/README.md index a88a40b9a5..f0d91521a4 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/README.md +++ b/sdk/core/azure-core-tracing-opentelemetry/README.md @@ -61,8 +61,7 @@ After this, the SDK API implementations will be able to retrieve the tracer prov ```cpp // Start by creating an OpenTelemetry Provider. -auto exporter = std::make_unique(); -m_spanData = exporter->GetData(); +auto exporter = std::make_unique(); // simple processor auto simple_processor = std::unique_ptr( diff --git a/sdk/core/azure-core-tracing-opentelemetry/test/ut/CMakeLists.txt b/sdk/core/azure-core-tracing-opentelemetry/test/ut/CMakeLists.txt index 8411492c39..a73d7272dd 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/test/ut/CMakeLists.txt +++ b/sdk/core/azure-core-tracing-opentelemetry/test/ut/CMakeLists.txt @@ -9,6 +9,16 @@ add_compile_definitions(AZURE_TEST_DATA_PATH="${CMAKE_BINARY_DIR}") add_compile_definitions(AZURE_TEST_RECORDING_DIR="${CMAKE_CURRENT_LIST_DIR}") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang") + add_compile_options(-Wno-error=deprecated-declarations) +endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") +# Disable deprecation warnings. + add_compile_options(/wd4996) +endif() + + project (azure-core-tracing-opentelemetry-test LANGUAGES CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) diff --git a/sdk/core/azure-core-tracing-opentelemetry/test/ut/service_support_test.cpp b/sdk/core/azure-core-tracing-opentelemetry/test/ut/service_support_test.cpp index 66d14624d7..b183fcf3fa 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/test/ut/service_support_test.cpp +++ b/sdk/core/azure-core-tracing-opentelemetry/test/ut/service_support_test.cpp @@ -262,10 +262,10 @@ class OpenTelemetryServiceTests : public Azure::Core::Test::TestBase { { EXPECT_EQ( expectedSpanContents["library"]["name"].get(), - span->GetInstrumentationLibrary().GetName()); + span->GetInstrumentationScope().GetName()); EXPECT_EQ( expectedSpanContents["library"]["version"].get(), - span->GetInstrumentationLibrary().GetVersion()); + span->GetInstrumentationScope().GetVersion()); } return true; } @@ -502,10 +502,10 @@ TEST_F(OpenTelemetryServiceTests, NestSpans) "my-service", opentelemetry::nostd::get(attributes.at("az.namespace"))); } - EXPECT_EQ("my-service", spans[0]->GetInstrumentationLibrary().GetName()); - EXPECT_EQ("my-service", spans[1]->GetInstrumentationLibrary().GetName()); - EXPECT_EQ("1.0beta-2", spans[0]->GetInstrumentationLibrary().GetVersion()); - EXPECT_EQ("1.0beta-2", spans[1]->GetInstrumentationLibrary().GetVersion()); + EXPECT_EQ("my-service", spans[0]->GetInstrumentationScope().GetName()); + EXPECT_EQ("my-service", spans[1]->GetInstrumentationScope().GetName()); + EXPECT_EQ("1.0beta-2", spans[0]->GetInstrumentationScope().GetVersion()); + EXPECT_EQ("1.0beta-2", spans[1]->GetInstrumentationScope().GetVersion()); // The trace ID for the inner and outer requests must be the same, the parent-id/span-id must be // different. diff --git a/vcpkg.json b/vcpkg.json index a76a3ffd38..17fa92fee4 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -24,9 +24,5 @@ } ], "overrides": [ - { - "name": "opentelemetry-cpp", - "version": "1.4.1" - } ] } From 90f1ff9364fdbb3b297043e9a0a999a3ba9eeecc Mon Sep 17 00:00:00 2001 From: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> Date: Thu, 20 Oct 2022 16:30:02 -0700 Subject: [PATCH 05/21] Sync eng/common directory with azure-sdk-tools for PR 3790 (#4041) * Added yaml support for job matrix creation * autogen scenario matrix for stress test * Temporary Working State * update to default sparse * pr comments and some error handling * custom matrixfilename and ordering of generatedValues.yaml * common module import * JobMatrix write host Co-authored-by: Albert Cheng --- .../scripts/Helpers/PSModule-Helpers.ps1 | 6 +- .../scripts/job-matrix/Create-JobMatrix.ps1 | 7 +- .../job-matrix/job-matrix-functions.ps1 | 34 ++++- .../stress-testing/deploy-stress-tests.ps1 | 10 +- .../find-all-stress-packages.ps1 | 30 +++- .../generate-scenario-matrix.ps1 | 86 +++++++++++ .../stress-test-deployment-lib.ps1 | 135 ++++++++++++------ 7 files changed, 251 insertions(+), 57 deletions(-) create mode 100644 eng/common/scripts/stress-testing/generate-scenario-matrix.ps1 diff --git a/eng/common/scripts/Helpers/PSModule-Helpers.ps1 b/eng/common/scripts/Helpers/PSModule-Helpers.ps1 index 1a2a0a9008..d9a5afaab1 100644 --- a/eng/common/scripts/Helpers/PSModule-Helpers.ps1 +++ b/eng/common/scripts/Helpers/PSModule-Helpers.ps1 @@ -22,9 +22,9 @@ function Update-PSModulePathForCI() $modulePaths = $modulePaths.Where({ !$_.StartsWith($hostedAgentModulePath) }) # Add any "az_" paths from the agent which is the lastest set of azure modules - $AzModuleCachPath = (Get-ChildItem "$hostedAgentModulePath/az_*" -Attributes Directory) -join $moduleSeperator - if ($AzModuleCachPath -and $env.PSModulePath -notcontains $AzModuleCachPath) { - $modulePaths += $AzModuleCachPath + $AzModuleCachePath = (Get-ChildItem "$hostedAgentModulePath/az_*" -Attributes Directory) -join $moduleSeperator + if ($AzModuleCachePath -and $env:PSModulePath -notcontains $AzModuleCachePath) { + $modulePaths += $AzModuleCachePath } $env:PSModulePath = $modulePaths -join $moduleSeperator diff --git a/eng/common/scripts/job-matrix/Create-JobMatrix.ps1 b/eng/common/scripts/job-matrix/Create-JobMatrix.ps1 index 6eba7e8795..ea4923daa4 100644 --- a/eng/common/scripts/job-matrix/Create-JobMatrix.ps1 +++ b/eng/common/scripts/job-matrix/Create-JobMatrix.ps1 @@ -23,7 +23,7 @@ if (!(Test-Path $ConfigPath)) { Write-Error "ConfigPath '$ConfigPath' does not exist." exit 1 } -$config = GetMatrixConfigFromJson (Get-Content $ConfigPath) +$config = GetMatrixConfigFromFile (Get-Content $ConfigPath -Raw) # Strip empty string filters in order to be able to use azure pipelines yaml join() $Filters = $Filters | Where-Object { $_ } @@ -38,4 +38,7 @@ $Filters = $Filters | Where-Object { $_ } $serialized = SerializePipelineMatrix $matrix Write-Output $serialized.pretty -Write-Output "##vso[task.setVariable variable=matrix;isOutput=true]$($serialized.compressed)" + +if ($null -ne $env:SYSTEM_TEAMPROJECTID) { + Write-Output "##vso[task.setVariable variable=matrix;isOutput=true]$($serialized.compressed)" +} \ No newline at end of file diff --git a/eng/common/scripts/job-matrix/job-matrix-functions.ps1 b/eng/common/scripts/job-matrix/job-matrix-functions.ps1 index 8822d7ce72..0926185910 100644 --- a/eng/common/scripts/job-matrix/job-matrix-functions.ps1 +++ b/eng/common/scripts/job-matrix/job-matrix-functions.ps1 @@ -84,6 +84,7 @@ class MatrixParameter { } } +. (Join-Path $PSScriptRoot "../Helpers" PSModule-Helpers.ps1) $IMPORT_KEYWORD = '$IMPORT' function GenerateMatrix( @@ -146,7 +147,7 @@ function ProcessNonSparseParameters( function FilterMatrixDisplayName([array]$matrix, [string]$filter) { return $matrix | Where-Object { $_ } | ForEach-Object { - if ($_.Name -match $filter) { + if ($_.ContainsKey("Name") -and $_.Name -match $filter) { return $_ } } @@ -168,7 +169,7 @@ function MatchesFilters([hashtable]$entry, [array]$filters) { # Default all regex checks to go against empty string when keys are missing. # This simplifies the filter syntax/interface to be regex only. $value = "" - if ($null -ne $entry -and $entry.parameters.Contains($key)) { + if ($null -ne $entry -and $entry.ContainsKey("parameters") -and $entry.parameters.Contains($key)) { $value = $entry.parameters[$key] } if ($value -notmatch $regex) { @@ -190,11 +191,34 @@ function ParseFilter([string]$filter) { } } -# Importing the JSON as PSCustomObject preserves key ordering, -# whereas ConvertFrom-Json -AsHashtable does not +function GetMatrixConfigFromFile([String] $config) +{ + [MatrixConfig]$config = try{ + GetMatrixConfigFromJson $config + } catch { + GetMatrixConfigFromYaml $config + } + return $config +} + +function GetMatrixConfigFromYaml([String] $yamlConfig) +{ + Install-ModuleIfNotInstalled "powershell-yaml" "0.4.1" | Import-Module + # ConvertTo then from json is to make sure the nested values are in PSCustomObject + [MatrixConfig]$config = ConvertFrom-Yaml $yamlConfig -Ordered | ConvertTo-Json -Depth 100 | ConvertFrom-Json + return GetMatrixConfig $config +} + function GetMatrixConfigFromJson([String]$jsonConfig) { [MatrixConfig]$config = $jsonConfig | ConvertFrom-Json + return GetMatrixConfig $config +} + +# Importing the JSON as PSCustomObject preserves key ordering, +# whereas ConvertFrom-Json -AsHashtable does not +function GetMatrixConfig([MatrixConfig]$config) +{ $config.matrixParameters = @() $config.displayNamesLookup = @{} $include = [MatrixParameter[]]@() @@ -359,7 +383,7 @@ function ProcessImport([MatrixParameter[]]$matrix, [String]$selection, [Array]$n Write-Error "`$IMPORT path '$importPath' does not exist." exit 1 } - $importedMatrixConfig = GetMatrixConfigFromJson (Get-Content $importPath) + $importedMatrixConfig = GetMatrixConfigFromFile (Get-Content -Raw $importPath) $importedMatrix = GenerateMatrix ` -config $importedMatrixConfig ` -selectFromMatrixType $selection ` diff --git a/eng/common/scripts/stress-testing/deploy-stress-tests.ps1 b/eng/common/scripts/stress-testing/deploy-stress-tests.ps1 index 01920bdcbf..c71e629431 100644 --- a/eng/common/scripts/stress-testing/deploy-stress-tests.ps1 +++ b/eng/common/scripts/stress-testing/deploy-stress-tests.ps1 @@ -24,7 +24,15 @@ param( [string]$Namespace, # Override remote stress-test-addons with local on-disk addons for development - [System.IO.FileInfo]$LocalAddonsPath + [System.IO.FileInfo]$LocalAddonsPath, + + # Matrix generation parameters + [Parameter(Mandatory=$False)][string]$MatrixFileName, + [Parameter(Mandatory=$False)][string]$MatrixSelection, + [Parameter(Mandatory=$False)][string]$MatrixDisplayNameFilter, + [Parameter(Mandatory=$False)][array]$MatrixFilters, + [Parameter(Mandatory=$False)][array]$MatrixReplace, + [Parameter(Mandatory=$False)][array]$MatrixNonSparseParameters ) . $PSScriptRoot/stress-test-deployment-lib.ps1 diff --git a/eng/common/scripts/stress-testing/find-all-stress-packages.ps1 b/eng/common/scripts/stress-testing/find-all-stress-packages.ps1 index 24c27da485..f949b03ad8 100644 --- a/eng/common/scripts/stress-testing/find-all-stress-packages.ps1 +++ b/eng/common/scripts/stress-testing/find-all-stress-packages.ps1 @@ -12,20 +12,42 @@ class StressTestPackageInfo { [string]$Deployer } +. $PSScriptRoot/../job-matrix/job-matrix-functions.ps1 +. $PSScriptRoot/generate-scenario-matrix.ps1 + function FindStressPackages( [string]$directory, [hashtable]$filters = @{}, [switch]$CI, - [string]$namespaceOverride + [string]$namespaceOverride, + [string]$MatrixSelection, + [Parameter(Mandatory=$False)][string]$MatrixFileName, + [Parameter(Mandatory=$False)][string]$MatrixDisplayNameFilter, + [Parameter(Mandatory=$False)][array]$MatrixFilters, + [Parameter(Mandatory=$False)][array]$MatrixReplace, + [Parameter(Mandatory=$False)][array]$MatrixNonSparseParameters ) { # Bare minimum filter for stress tests $filters['stressTest'] = 'true' - $packages = @() $chartFiles = Get-ChildItem -Recurse -Filter 'Chart.yaml' $directory + if (!$MatrixFileName) { + $MatrixFileName = '/scenarios-matrix.yaml' + } foreach ($chartFile in $chartFiles) { $chart = ParseChart $chartFile if (matchesAnnotations $chart $filters) { + $matrixFilePath = (Join-Path $chartFile.Directory.FullName $MatrixFileName) + if (Test-Path $matrixFilePath) { + GenerateScenarioMatrix ` + -matrixFilePath $matrixFilePath ` + -Selection $MatrixSelection ` + -DisplayNameFilter $MatrixDisplayNameFilter ` + -Filters $MatrixFilters ` + -Replace $MatrixReplace ` + -NonSparseParameters $MatrixNonSparseParameters + } + $packages += NewStressTestPackageInfo ` -chart $chart ` -chartFile $chartFile ` @@ -80,8 +102,8 @@ function NewStressTestPackageInfo( Namespace = $namespace.ToLower() Directory = $chartFile.DirectoryName ReleaseName = $chart.name - Dockerfile = $chart.annotations.dockerfile - DockerBuildDir = $chart.annotations.dockerbuilddir + Dockerfile = "dockerfile" -in $chart.annotations.keys ? $chart.annotations.dockerfile : $null + DockerBuildDir = "dockerbuilddir" -in $chart.annotations.keys ? $chart.annotations.dockerbuilddir : $null } } diff --git a/eng/common/scripts/stress-testing/generate-scenario-matrix.ps1 b/eng/common/scripts/stress-testing/generate-scenario-matrix.ps1 new file mode 100644 index 0000000000..aba8be3451 --- /dev/null +++ b/eng/common/scripts/stress-testing/generate-scenario-matrix.ps1 @@ -0,0 +1,86 @@ +param( + [string]$matrixFilePath, + [string]$Selection, + [Parameter(Mandatory=$False)][string]$DisplayNameFilter, + [Parameter(Mandatory=$False)][array]$Filters, + [Parameter(Mandatory=$False)][array]$Replace, + [Parameter(Mandatory=$False)][array]$NonSparseParameters +) + +function GenerateScenarioMatrix( + [string]$matrixFilePath, + [string]$Selection, + [Parameter(Mandatory=$False)][string]$DisplayNameFilter, + [Parameter(Mandatory=$False)][array]$Filters, + [Parameter(Mandatory=$False)][array]$Replace, + [Parameter(Mandatory=$False)][array]$NonSparseParameters +) { + $yamlConfig = Get-Content $matrixFilePath -Raw + + $prettyMatrix = &"$PSScriptRoot/../job-matrix/Create-JobMatrix.ps1" ` + -ConfigPath $matrixFilePath ` + -Selection $Selection ` + -DisplayNameFilter $DisplayNameFilter ` + -Filters $Filters ` + -Replace $Replace ` + -NonSparseParameters $NonSparseParameters + Write-Host $prettyMatrix + $prettyMatrix = $prettyMatrix | ConvertFrom-Json + + $scenariosMatrix = @() + foreach($permutation in $prettyMatrix.psobject.properties) { + $entry = @{} + $entry.Name = $permutation.Name -replace '_', '-' + $entry.Scenario = $entry.Name + $entry.Remove("Name") + foreach ($param in $permutation.value.psobject.properties) { + $entry.add($param.Name, $param.value) + } + $scenariosMatrix += $entry + } + + $valuesYaml = Get-Content -Raw (Join-Path (Split-Path $matrixFilePath) 'values.yaml') + $values = $valuesYaml | ConvertFrom-Yaml -Ordered + if (!$values) {$values = @{}} + + if ($values.ContainsKey('Scenarios')) { + throw "Please use matrix generation for stress test scenarios." + } + + $values.scenarios = $scenariosMatrix + $values | ConvertTo-Yaml | Out-File -FilePath (Join-Path $matrixFilePath '../generatedValues.yaml') +} + +function NewStressTestPackageInfo( + [hashtable]$chart, + [System.IO.FileInfo]$chartFile, + [switch]$CI, + [object]$namespaceOverride +) { + $namespace = if ($namespaceOverride) { + $namespaceOverride + } elseif ($CI) { + $chart.annotations.namespace + } else { + GetUsername + } + + return [StressTestPackageInfo]@{ + Namespace = $namespace.ToLower() + Directory = $chartFile.DirectoryName + ReleaseName = $chart.name + Dockerfile = $chart.annotations.dockerfile + DockerBuildDir = $chart.annotations.dockerbuilddir + } +} + +# Don't call functions when the script is being dot sourced +if ($MyInvocation.InvocationName -ne ".") { + GenerateScenarioMatrix ` + -matrixFilePath $matrixFilePath ` + -Selection $Selection ` + -DisplayNameFilter $DisplayNameFilter ` + -Filters $Filters ` + -Replace $Replace ` + -NonSparseParameters $NonSparseParameters +} diff --git a/eng/common/scripts/stress-testing/stress-test-deployment-lib.ps1 b/eng/common/scripts/stress-testing/stress-test-deployment-lib.ps1 index 9369dcc6ba..a082477779 100644 --- a/eng/common/scripts/stress-testing/stress-test-deployment-lib.ps1 +++ b/eng/common/scripts/stress-testing/stress-test-deployment-lib.ps1 @@ -79,7 +79,13 @@ function DeployStressTests( } return $true })] - [System.IO.FileInfo]$LocalAddonsPath + [System.IO.FileInfo]$LocalAddonsPath, + [Parameter(Mandatory=$False)][string]$MatrixFileName, + [Parameter(Mandatory=$False)][string]$MatrixSelection = "sparse", + [Parameter(Mandatory=$False)][string]$MatrixDisplayNameFilter, + [Parameter(Mandatory=$False)][array]$MatrixFilters, + [Parameter(Mandatory=$False)][array]$MatrixReplace, + [Parameter(Mandatory=$False)][array]$MatrixNonSparseParameters ) { if ($environment -eq 'pg') { if ($clusterGroup -or $subscription) { @@ -115,9 +121,17 @@ function DeployStressTests( Run helm repo update if ($LASTEXITCODE) { return $LASTEXITCODE } - $deployer = if ($deployId) { $deployId } else { GetUsername } - $pkgs = FindStressPackages -directory $searchDirectory -filters $filters -CI:$CI -namespaceOverride $Namespace + $pkgs = @(FindStressPackages ` + -directory $searchDirectory ` + -filters $filters ` + -CI:$CI ` + -namespaceOverride $Namespace ` + -MatrixSelection $MatrixSelection ` + -MatrixFileName $MatrixFileName ` + -MatrixFilters $MatrixFilters ` + -MatrixReplace $MatrixReplace ` + -MatrixNonSparseParameters $MatrixNonSparseParameters) Write-Host "" "Found $($pkgs.Length) stress test packages:" Write-Host $pkgs.Directory "" foreach ($pkg in $pkgs) { @@ -164,59 +178,96 @@ function DeployStressPackage( if ($LASTEXITCODE) { return } } - $imageTag = "${registryName}.azurecr.io" + $imageTagBase = "${registryName}.azurecr.io" if ($repositoryBase) { - $imageTag += "/$repositoryBase" + $imageTagBase += "/$repositoryBase" } - $imageTag += "/$($pkg.Namespace)/$($pkg.ReleaseName):${deployId}" + $imageTagBase += "/$($pkg.Namespace)/$($pkg.ReleaseName)" - $dockerFilePath = if ($pkg.Dockerfile) { - Join-Path $pkg.Directory $pkg.Dockerfile - } else { - "$($pkg.Directory)/Dockerfile" - } - $dockerFilePath = [System.IO.Path]::GetFullPath($dockerFilePath) - - if ($pushImages -and (Test-Path $dockerFilePath)) { - Write-Host "Building and pushing stress test docker image '$imageTag'" - $dockerFile = Get-ChildItem $dockerFilePath - $dockerBuildFolder = if ($pkg.DockerBuildDir) { - Join-Path $pkg.Directory $pkg.DockerBuildDir - } else { - $dockerFile.DirectoryName - } - $dockerBuildFolder = [System.IO.Path]::GetFullPath($dockerBuildFolder).Trim() + Write-Host "Creating namespace $($pkg.Namespace) if it does not exist..." + kubectl create namespace $pkg.Namespace --dry-run=client -o yaml | kubectl apply -f - + if ($LASTEXITCODE) {exit $LASTEXITCODE} - Run docker build -t $imageTag -f $dockerFile $dockerBuildFolder - if ($LASTEXITCODE) { return } + $dockerBuildConfigs = @() + + $genValFile = Join-Path $pkg.Directory "generatedValues.yaml" + $genVal = Get-Content $genValFile -Raw | ConvertFrom-Yaml -Ordered + if (Test-Path $genValFile) { + $scenarios = $genVal.Scenarios + foreach ($scenario in $scenarios) { + if ("image" -in $scenario.keys) { + $dockerFilePath = Join-Path $pkg.Directory $scenario.image + } else { + $dockerFilePath = "$($pkg.Directory)/Dockerfile" + } + $dockerFilePath = [System.IO.Path]::GetFullPath($dockerFilePath).Trim() - Write-Host "`nContainer image '$imageTag' successfully built. To run commands on the container locally:" -ForegroundColor Blue - Write-Host " docker run -it $imageTag" -ForegroundColor DarkBlue - Write-Host " docker run -it $imageTag " -ForegroundColor DarkBlue - Write-Host "To show installed container images:" -ForegroundColor Blue - Write-Host " docker image ls" -ForegroundColor DarkBlue - Write-Host "To show running containers:" -ForegroundColor Blue - Write-Host " docker ps" -ForegroundColor DarkBlue - - Run docker push $imageTag - if ($LASTEXITCODE) { - if ($login) { - Write-Warning "If docker push is failing due to authentication issues, try calling this script with '-Login'" + if ("imageBuildDir" -in $scenario.keys) { + $dockerBuildDir = Join-Path $pkg.Directory $scenario.imageBuildDir + } else { + $dockerBuildDir = Split-Path $dockerFilePath } - return + $dockerBuildDir = [System.IO.Path]::GetFullPath($dockerBuildDir).Trim() + $dockerBuildConfigs += @{"dockerFilePath"=$dockerFilePath; "dockerBuildDir"=$dockerBuildDir} } } + if ($pkg.Dockerfile -or $pkg.DockerBuildDir) { + throw "The chart.yaml docker config is depracated, please use the scenarios matrix instead." + } + - Write-Host "Creating namespace $($pkg.Namespace) if it does not exist..." - kubectl create namespace $pkg.Namespace --dry-run=client -o yaml | kubectl apply -f - - if ($LASTEXITCODE) {exit $LASTEXITCODE} + foreach ($dockerBuildConfig in $dockerBuildConfigs) { + $dockerFilePath = $dockerBuildConfig.dockerFilePath + $dockerBuildFolder = $dockerBuildConfig.dockerBuildDir + if (!(Test-Path $dockerFilePath)) { + throw "Invalid dockerfile path, cannot find dockerfile at ${dockerFilePath}" + } + if (!(Test-Path $dockerBuildFolder)) { + throw "Invalid docker build directory, cannot find directory ${dockerBuildFolder}" + } + $dockerfileName = ($dockerFilePath -split { $_ -in '\', '/' })[-1].ToLower() + $imageTag = $imageTagBase + "/${dockerfileName}:${deployId}" + if ($pushImages) { + Write-Host "Building and pushing stress test docker image '$imageTag'" + $dockerFile = Get-ChildItem $dockerFilePath + + Run docker build -t $imageTag -f $dockerFile $dockerBuildFolder + + Write-Host "`nContainer image '$imageTag' successfully built. To run commands on the container locally:" -ForegroundColor Blue + Write-Host " docker run -it $imageTag" -ForegroundColor DarkBlue + Write-Host " docker run -it $imageTag " -ForegroundColor DarkBlue + Write-Host "To show installed container images:" -ForegroundColor Blue + Write-Host " docker image ls" -ForegroundColor DarkBlue + Write-Host "To show running containers:" -ForegroundColor Blue + Write-Host " docker ps" -ForegroundColor DarkBlue + + Run docker push $imageTag + if ($LASTEXITCODE) { + if ($login) { + Write-Warning "If docker push is failing due to authentication issues, try calling this script with '-Login'" + } + } + } + $genVal.scenarios = foreach ($scenario in $genVal.scenarios) { + $dockerPath = Join-Path $pkg.Directory $scenario.image + if ("image" -notin $scenario) { + $dockerPath = $dockerFilePath + } + if ([System.IO.Path]::GetFullPath($dockerPath) -eq $dockerFilePath) { + $scenario.imageTag = $imageTag + } + $scenario + } + + $genVal | ConvertTo-Yaml | Out-File -FilePath $genValFile + } Write-Host "Installing or upgrading stress test $($pkg.ReleaseName) from $($pkg.Directory)" Run helm upgrade $pkg.ReleaseName $pkg.Directory ` -n $pkg.Namespace ` --install ` - --set image=$imageTag ` - --set stress-test-addons.env=$environment + --set stress-test-addons.env=$environment ` + --values generatedValues.yaml if ($LASTEXITCODE) { # Issues like 'UPGRADE FAILED: another operation (install/upgrade/rollback) is in progress' # can be the result of cancelled `upgrade` operations (e.g. ctrl-c). From fc50c08b20dc5871b03a036444bd3fd43521c35f Mon Sep 17 00:00:00 2001 From: George Arama <50641385+gearama@users.noreply.github.com> Date: Fri, 21 Oct 2022 09:36:49 -0700 Subject: [PATCH 06/21] Storageblob (#4043) * first take * grrrrr * qwqwq * ewqw * eewew * put back * pipeline * Set read-only VCPKG_BINARY_SOURCES_SECRET * Pass InstallLanguageSteps through the perf template * blop pipeline * path * ';l'l; * add support for sync param * --sync flag support * typo * sync * sync to y * for PR * clang Co-authored-by: Daniel Jurek --- .vscode/cspell.json | 1 + cmake-modules/PerfTest.cmake | 11 +++++ eng/pipelines/templates/jobs/perf.yml | 9 ++--- sdk/core/perf.yml | 8 ++++ sdk/core/perf/src/options.cpp | 3 +- .../azure-storage-blobs/perf-resources.bicep | 21 ++++++++++ sdk/storage/azure-storage-blobs/perf.yml | 40 +++++++++++++++++++ .../test/perf/CMakeLists.txt | 7 +++- .../src/azure_storage_blobs_perf_test.cpp | 1 + vcpkg.json | 2 +- 10 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 cmake-modules/PerfTest.cmake create mode 100644 sdk/storage/azure-storage-blobs/perf-resources.bicep create mode 100644 sdk/storage/azure-storage-blobs/perf.yml diff --git a/.vscode/cspell.json b/.vscode/cspell.json index fbd5d8dda6..cfbe17a05f 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -74,6 +74,7 @@ "HRESULT", "IMDS", "Intel", + "issecret", "itfactor", "iusg", "jepio", diff --git a/cmake-modules/PerfTest.cmake b/cmake-modules/PerfTest.cmake new file mode 100644 index 0000000000..001d7eae5f --- /dev/null +++ b/cmake-modules/PerfTest.cmake @@ -0,0 +1,11 @@ +macro(SetPerfDeps PACKAGE VAR_RESULT) + string(TOUPPER ${PACKAGE} SUFFIX) + string(CONCAT VAR_TRIGGER "VCPKG-" ${SUFFIX}) + message(STATUS "trigger name ${VAR_TRIGGER}") + if(DEFINED ENV{${VAR_TRIGGER}}) + find_package(${PACKAGE} $ENV{${VAR_TRIGGER}} EXACT) + add_compile_definitions(${VAR_RESULT}="$ENV{${VAR_TRIGGER}}") + else() + add_compile_definitions(${VAR_RESULT}="source") + endif() +endmacro() diff --git a/eng/pipelines/templates/jobs/perf.yml b/eng/pipelines/templates/jobs/perf.yml index a31dda892d..72cf243081 100644 --- a/eng/pipelines/templates/jobs/perf.yml +++ b/eng/pipelines/templates/jobs/perf.yml @@ -23,6 +23,9 @@ parameters: - name: EnvVars type: object default: [] +- name: InstallLanguageSteps + type: object + default: [] extends: template: /eng/common/pipelines/templates/jobs/perf.yml @@ -38,8 +41,4 @@ extends: Iterations: ${{ parameters.Iterations }} AdditionalArguments: ${{ parameters.AdditionalArguments }} EnvVars: ${{ parameters.EnvVars}} - InstallLanguageSteps: - - template: /eng/pipelines/templates/steps/vcpkg.yml - #/eng/pipelines/templates/steps/vcpkg-clone.yml - parameters: - RepoOwner: Microsoft + InstallLanguageSteps: ${{ parameters.InstallLanguageSteps }} diff --git a/sdk/core/perf.yml b/sdk/core/perf.yml index a8494272b1..6708e23dfa 100644 --- a/sdk/core/perf.yml +++ b/sdk/core/perf.yml @@ -30,3 +30,11 @@ extends: Arguments: ${{ parameters.Arguments }} Iterations: ${{ parameters.Iterations }} AdditionalArguments: ${{ parameters.AdditionalArguments }} + InstallLanguageSteps: + - pwsh: | + Write-Host "##vso[task.setvariable variable=VCPKG_BINARY_SOURCES_SECRET;issecret=true;]clear;x-azblob,https://cppvcpkgcache.blob.core.windows.net/public-vcpkg-container,,read" + displayName: Set Vcpkg Variables + + EnvVars: + # This is set in the InstallLanguageSteps + VCPKG_BINARY_SOURCES_SECRET: $(VCPKG_BINARY_SOURCES_SECRET) diff --git a/sdk/core/perf/src/options.cpp b/sdk/core/perf/src/options.cpp index ad404fe20b..f016936128 100644 --- a/sdk/core/perf/src/options.cpp +++ b/sdk/core/perf/src/options.cpp @@ -85,5 +85,6 @@ std::vector Azure::Perf::GlobalTestOptions::GetOptionMe {"Rate", {"-r", "--rate"}, "Target throughput (ops/sec). Default to no throughput.", 1}, {"Warmup", {"-w", "--warmup"}, "Duration of warmup in seconds. Default to 5 seconds.", 1}, {"TestProxies", {"-x", "--test-proxies"}, "URIs of TestProxy Servers (separated by ';')", 1}, - {"help", {"-h", "--help"}, "Display help information.", 0}}; + {"help", {"-h", "--help"}, "Display help information.", 0}, + {"Sync", {"-y", "--sync"}, "Runs sync version of test, not implemented", 0}}; } diff --git a/sdk/storage/azure-storage-blobs/perf-resources.bicep b/sdk/storage/azure-storage-blobs/perf-resources.bicep new file mode 100644 index 0000000000..f05d353d74 --- /dev/null +++ b/sdk/storage/azure-storage-blobs/perf-resources.bicep @@ -0,0 +1,21 @@ +param baseName string = resourceGroup().name +param location string = resourceGroup().location + +resource storageAccount 'Microsoft.Storage/storageAccounts@2019-06-01' = { + name: '${baseName}blob' + location: location + kind: 'BlockBlobStorage' + sku: { + name: 'Premium_LRS' + } +} + +var name = storageAccount.name +var key = storageAccount.listKeys().keys[0].value +var connectionString = 'DefaultEndpointsProtocol=https;AccountName=${name};AccountKey=${key}' + +output AZURE_STORAGE_ACCOUNT_NAME string = name +output AZURE_STORAGE_ACCOUNT_KEY string = key +output AZURE_STORAGE_CONNECTION_STRING string = connectionString +output STANDARD_STORAGE_CONNECTION_STRING string = connectionString +output STORAGE_CONNECTION_STRING string = connectionString diff --git a/sdk/storage/azure-storage-blobs/perf.yml b/sdk/storage/azure-storage-blobs/perf.yml new file mode 100644 index 0000000000..46eb0233c9 --- /dev/null +++ b/sdk/storage/azure-storage-blobs/perf.yml @@ -0,0 +1,40 @@ +parameters: +- name: PackageVersions + displayName: PackageVersions (regex of package versions to run) + type: string + default: '12|source' +- name: Tests + displayName: Tests (regex of tests to run) + type: string + default: '^(download|upload|list-blobs)$' +- name: Arguments + displayName: Arguments (regex of arguments to run) + type: string + default: '(10240)|(10485760)|(1073741824)|(5 )|(500 )|(50000 )' +- name: Iterations + displayName: Iterations (times to run each test) + type: number + default: '5' +- name: AdditionalArguments + displayName: AdditionalArguments (passed to PerfAutomation) + type: string + default: ' ' + +extends: + template: /eng/pipelines/templates/jobs/perf.yml + parameters: + ServiceDirectory: storage/azure-storage-blobs + Services: "^storage-blob$" + PackageVersions: ${{ parameters.PackageVersions }} + Tests: ${{ parameters.Tests }} + Arguments: ${{ parameters.Arguments }} + Iterations: ${{ parameters.Iterations }} + AdditionalArguments: ${{ parameters.AdditionalArguments }} + InstallLanguageSteps: + - pwsh: | + Write-Host "##vso[task.setvariable variable=VCPKG_BINARY_SOURCES_SECRET;issecret=true;]clear;x-azblob,https://cppvcpkgcache.blob.core.windows.net/public-vcpkg-container,,read" + displayName: Set Vcpkg Variables + + EnvVars: + # This is set in the InstallLanguageSteps + VCPKG_BINARY_SOURCES_SECRET: $(VCPKG_BINARY_SOURCES_SECRET) diff --git a/sdk/storage/azure-storage-blobs/test/perf/CMakeLists.txt b/sdk/storage/azure-storage-blobs/test/perf/CMakeLists.txt index 73159ded48..63a01d6d72 100644 --- a/sdk/storage/azure-storage-blobs/test/perf/CMakeLists.txt +++ b/sdk/storage/azure-storage-blobs/test/perf/CMakeLists.txt @@ -6,6 +6,8 @@ cmake_minimum_required (VERSION 3.13) project(azure-storage-blobs-perf LANGUAGES CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) +include(AzureVcpkg) +az_vcpkg_integrate() if(BUILD_TRANSPORT_CURL) set(DOWNLOAD_WITH_LIBCURL inc/azure/storage/blobs/test/download_blob_transport_only.hpp) @@ -35,6 +37,8 @@ add_executable ( create_per_service_target_build(storage azure-storage-blobs-perf) +include(PerfTest) +SETPERFDEPS(azure-storage-blobs-cpp VCPKG_STORAGE_BLOB_VERSION) # Include the headers from the project. target_include_directories( azure-storage-blobs-perf @@ -47,7 +51,8 @@ if (MSVC) target_compile_options(azure-storage-blobs-perf PUBLIC /wd4996) endif() + # link the `azure-perf` lib together with any other library which will be used for the tests. -target_link_libraries(azure-storage-blobs-perf PRIVATE azure-storage-blobs azure-perf) +target_link_libraries(azure-storage-blobs-perf PRIVATE Azure::azure-storage-blobs azure-perf) # Make sure the project will appear in the test folder for Visual Studio CMake view set_target_properties(azure-storage-blobs-perf PROPERTIES FOLDER "Tests/Storage") diff --git a/sdk/storage/azure-storage-blobs/test/perf/src/azure_storage_blobs_perf_test.cpp b/sdk/storage/azure-storage-blobs/test/perf/src/azure_storage_blobs_perf_test.cpp index 04fd4018eb..996f4e9607 100644 --- a/sdk/storage/azure-storage-blobs/test/perf/src/azure_storage_blobs_perf_test.cpp +++ b/sdk/storage/azure-storage-blobs/test/perf/src/azure_storage_blobs_perf_test.cpp @@ -16,6 +16,7 @@ int main(int argc, char** argv) { + std::cout << "Azure-storage-blobs VERSION " << VCPKG_STORAGE_BLOB_VERSION << std::endl; // Create the test list std::vector tests diff --git a/vcpkg.json b/vcpkg.json index 17fa92fee4..b88dcc5b0b 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -15,7 +15,7 @@ }, { "name": "opentelemetry-cpp", - "platform": "!uwp", + "platform": "!(windows & !static)", "version>=": "1.3.0" }, { From 5ddcbe8cc09a0a08f2a0e169b7cd4a45c92d1f54 Mon Sep 17 00:00:00 2001 From: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> Date: Fri, 21 Oct 2022 14:36:40 -0700 Subject: [PATCH 07/21] Upgrade cspell packages to version `^6.12.0` (#4044) to address dependabot issue https://github.com/Azure/azure-sdk-for-js/security/dependabot/13 Co-authored-by: Jeremy Meng --- eng/common/spelling/Invoke-Cspell.ps1 | 2 +- eng/common/spelling/package-lock.json | 1481 ++++++++++++++++--------- eng/common/spelling/package.json | 8 +- 3 files changed, 942 insertions(+), 549 deletions(-) diff --git a/eng/common/spelling/Invoke-Cspell.ps1 b/eng/common/spelling/Invoke-Cspell.ps1 index 2616644257..3275e52fac 100644 --- a/eng/common/spelling/Invoke-Cspell.ps1 +++ b/eng/common/spelling/Invoke-Cspell.ps1 @@ -84,7 +84,7 @@ if (!(Test-Path $CSpellConfigPath)) { function Test-VersionReportMatches() { # Arrange - $expectedPackageVersion = '5.12.3' + $expectedPackageVersion = '6.12.0' # Act $actual = &"$PSSCriptRoot/Invoke-Cspell.ps1" ` diff --git a/eng/common/spelling/package-lock.json b/eng/common/spelling/package-lock.json index 8878300b56..73aa96879e 100644 --- a/eng/common/spelling/package-lock.json +++ b/eng/common/spelling/package-lock.json @@ -1,41 +1,44 @@ { - "name": "cspell-locked", + "name": "cspell-version-pin", + "version": "0.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { + "name": "cspell-version-pin", + "version": "0.1.1", "dependencies": { - "@cspell/cspell-bundled-dicts": "^5.12.3", - "@cspell/cspell-types": "^5.12.3", - "cspell": "^5.12.3", - "cspell-lib": "^5.12.3" + "@cspell/cspell-bundled-dicts": "^6.12.0", + "@cspell/cspell-types": "^6.12.0", + "cspell": "^6.12.0", + "cspell-lib": "^6.12.0" } }, "node_modules/@babel/code-frame": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", - "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dependencies": { - "@babel/highlight": "^7.16.0" + "@babel/highlight": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", - "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dependencies": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -78,12 +81,12 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { "node": ">=4" } @@ -100,117 +103,150 @@ } }, "node_modules/@cspell/cspell-bundled-dicts": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.3.tgz", - "integrity": "sha512-f3kyUHYxyGqNt2DTphpmP8hr38YTL48wr4Dq7pZDbqDjLkerq9T7ufX2CZ2OfydBEdIgduX2UXwiow7IfdwY/A==", - "dependencies": { - "@cspell/dict-ada": "^1.1.2", - "@cspell/dict-aws": "^1.0.14", - "@cspell/dict-bash": "^1.0.15", - "@cspell/dict-companies": "^1.0.40", - "@cspell/dict-cpp": "^1.1.40", - "@cspell/dict-cryptocurrencies": "^1.0.10", - "@cspell/dict-csharp": "^1.0.11", - "@cspell/dict-css": "^1.0.12", - "@cspell/dict-django": "^1.0.26", - "@cspell/dict-dotnet": "^1.0.31", - "@cspell/dict-elixir": "^1.0.25", - "@cspell/dict-en_us": "^2.1.1", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-6.12.0.tgz", + "integrity": "sha512-myfsDwSJcAMjKbztKBG424wIp/YV9/lvxsgHFKxBGPi+nNx1p7TbOjAAO9EWk0mZVHyGKZwCFJS2ohkoqxJWoQ==", + "dependencies": { + "@cspell/dict-ada": "^2.0.1", + "@cspell/dict-aws": "^2.0.0", + "@cspell/dict-bash": "^2.0.4", + "@cspell/dict-companies": "^2.0.14", + "@cspell/dict-cpp": "^3.2.1", + "@cspell/dict-cryptocurrencies": "^2.0.0", + "@cspell/dict-csharp": "^3.0.1", + "@cspell/dict-css": "^2.1.0", + "@cspell/dict-dart": "^1.1.1", + "@cspell/dict-django": "^2.0.0", + "@cspell/dict-docker": "^1.1.1", + "@cspell/dict-dotnet": "^2.0.1", + "@cspell/dict-elixir": "^2.0.1", + "@cspell/dict-en_us": "^2.3.3", "@cspell/dict-en-gb": "^1.1.33", - "@cspell/dict-filetypes": "^1.1.8", - "@cspell/dict-fonts": "^1.0.14", - "@cspell/dict-fullstack": "^1.0.38", - "@cspell/dict-golang": "^1.1.24", - "@cspell/dict-haskell": "^1.0.13", - "@cspell/dict-html": "^1.1.9", - "@cspell/dict-html-symbol-entities": "^1.0.23", - "@cspell/dict-java": "^1.0.23", - "@cspell/dict-latex": "^1.0.25", - "@cspell/dict-lorem-ipsum": "^1.0.22", - "@cspell/dict-lua": "^1.0.16", - "@cspell/dict-node": "^1.0.12", - "@cspell/dict-npm": "^1.0.16", - "@cspell/dict-php": "^1.0.24", - "@cspell/dict-powershell": "^1.0.18", - "@cspell/dict-public-licenses": "^1.0.3", - "@cspell/dict-python": "^2.0.3", - "@cspell/dict-ruby": "^1.0.14", - "@cspell/dict-rust": "^1.0.23", - "@cspell/dict-scala": "^1.0.21", - "@cspell/dict-software-terms": "^1.0.47", - "@cspell/dict-typescript": "^1.0.19" - }, - "engines": { - "node": ">=12.13.0" + "@cspell/dict-filetypes": "^2.1.1", + "@cspell/dict-fonts": "^2.1.0", + "@cspell/dict-fullstack": "^2.0.6", + "@cspell/dict-git": "^1.0.1", + "@cspell/dict-golang": "^3.0.1", + "@cspell/dict-haskell": "^2.0.1", + "@cspell/dict-html": "^3.3.2", + "@cspell/dict-html-symbol-entities": "^3.0.0", + "@cspell/dict-java": "^3.0.7", + "@cspell/dict-latex": "^2.0.9", + "@cspell/dict-lorem-ipsum": "^2.0.1", + "@cspell/dict-lua": "^2.0.0", + "@cspell/dict-node": "^3.0.1", + "@cspell/dict-npm": "^3.1.2", + "@cspell/dict-php": "^2.0.0", + "@cspell/dict-powershell": "^2.0.0", + "@cspell/dict-public-licenses": "^1.0.6", + "@cspell/dict-python": "^3.0.6", + "@cspell/dict-r": "^1.0.3", + "@cspell/dict-ruby": "^2.0.2", + "@cspell/dict-rust": "^2.0.1", + "@cspell/dict-scala": "^2.0.0", + "@cspell/dict-software-terms": "^2.2.11", + "@cspell/dict-sql": "^1.0.4", + "@cspell/dict-swift": "^1.0.3", + "@cspell/dict-typescript": "^2.0.2", + "@cspell/dict-vue": "^2.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@cspell/cspell-pipe": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-6.12.0.tgz", + "integrity": "sha512-Nkm+tIJ5k+jZPovZCdmZhrWrwRFwnDq+7yCxhov0C7UX3hsSNtTJIpFuaCNEQJ+Whpvxdh1YKflvHiHYygEgTg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@cspell/cspell-service-bus": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-6.12.0.tgz", + "integrity": "sha512-GgvciSeMUekl8z8vP8//cs5/qRQJSLz9IVREf6fxQW4upjw6zXZ1KonwPqOF5uLocIMAr8eCdrJzHKuKvigJIA==", + "engines": { + "node": ">=14" } }, "node_modules/@cspell/cspell-types": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-5.12.3.tgz", - "integrity": "sha512-4l43apk3QGMkpszirKjrRGWmzZVuCyvoa0+kgWCl28dviLKsVonop8liBJaBzjmZbdpe27IKpMrNtj0fOus+fw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-6.12.0.tgz", + "integrity": "sha512-BcZTt05fNy9SGXfbPgUyxS4FfIaUpcVq8IOJ0noN+jsKsmlbssOUgJOB2ApN1h66FfWcKuFy/uNrjfcrQ7PTqg==", "engines": { - "node": ">=12.13.0" + "node": ">=14" } }, "node_modules/@cspell/dict-ada": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-1.1.2.tgz", - "integrity": "sha512-UDrcYcKIVyXDz5mInJabRNQpJoehjBFvja5W+GQyu9pGcx3BS3cAU8mWENstGR0Qc/iFTxB010qwF8F3cHA/aA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-2.0.1.tgz", + "integrity": "sha512-vopTJ1oHrrFYV5GU55Sr+AzItR78Uj5YbCaspYABmYKlq4NRrcUAUsr4bWgymDcspMIHO7e7IFcj48OKs1fndA==" }, "node_modules/@cspell/dict-aws": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-1.0.14.tgz", - "integrity": "sha512-K21CfB4ZpKYwwDQiPfic2zJA/uxkbsd4IQGejEvDAhE3z8wBs6g6BwwqdVO767M9NgZqc021yAVpr79N5pWe3w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-2.0.0.tgz", + "integrity": "sha512-NKz7pDZ7pwj/b33i3f4WLpC1rOOUMmENwYgftxU+giU2YBeKM2wZbMTSEIzsrel56r0UlQYmdIVlP/B4nnVaoQ==" }, "node_modules/@cspell/dict-bash": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-1.0.16.tgz", - "integrity": "sha512-GyxHfX23AWv4iJyKQsQ5lq4qlEXzi/mjyUmCh3LY+jv8Kggqt0F/KCxOHhH7vrFgInnZyuPrRuwxtWv+I2rbwQ==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-2.0.4.tgz", + "integrity": "sha512-uK/ehmp5LYrmRH2Gv3nbvdPswpkybJUn34WYKLpeuYHQktmi+pOI1A9uPdBPnSbMDffSvwQlQohIyKawz+X8Ag==" }, "node_modules/@cspell/dict-companies": { - "version": "1.0.40", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-1.0.40.tgz", - "integrity": "sha512-Aw07qiTroqSST2P5joSrC4uOA05zTXzI2wMb+me3q4Davv1D9sCkzXY0TGoC2vzhNv5ooemRi9KATGaBSdU1sw==" + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-2.0.14.tgz", + "integrity": "sha512-Sq1X29Z05OZ/UNqTwVhf3/WaqvJQy4/S6gS8qYI5AQRX45gVe8CPhNBLmZOTC6z8m716bfQCxa5rRT9YNSdTZg==" }, "node_modules/@cspell/dict-cpp": { - "version": "1.1.40", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-1.1.40.tgz", - "integrity": "sha512-sscfB3woNDNj60/yGXAdwNtIRWZ89y35xnIaJVDMk5TPMMpaDvuk0a34iOPIq0g4V+Y8e3RyAg71SH6ADwSjGw==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-3.2.1.tgz", + "integrity": "sha512-XcmzrKIghqFfrYLLaHtWKOp9rupiuGdc5ODONk+emsq0W5CIc3Abn27IQHwUzxzF+Cm5IfKAIJ5Kpe6hkzm0HQ==" }, "node_modules/@cspell/dict-cryptocurrencies": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-1.0.10.tgz", - "integrity": "sha512-47ABvDJOkaST/rXipNMfNvneHUzASvmL6K/CbOFpYKfsd0x23Jc9k1yaOC7JAm82XSC/8a7+3Yu+Fk2jVJNnsA==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-2.0.0.tgz", + "integrity": "sha512-nREysmmfOp7L2YCRAUufQahwD5/Punzb5AZ6eyg4zUamdRWHgBFphb5/9h2flt1vgdUfhc6hZcML21Ci7iXjaA==" }, "node_modules/@cspell/dict-csharp": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-1.0.11.tgz", - "integrity": "sha512-nub+ZCiTgmT87O+swI+FIAzNwaZPWUGckJU4GN402wBq420V+F4ZFqNV7dVALJrGaWH7LvADRtJxi6cZVHJKeA==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-3.0.1.tgz", + "integrity": "sha512-xkfQu03F388w4sdVQSSjrVMkxAxpTYB2yW7nw0XYtTjl3L/jBgvTr/j1BTjdFbQhdNf10Lg0Ak1kXOjmHodVqA==" }, "node_modules/@cspell/dict-css": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-1.0.12.tgz", - "integrity": "sha512-K6yuxej7n454O7dwKG6lHacHrAOMZ0PhMEbmV6qH2JH0U4TtWXfBASYugHvXZCDDx1UObpiJP+3tQJiBqfGpHA==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-2.1.0.tgz", + "integrity": "sha512-glASAELcGhh4Ru0rTQ4G9mTQxSyPwsZOON/5BYflB6Kks8YC8nUvKrtMCoo5W7CPKPfSEa8zUNctFQ1+IUYDHA==" + }, + "node_modules/@cspell/dict-dart": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-1.1.1.tgz", + "integrity": "sha512-XBOCpezXrgFN18kGEwqMpTUGZdw4BjCoJrNOo6qBdcdZySCrEHLwELraLOkcSba2kM4stmTp0t59FkwtP8TKOA==" }, "node_modules/@cspell/dict-django": { - "version": "1.0.26", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-1.0.26.tgz", - "integrity": "sha512-mn9bd7Et1L2zuibc08GVHTiD2Go3/hdjyX5KLukXDklBkq06r+tb0OtKtf1zKodtFDTIaYekGADhNhA6AnKLkg==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-2.0.0.tgz", + "integrity": "sha512-GkJdJv6cmzrKcmq2/oxTXjKF5uv71r4eTqnFmgPbNBW1t+G4VYpzOf0QrVQrhx2RC4DdW5XfcTf+iS0FxHOTmw==" + }, + "node_modules/@cspell/dict-docker": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.1.tgz", + "integrity": "sha512-UEYoeRDm7oUN9yz1mYSozz6D4+2N14S/cd2Re9et6Xzq6yi62s4ky3knF92Of2weelADjnN41UA22VBhRAf7Sw==" }, "node_modules/@cspell/dict-dotnet": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-1.0.32.tgz", - "integrity": "sha512-9H9vXrgJB4KF8xsyTToXO53cXD33iyfrpT4mhCds+YLUw3P3x3E9myszgJzshnrxYBvQZ+QMII57Qr6SjZVk4Q==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-2.0.1.tgz", + "integrity": "sha512-b1n4crJRW0WZVf9Gp/52j/tDtjYiZ3N81fIyfqPlBrjsh/5AivfA697DYwQ2mr8ngNX7RsqRtYNQjealA1rEnQ==" }, "node_modules/@cspell/dict-elixir": { - "version": "1.0.26", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-1.0.26.tgz", - "integrity": "sha512-hz1yETUiRJM7yjN3mITSnxcmZaEyaBbyJhpZPpg+cKUil+xhHeZ2wwfbRc83QHGmlqEuDWbdCFqKSpCDJYpYhg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-2.0.1.tgz", + "integrity": "sha512-eTTTxZt1FqGkM780yFDxsGHvTbWqvlK8YISSccK8FyrB6ULW+uflQlNS5AnWg3uWKC48b7pQott+odYCsPJ+Ow==" }, "node_modules/@cspell/dict-en_us": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-2.1.3.tgz", - "integrity": "sha512-71YlVhKRBd758UNPMNeZrZQdPafEKS0e4LAgbhyuGhJhwxzAJnJolKT3vQpiFdaH4zsEGVvK1l2oTHpQDt9sng==" + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-2.3.3.tgz", + "integrity": "sha512-csyKeaNktfpvMkmE2GOPTwsrQm3wWhLKVaDRaGU0qTcIjDiCvqv/iYgrVrKRkoddA3kdNTZ8YNCcix7lb6VkOg==" }, "node_modules/@cspell/dict-en-gb": { "version": "1.1.33", @@ -218,114 +254,139 @@ "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==" }, "node_modules/@cspell/dict-filetypes": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-1.1.8.tgz", - "integrity": "sha512-EllahNkhzvLWo0ptwu0l3oEeAJOQSUpZnDfnKRIh6mJVehuSovNHwA9vrdZ8jBUjuqcfaN2e7c32zN0D/qvWJQ==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-2.1.1.tgz", + "integrity": "sha512-Oo0/mUbFHzsaATqRLdkV1RMoYns3aGzeKFIpVJg415GYtJ8EABXtEArYTXeMwlboyGTPvEk+PR2hBSTSfQTqmg==" }, "node_modules/@cspell/dict-fonts": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-1.0.14.tgz", - "integrity": "sha512-VhIX+FVYAnqQrOuoFEtya6+H72J82cIicz9QddgknsTqZQ3dvgp6lmVnsQXPM3EnzA8n1peTGpLDwHzT7ociLA==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-2.1.0.tgz", + "integrity": "sha512-hk7xsbfWEUhc136Xj7I2TD7ouKAfWwzCVAQaHBxcVXAsVxu7bDOGj4FvE2jBzlkSUY8A9Ww8qS0GOFvowJshVg==" }, "node_modules/@cspell/dict-fullstack": { - "version": "1.0.39", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-1.0.39.tgz", - "integrity": "sha512-Mbi+zWdiP9yzL+X4YD9Tgcm5YQ95Ql+Y3vF2LRnOY6g2QWaijTRN1rgksVuxzpFqHi//+bx2uoUb0XEKBYDi8g==" + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-2.0.6.tgz", + "integrity": "sha512-R2E2xvbHvvRwwurxfpBJDRIJjXBMfEPF5WNV3LTOEMRqkZtoYCeJK9aqc8LHlmJMtAbnN1cx//BCDIyTJ0rO0A==" + }, + "node_modules/@cspell/dict-git": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-1.0.1.tgz", + "integrity": "sha512-Rk+eTof/9inF11lvxmkCRK+gODatA3qai8kSASv6OG/JfPvpj7fTHErx/rdgPw/LOTDUafnoTjTYmj7B2MOQXg==" }, "node_modules/@cspell/dict-golang": { - "version": "1.1.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-1.1.24.tgz", - "integrity": "sha512-qq3Cjnx2U1jpeWAGJL1GL0ylEhUMqyaR36Xij6Y6Aq4bViCRp+HRRqk0x5/IHHbOrti45h3yy7ii1itRFo+Xkg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-3.0.1.tgz", + "integrity": "sha512-0KNfXTbxHW2l8iVjxeOf+KFv9Qrw3z5cyKnkuYJWlBTSB5KcUBfeKCb4fsds26VdANqiy6U91b4gDx5kNEmBjQ==" }, "node_modules/@cspell/dict-haskell": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-1.0.13.tgz", - "integrity": "sha512-kvl8T84cnYRPpND/P3D86P6WRSqebsbk0FnMfy27zo15L5MLAb3d3MOiT1kW3vEWfQgzUD7uddX/vUiuroQ8TA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-2.0.1.tgz", + "integrity": "sha512-ooA23qIG7InOOxlLm67CNH5O2J85QsPHEAzEU9KEqVfYG5ovFs5tx6n9pHekDVk3MpQULpqfNUYDR0KigPLg5g==" }, "node_modules/@cspell/dict-html": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-1.1.9.tgz", - "integrity": "sha512-vvnYia0tyIS5Fdoz+gEQm77MGZZE66kOJjuNpIYyRHCXFAhWdYz3SmkRm6YKJSWSvuO+WBJYTKDvkOxSh3Fx/w==" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-3.3.2.tgz", + "integrity": "sha512-cM5pQSEiqjrdk6cRFLrlLdWNT/J8399f/A6DjwjfYhHrGy0e/Rsjv76HZT0GlE1OqMoq9eG9jdQsfoYYgWTIpQ==" }, "node_modules/@cspell/dict-html-symbol-entities": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-1.0.23.tgz", - "integrity": "sha512-PV0UBgcBFbBLf/m1wfkVMM8w96kvfHoiCGLWO6BR3Q9v70IXoE4ae0+T+f0CkxcEkacMqEQk/I7vuE9MzrjaNw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-3.0.0.tgz", + "integrity": "sha512-04K7cPTcbYXmHICfiob4gZA1yaj4hpfM+Nl5WIJ1EAZsSGHdqmGEF28GuCjyQ8ZeKiJAsPt/vXuLBbjxkHqZyQ==" }, "node_modules/@cspell/dict-java": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-1.0.23.tgz", - "integrity": "sha512-LcOg9srYLDoNGd8n3kbfDBlZD+LOC9IVcnFCdua1b/luCHNVmlgBx7e677qPu7olpMYOD5TQIVW2OmM1+/6MFA==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-3.0.7.tgz", + "integrity": "sha512-IL7ubsRvKX6dZSx++TplJCfhiS7kkEGpbTPG0gMEP50DTNAVM4icZS8zmer2UBCU5PTwF85abJjdX7mRADWKVg==" }, "node_modules/@cspell/dict-latex": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-1.0.25.tgz", - "integrity": "sha512-cEgg91Migqcp1SdVV7dUeMxbPDhxdNo6Fgq2eygAXQjIOFK520FFvh/qxyBvW90qdZbIRoU2AJpchyHfGuwZFA==" + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-2.0.9.tgz", + "integrity": "sha512-d1kTK6dJb5z6UcfASQWjqQlsjZvnoVOvMWxYtLpGksYf6gM4IgqoPVNMLYYK6xBS4T/uAnLIj975A6YuAeyZpg==" }, "node_modules/@cspell/dict-lorem-ipsum": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-1.0.22.tgz", - "integrity": "sha512-yqzspR+2ADeAGUxLTfZ4pXvPl7FmkENMRcGDECmddkOiuEwBCWMZdMP5fng9B0Q6j91hQ8w9CLvJKBz10TqNYg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-2.0.1.tgz", + "integrity": "sha512-s7Ft8UiloUJwgz4z8uLeFvCkeTcZ43HQl7mSAlZd76eW+keLSsdeGmLDx2zaciqo+MftPGyzygVCwaJjTGxiew==" }, "node_modules/@cspell/dict-lua": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-1.0.16.tgz", - "integrity": "sha512-YiHDt8kmHJ8nSBy0tHzaxiuitYp+oJ66ffCYuFWTNB3//Y0SI4OGHU3omLsQVeXIfCeVrO4DrVvRDoCls9B5zQ==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-2.0.0.tgz", + "integrity": "sha512-7WUEBEspSKtsq104WdIys1+DLqAxpJPzw74Py1TuE3fI5GvlzeSZkRFP2ya54GB2lCO4C3mq4M8EnitpibVDfw==" }, "node_modules/@cspell/dict-node": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-1.0.12.tgz", - "integrity": "sha512-RPNn/7CSkflAWk0sbSoOkg0ORrgBARUjOW3QjB11KwV1gSu8f5W/ij/S50uIXtlrfoBLqd4OyE04jyON+g/Xfg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-3.0.1.tgz", + "integrity": "sha512-sK2cpuV0EAc43Amd5xeQXkI9MeRTECMw+yjap06gKSModbgI7BqJUHeKZed+0Hii+LpaJ4TYpLGiRVsO+qSk0w==" }, "node_modules/@cspell/dict-npm": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-1.0.16.tgz", - "integrity": "sha512-RwkuZGcYBxL3Yux3cSG/IOWGlQ1e9HLCpHeyMtTVGYKAIkFAVUnGrz20l16/Q7zUG7IEktBz5O42kAozrEnqMQ==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-3.1.3.tgz", + "integrity": "sha512-xnGp+TMpArdMLBUSG+ZrbEuhvY016rb76Yh35/OPDDEEz4ulENxLSZJxtN2/A0tZ9FJngDNSdFh7eJsOFmciZQ==" }, "node_modules/@cspell/dict-php": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-1.0.25.tgz", - "integrity": "sha512-RoBIP5MRdByyPaXcznZMfOY1JdCMYPPLua5E9gkq0TJO7bX5mC9hyAKfYBSWVQunZydd82HZixjb5MPkDFU1uw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-2.0.0.tgz", + "integrity": "sha512-29WgU77eTO985LvMHwPi1pcpfopfCWfTdffDyqya0JIfOSaFUrlYKzGPkE4mRxcz2G3hXsaM0SRvBNdIRwEdUg==" }, "node_modules/@cspell/dict-powershell": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-1.0.19.tgz", - "integrity": "sha512-zF/raM/lkhXeHf4I43OtK0gP9rBeEJFArscTVwLWOCIvNk21MJcNoTYoaGw+c056+Q+hJL0psGLO7QN+mxYH1A==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-2.0.0.tgz", + "integrity": "sha512-6uvEhLiGmG3u9TFkM1TYcky6aL9Yk7Sk3KJwoTYBaQJY2KqrprgyQtW6yxIw9oU52VRHlq3KKvSAA9Q26+SIkQ==" }, "node_modules/@cspell/dict-public-licenses": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-1.0.3.tgz", - "integrity": "sha512-sXjxOHJ9Q4rZvE1UbwpwJQ8EXO3fadKBjJIWmz0z+dZAbvTrmz5Ln1Ef9ruJvLPfwAps8m3TCV6Diz60RAQqHg==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-1.0.6.tgz", + "integrity": "sha512-Z9IUFPkkOpOsEdgPUfQOJNQ+qU6+iBAZWS/CR5sUqTX+s5VkPNVwQyVC2kdmgmE2U5qwzAPewG6nVKr2MVogwg==" }, "node_modules/@cspell/dict-python": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-2.0.4.tgz", - "integrity": "sha512-71X/VnyFPm6OPEkqmoVXCJz28RvBgktxy6zF6D5TLt97LbWg2JyRrWSXaf2+seVoLnJQ5CHACxcs+jyEyLhBJA==" + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-3.0.6.tgz", + "integrity": "sha512-tzxJ4sd9ZGhAUKg/WJJpQGDNtoHvM8Wn+iS2+PnQj2/LTHBW4mnaCogsGsBtYu8C4b2+BEQs+tc5808AeEfLug==" + }, + "node_modules/@cspell/dict-r": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-1.0.3.tgz", + "integrity": "sha512-u2qeXd4cx/TvTVcmkvA+sK6f4K1uMAMO6QPMSr1pSvqGElPRP1mIBXmuiSuBzLO3LbsJuUEHw5Cp3/bxIB6rNA==" }, "node_modules/@cspell/dict-ruby": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-1.0.14.tgz", - "integrity": "sha512-XHBGN4U1y9rjRuqrCA+3yIm2TCdhwwHXpOEcWkNeyXm8K03yPnIrKFS+kap8GTTrLpfNDuFsrmkkQTa7ssXLRA==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-2.0.2.tgz", + "integrity": "sha512-vVnUpSmGDbPjs7MHq741DsLHhQcoA4CnUCM9wsTorQ9AQRDAkDTbK/LcY8nM19MoXCb3eF8PFku5Jq+gqH0u7w==" }, "node_modules/@cspell/dict-rust": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-1.0.23.tgz", - "integrity": "sha512-lR4boDzs79YD6+30mmiSGAMMdwh7HTBAPUFSB0obR3Kidibfc3GZ+MHWZXay5dxZ4nBKM06vyjtanF9VJ8q1Iw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-2.0.1.tgz", + "integrity": "sha512-ATDpIh0VWpQdUIZa8zqqJY4wQz3q00BTXlQCodeOmObYSb23+L6KWWzJ8mKLgpbc1lqTkogWrqxiCxlrCmqNmg==" }, "node_modules/@cspell/dict-scala": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-1.0.21.tgz", - "integrity": "sha512-5V/R7PRbbminTpPS3ywgdAalI9BHzcEjEj9ug4kWYvBIGwSnS7T6QCFCiu+e9LvEGUqQC+NHgLY4zs1NaBj2vA==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-2.0.0.tgz", + "integrity": "sha512-MUwA2YKpqaQOSR4V1/CVGRNk8Ii5kf6I8Ch+4/BhRZRQXuwWbi21rDRYWPqdQWps7VNzAbbMA+PQDWsD5YY38g==" }, "node_modules/@cspell/dict-software-terms": { - "version": "1.0.48", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-1.0.48.tgz", - "integrity": "sha512-pfF3Ys2gRffu5ElqkH7FQMDMi/iZMyOzpGMb3FSH0PJ2AnRQ5rRNWght1h2L36YxvXl0mWVaFrrfwiOyRIc8ZQ==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-2.3.0.tgz", + "integrity": "sha512-rl+quUw68IxjWgeX/QDMgQsImZ1DaKzFyYMSGrCNcNPp4b4SMLwHCKoJ97/uOnUnw0jaBxueXoqp2iyN/QiOVw==" + }, + "node_modules/@cspell/dict-sql": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-1.0.4.tgz", + "integrity": "sha512-+9nMcwsCzdYH0tyv2LeuVvQ+DdecS2C1N+hw6sl0FTHWI5GwULHAGW840RBwcKw0s+dl7sc0WpZhS1EW7b0pXg==" + }, + "node_modules/@cspell/dict-swift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-1.0.3.tgz", + "integrity": "sha512-yOBLSaRD0AnkkkndJ8PuB82Evp6lA2xItf2AWsnPfCCgxp5Ojk6uUBC/WQBSkzkCAOGbXyHsu9D97tsOx2c6cw==" }, "node_modules/@cspell/dict-typescript": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-1.0.19.tgz", - "integrity": "sha512-qmJApzoVskDeJnLZzZMaafEDGbEg5Elt4c3Mpg49SWzIHm1N4VXCp5CcFfHsOinJ30dGrs3ARAJGJZIw56kK6A==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-2.0.2.tgz", + "integrity": "sha512-OIoSJsCw9WHX4eDikoF5/0QbptMPZjElOcMYdYCyV03nqV5n4ot72ysTexW95yW4+fQU6uDPNQvnrUnhXXEkTA==" + }, + "node_modules/@cspell/dict-vue": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-2.0.2.tgz", + "integrity": "sha512-/MB0RS0Gn01s4pgmjy0FvsLfr3RRMrRphEuvTRserNcM8XVtoIVAtrjig/Gg0DPwDrN8Clm0L1j7iQay6S8D0g==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -365,12 +426,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -439,20 +499,20 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", "engines": { - "node": ">= 12" + "node": "^12.20.0 || >=14" } }, "node_modules/comment-json": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.1.1.tgz", - "integrity": "sha512-v8gmtPvxhBlhdRBLwdHSjGy9BgA23t9H1FctdQKyUrErPjSrJcdDMqBq9B4Irtm7w3TNYLQJNH6ARKnpyag1sA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.3.tgz", + "integrity": "sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==", "dependencies": { "array-timsort": "^1.0.3", - "core-util-is": "^1.0.2", + "core-util-is": "^1.0.3", "esprima": "^4.0.1", "has-own-prop": "^2.0.0", "repeat-string": "^1.6.1" @@ -464,7 +524,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/configstore": { "version": "5.0.1", @@ -511,105 +571,147 @@ } }, "node_modules/cspell": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.3.tgz", - "integrity": "sha512-lPyWZHfdQh+xjUZDAQC0gnpjglMu2AEfxBWlziTm3XuYuPGTvNJQSUrkMcH180tA3fkj8q2XFwfxHkXXAxm68w==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-6.12.0.tgz", + "integrity": "sha512-ny4xVEPYFP2jVf5w71Mnk4HKj6RbPH+CMSzUrOMbYVVNnQUj3GLfzy5DrSFLG0zGa353ZRC4/s9MsEvnAL8mkA==", "dependencies": { + "@cspell/cspell-pipe": "^6.12.0", "chalk": "^4.1.2", - "commander": "^8.2.0", - "comment-json": "^4.1.1", - "cspell-gitignore": "^5.12.3", - "cspell-glob": "^5.12.3", - "cspell-lib": "^5.12.3", + "commander": "^9.4.0", + "cspell-gitignore": "^6.12.0", + "cspell-glob": "^6.12.0", + "cspell-lib": "^6.12.0", "fast-json-stable-stringify": "^2.1.0", "file-entry-cache": "^6.0.1", - "fs-extra": "^10.0.0", + "fs-extra": "^10.1.0", "get-stdin": "^8.0.0", - "glob": "^7.2.0", + "glob": "^8.0.3", "imurmurhash": "^0.1.4", + "semver": "^7.3.7", "strip-ansi": "^6.0.1", - "vscode-uri": "^3.0.2" + "vscode-uri": "^3.0.6" }, "bin": { "cspell": "bin.js" }, "engines": { - "node": ">=12.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/streetsidesoftware/cspell?sponsor=1" } }, + "node_modules/cspell-dictionary": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-6.12.0.tgz", + "integrity": "sha512-I2cXSdXndt9H7yXmJzLTjgui/SAPGghXwxFeibTbvF68gyQYD5fUXvOygEIPrOEySKlAIb+aouV77SgoURxMHw==", + "dependencies": { + "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-types": "^6.12.0", + "cspell-trie-lib": "^6.12.0", + "fast-equals": "^4.0.3", + "gensequence": "^4.0.2" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/cspell-gitignore": { - "version": "5.12.6", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.6.tgz", - "integrity": "sha512-4C6kNc6y9avFvd0/1LiSi139TZwWc4o1vxWBlSEACjeJ7fMKiunIRCrDPb8QPtzDy+Ot+CGNk+ONi3nBqMX8cw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-6.12.0.tgz", + "integrity": "sha512-gtsN2AAvqdE8CHVzpxsQcd/Wn5GAMTjzHpDXX71g/k8IJn743poGU06O0O1WSVAgK0fWTRsfg+V5OegA1TAo7A==", "dependencies": { - "cspell-glob": "^5.12.6", + "cspell-glob": "^6.12.0", "find-up": "^5.0.0" }, "bin": { "cspell-gitignore": "bin.js" }, "engines": { - "node": ">=12.13.0" + "node": ">=14" } }, "node_modules/cspell-glob": { - "version": "5.12.6", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-5.12.6.tgz", - "integrity": "sha512-trAnJLEsqpS8SbD2ZTBjLlLuauneZwC4BFiizUeb80EoCgexwMS1F2pzHngDQ+u4JmMcIuBsNgTWiYwuyu+/Wg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-6.12.0.tgz", + "integrity": "sha512-Q0rMGTxDyFFPm1LmHYM0ziuxQt2aXgr8Oi1glA2s0dBs0hg1DexlAEoLwLiMDUwSTvibEKIidPzlrmZ1AUDWEg==", + "dependencies": { + "micromatch": "^4.0.5" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/cspell-grammar": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-6.12.0.tgz", + "integrity": "sha512-WXcDiWJ2pTW0jHY0Bf0DW5s8A9S0a+2tsVZsNxE/0CR5P/8yDSnznE+59uok/JN+GXOKQ6VIaqAZA3/XjDZuuA==", "dependencies": { - "micromatch": "^4.0.4" + "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-types": "^6.12.0" + }, + "bin": { + "cspell-grammar": "bin.js" }, "engines": { - "node": ">=12.13.0" + "node": ">=14" } }, "node_modules/cspell-io": { - "version": "5.12.6", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-5.12.6.tgz", - "integrity": "sha512-pTcxw5+/GKD5qIxTcQzWq6pTfWmSVAZVD11kkQ9gFYwX+JYdYmm3Af2x8u5oV46IKL0eAuLp7F1kfan1IsRnEA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-6.12.0.tgz", + "integrity": "sha512-1faxDj2OMgq61w7GaiXZD7ytks6PksJlG484LMl2USv58jDky4i2lujJs1C/+aP97Box9EcdwzydHX9GpnqqCw==", + "dependencies": { + "@cspell/cspell-service-bus": "^6.12.0", + "node-fetch": "^2.6.7" + }, "engines": { - "node": ">=12.13.0" + "node": ">=14" } }, "node_modules/cspell-lib": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.3.tgz", - "integrity": "sha512-wiS3X3inzkwr2d6UojVLjzGFxwhnE+HoQYg7cDyC2qqK1Q++36c5bHJGE8564lsVedeAMVbHh81bP7hibg/yUw==", - "dependencies": { - "@cspell/cspell-bundled-dicts": "^5.12.3", - "@cspell/cspell-types": "^5.12.3", - "clear-module": "^4.1.1", - "comment-json": "^4.1.1", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-6.12.0.tgz", + "integrity": "sha512-IKd2MzH/zoiXohc26Lqb1b8i+41Y2xGreyAe9ihv/7Z2dscGGVy7F/2taZvZK9kJIhaz33Yatxfx3htT6w0hqg==", + "dependencies": { + "@cspell/cspell-bundled-dicts": "^6.12.0", + "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-types": "^6.12.0", + "clear-module": "^4.1.2", + "comment-json": "^4.2.3", "configstore": "^5.0.1", "cosmiconfig": "^7.0.1", - "cspell-glob": "^5.12.3", - "cspell-io": "^5.12.3", - "cspell-trie-lib": "^5.12.3", + "cspell-dictionary": "^6.12.0", + "cspell-glob": "^6.12.0", + "cspell-grammar": "^6.12.0", + "cspell-io": "^6.12.0", + "cspell-trie-lib": "^6.12.0", + "fast-equals": "^4.0.3", "find-up": "^5.0.0", - "fs-extra": "^10.0.0", - "gensequence": "^3.1.1", + "fs-extra": "^10.1.0", + "gensequence": "^4.0.2", "import-fresh": "^3.3.0", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0", - "vscode-uri": "^3.0.2" + "vscode-languageserver-textdocument": "^1.0.7", + "vscode-uri": "^3.0.6" }, "engines": { - "node": ">=12.13.0" + "node": ">=14" } }, "node_modules/cspell-trie-lib": { - "version": "5.12.6", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.6.tgz", - "integrity": "sha512-ahT/lzhA7WiXzkFadOaXngPfxA74n4YLXXsZi+lL8/GgdezgbcsL4OoKuiKv24pMSLQBuJ6MOSWSr6rlNrImkw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-6.12.0.tgz", + "integrity": "sha512-SJOdb51Wy3ewaKfttZwc9NYOIXaKlhyr+ykYKBExj3qMfV1J4d4iDLE95FriaRcqnq6X/qEM9jUvZHlvadDk3A==", "dependencies": { - "fs-extra": "^10.0.0", - "gensequence": "^3.1.1" + "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-types": "^6.12.0", + "fs-extra": "^10.1.0", + "gensequence": "^4.0.2" }, "engines": { - "node": ">=12.13.0" + "node": ">=14" } }, "node_modules/dot-prop": { @@ -634,7 +736,7 @@ "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { "node": ">=0.8.0" } @@ -651,6 +753,11 @@ "node": ">=4" } }, + "node_modules/fast-equals": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz", + "integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -706,14 +813,14 @@ } }, "node_modules/flatted": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", - "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==" + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, "node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -726,14 +833,14 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/gensequence": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-3.1.1.tgz", - "integrity": "sha512-ys3h0hiteRwmY6BsvSttPmkhC0vEQHPJduANBRtH/dlDPZ0UBIb/dXy80IcckXyuQ6LKg+PloRqvGER9IS7F7g==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-4.0.2.tgz", + "integrity": "sha512-mQiFskYFPFDSUpBJ/n3ebAV2Ufu6DZGvUPXzyWYzFfJr6/DyOOZVnjx6VTWE4y0RLvYWnc5tZq5sCjzEWhRjqQ==", "engines": { - "node": ">=10.0.0" + "node": ">=14" } }, "node_modules/get-stdin": { @@ -748,19 +855,18 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -769,7 +875,7 @@ "node_modules/global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", "dependencies": { "ini": "^1.3.4" }, @@ -778,9 +884,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "node_modules/has-flag": { "version": "4.0.0", @@ -835,7 +941,7 @@ "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "engines": { "node": ">=0.8.19" } @@ -843,7 +949,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -862,7 +968,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-number": { "version": "7.0.0", @@ -883,7 +989,7 @@ "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, "node_modules/js-tokens": { "version": "4.0.0", @@ -907,9 +1013,9 @@ } }, "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/locate-path": { "version": "6.0.0", @@ -925,6 +1031,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -939,33 +1056,60 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=10" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dependencies": { "wrappy": "1" } @@ -1037,7 +1181,7 @@ "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "engines": { "node": ">=0.10.0" } @@ -1051,9 +1195,9 @@ } }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { "node": ">=8.6" }, @@ -1064,7 +1208,7 @@ "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "engines": { "node": ">=0.10" } @@ -1102,18 +1246,63 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/strip-ansi": { "version": "6.0.1", @@ -1148,6 +1337,11 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -1175,15 +1369,34 @@ "node": ">= 10.0.0" } }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz", + "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg==" + }, "node_modules/vscode-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.2.tgz", - "integrity": "sha512-jkjy6pjU1fxUvI51P+gCsxg1u2n8LSt0W6KrCNQceaziKzff74GoWmjVG46KieVzybO1sttPQmYfrwSHey7GUA==" + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz", + "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "3.0.3", @@ -1204,6 +1417,11 @@ "node": ">=8" } }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", @@ -1226,24 +1444,24 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", - "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "requires": { - "@babel/highlight": "^7.16.0" + "@babel/highlight": "^7.18.6" } }, "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" }, "@babel/highlight": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", - "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "requires": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -1277,12 +1495,12 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "supports-color": { "version": "5.5.0", @@ -1295,111 +1513,138 @@ } }, "@cspell/cspell-bundled-dicts": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.3.tgz", - "integrity": "sha512-f3kyUHYxyGqNt2DTphpmP8hr38YTL48wr4Dq7pZDbqDjLkerq9T7ufX2CZ2OfydBEdIgduX2UXwiow7IfdwY/A==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-6.12.0.tgz", + "integrity": "sha512-myfsDwSJcAMjKbztKBG424wIp/YV9/lvxsgHFKxBGPi+nNx1p7TbOjAAO9EWk0mZVHyGKZwCFJS2ohkoqxJWoQ==", "requires": { - "@cspell/dict-ada": "^1.1.2", - "@cspell/dict-aws": "^1.0.14", - "@cspell/dict-bash": "^1.0.15", - "@cspell/dict-companies": "^1.0.40", - "@cspell/dict-cpp": "^1.1.40", - "@cspell/dict-cryptocurrencies": "^1.0.10", - "@cspell/dict-csharp": "^1.0.11", - "@cspell/dict-css": "^1.0.12", - "@cspell/dict-django": "^1.0.26", - "@cspell/dict-dotnet": "^1.0.31", - "@cspell/dict-elixir": "^1.0.25", - "@cspell/dict-en_us": "^2.1.1", + "@cspell/dict-ada": "^2.0.1", + "@cspell/dict-aws": "^2.0.0", + "@cspell/dict-bash": "^2.0.4", + "@cspell/dict-companies": "^2.0.14", + "@cspell/dict-cpp": "^3.2.1", + "@cspell/dict-cryptocurrencies": "^2.0.0", + "@cspell/dict-csharp": "^3.0.1", + "@cspell/dict-css": "^2.1.0", + "@cspell/dict-dart": "^1.1.1", + "@cspell/dict-django": "^2.0.0", + "@cspell/dict-docker": "^1.1.1", + "@cspell/dict-dotnet": "^2.0.1", + "@cspell/dict-elixir": "^2.0.1", + "@cspell/dict-en_us": "^2.3.3", "@cspell/dict-en-gb": "^1.1.33", - "@cspell/dict-filetypes": "^1.1.8", - "@cspell/dict-fonts": "^1.0.14", - "@cspell/dict-fullstack": "^1.0.38", - "@cspell/dict-golang": "^1.1.24", - "@cspell/dict-haskell": "^1.0.13", - "@cspell/dict-html": "^1.1.9", - "@cspell/dict-html-symbol-entities": "^1.0.23", - "@cspell/dict-java": "^1.0.23", - "@cspell/dict-latex": "^1.0.25", - "@cspell/dict-lorem-ipsum": "^1.0.22", - "@cspell/dict-lua": "^1.0.16", - "@cspell/dict-node": "^1.0.12", - "@cspell/dict-npm": "^1.0.16", - "@cspell/dict-php": "^1.0.24", - "@cspell/dict-powershell": "^1.0.18", - "@cspell/dict-public-licenses": "^1.0.3", - "@cspell/dict-python": "^2.0.3", - "@cspell/dict-ruby": "^1.0.14", - "@cspell/dict-rust": "^1.0.23", - "@cspell/dict-scala": "^1.0.21", - "@cspell/dict-software-terms": "^1.0.47", - "@cspell/dict-typescript": "^1.0.19" - } + "@cspell/dict-filetypes": "^2.1.1", + "@cspell/dict-fonts": "^2.1.0", + "@cspell/dict-fullstack": "^2.0.6", + "@cspell/dict-git": "^1.0.1", + "@cspell/dict-golang": "^3.0.1", + "@cspell/dict-haskell": "^2.0.1", + "@cspell/dict-html": "^3.3.2", + "@cspell/dict-html-symbol-entities": "^3.0.0", + "@cspell/dict-java": "^3.0.7", + "@cspell/dict-latex": "^2.0.9", + "@cspell/dict-lorem-ipsum": "^2.0.1", + "@cspell/dict-lua": "^2.0.0", + "@cspell/dict-node": "^3.0.1", + "@cspell/dict-npm": "^3.1.2", + "@cspell/dict-php": "^2.0.0", + "@cspell/dict-powershell": "^2.0.0", + "@cspell/dict-public-licenses": "^1.0.6", + "@cspell/dict-python": "^3.0.6", + "@cspell/dict-r": "^1.0.3", + "@cspell/dict-ruby": "^2.0.2", + "@cspell/dict-rust": "^2.0.1", + "@cspell/dict-scala": "^2.0.0", + "@cspell/dict-software-terms": "^2.2.11", + "@cspell/dict-sql": "^1.0.4", + "@cspell/dict-swift": "^1.0.3", + "@cspell/dict-typescript": "^2.0.2", + "@cspell/dict-vue": "^2.0.2" + } + }, + "@cspell/cspell-pipe": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-6.12.0.tgz", + "integrity": "sha512-Nkm+tIJ5k+jZPovZCdmZhrWrwRFwnDq+7yCxhov0C7UX3hsSNtTJIpFuaCNEQJ+Whpvxdh1YKflvHiHYygEgTg==" + }, + "@cspell/cspell-service-bus": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-6.12.0.tgz", + "integrity": "sha512-GgvciSeMUekl8z8vP8//cs5/qRQJSLz9IVREf6fxQW4upjw6zXZ1KonwPqOF5uLocIMAr8eCdrJzHKuKvigJIA==" }, "@cspell/cspell-types": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-5.12.3.tgz", - "integrity": "sha512-4l43apk3QGMkpszirKjrRGWmzZVuCyvoa0+kgWCl28dviLKsVonop8liBJaBzjmZbdpe27IKpMrNtj0fOus+fw==" + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-6.12.0.tgz", + "integrity": "sha512-BcZTt05fNy9SGXfbPgUyxS4FfIaUpcVq8IOJ0noN+jsKsmlbssOUgJOB2ApN1h66FfWcKuFy/uNrjfcrQ7PTqg==" }, "@cspell/dict-ada": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-1.1.2.tgz", - "integrity": "sha512-UDrcYcKIVyXDz5mInJabRNQpJoehjBFvja5W+GQyu9pGcx3BS3cAU8mWENstGR0Qc/iFTxB010qwF8F3cHA/aA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-2.0.1.tgz", + "integrity": "sha512-vopTJ1oHrrFYV5GU55Sr+AzItR78Uj5YbCaspYABmYKlq4NRrcUAUsr4bWgymDcspMIHO7e7IFcj48OKs1fndA==" }, "@cspell/dict-aws": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-1.0.14.tgz", - "integrity": "sha512-K21CfB4ZpKYwwDQiPfic2zJA/uxkbsd4IQGejEvDAhE3z8wBs6g6BwwqdVO767M9NgZqc021yAVpr79N5pWe3w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-2.0.0.tgz", + "integrity": "sha512-NKz7pDZ7pwj/b33i3f4WLpC1rOOUMmENwYgftxU+giU2YBeKM2wZbMTSEIzsrel56r0UlQYmdIVlP/B4nnVaoQ==" }, "@cspell/dict-bash": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-1.0.16.tgz", - "integrity": "sha512-GyxHfX23AWv4iJyKQsQ5lq4qlEXzi/mjyUmCh3LY+jv8Kggqt0F/KCxOHhH7vrFgInnZyuPrRuwxtWv+I2rbwQ==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-2.0.4.tgz", + "integrity": "sha512-uK/ehmp5LYrmRH2Gv3nbvdPswpkybJUn34WYKLpeuYHQktmi+pOI1A9uPdBPnSbMDffSvwQlQohIyKawz+X8Ag==" }, "@cspell/dict-companies": { - "version": "1.0.40", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-1.0.40.tgz", - "integrity": "sha512-Aw07qiTroqSST2P5joSrC4uOA05zTXzI2wMb+me3q4Davv1D9sCkzXY0TGoC2vzhNv5ooemRi9KATGaBSdU1sw==" + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-2.0.14.tgz", + "integrity": "sha512-Sq1X29Z05OZ/UNqTwVhf3/WaqvJQy4/S6gS8qYI5AQRX45gVe8CPhNBLmZOTC6z8m716bfQCxa5rRT9YNSdTZg==" }, "@cspell/dict-cpp": { - "version": "1.1.40", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-1.1.40.tgz", - "integrity": "sha512-sscfB3woNDNj60/yGXAdwNtIRWZ89y35xnIaJVDMk5TPMMpaDvuk0a34iOPIq0g4V+Y8e3RyAg71SH6ADwSjGw==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-3.2.1.tgz", + "integrity": "sha512-XcmzrKIghqFfrYLLaHtWKOp9rupiuGdc5ODONk+emsq0W5CIc3Abn27IQHwUzxzF+Cm5IfKAIJ5Kpe6hkzm0HQ==" }, "@cspell/dict-cryptocurrencies": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-1.0.10.tgz", - "integrity": "sha512-47ABvDJOkaST/rXipNMfNvneHUzASvmL6K/CbOFpYKfsd0x23Jc9k1yaOC7JAm82XSC/8a7+3Yu+Fk2jVJNnsA==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-2.0.0.tgz", + "integrity": "sha512-nREysmmfOp7L2YCRAUufQahwD5/Punzb5AZ6eyg4zUamdRWHgBFphb5/9h2flt1vgdUfhc6hZcML21Ci7iXjaA==" }, "@cspell/dict-csharp": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-1.0.11.tgz", - "integrity": "sha512-nub+ZCiTgmT87O+swI+FIAzNwaZPWUGckJU4GN402wBq420V+F4ZFqNV7dVALJrGaWH7LvADRtJxi6cZVHJKeA==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-3.0.1.tgz", + "integrity": "sha512-xkfQu03F388w4sdVQSSjrVMkxAxpTYB2yW7nw0XYtTjl3L/jBgvTr/j1BTjdFbQhdNf10Lg0Ak1kXOjmHodVqA==" }, "@cspell/dict-css": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-1.0.12.tgz", - "integrity": "sha512-K6yuxej7n454O7dwKG6lHacHrAOMZ0PhMEbmV6qH2JH0U4TtWXfBASYugHvXZCDDx1UObpiJP+3tQJiBqfGpHA==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-2.1.0.tgz", + "integrity": "sha512-glASAELcGhh4Ru0rTQ4G9mTQxSyPwsZOON/5BYflB6Kks8YC8nUvKrtMCoo5W7CPKPfSEa8zUNctFQ1+IUYDHA==" + }, + "@cspell/dict-dart": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-1.1.1.tgz", + "integrity": "sha512-XBOCpezXrgFN18kGEwqMpTUGZdw4BjCoJrNOo6qBdcdZySCrEHLwELraLOkcSba2kM4stmTp0t59FkwtP8TKOA==" }, "@cspell/dict-django": { - "version": "1.0.26", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-1.0.26.tgz", - "integrity": "sha512-mn9bd7Et1L2zuibc08GVHTiD2Go3/hdjyX5KLukXDklBkq06r+tb0OtKtf1zKodtFDTIaYekGADhNhA6AnKLkg==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-2.0.0.tgz", + "integrity": "sha512-GkJdJv6cmzrKcmq2/oxTXjKF5uv71r4eTqnFmgPbNBW1t+G4VYpzOf0QrVQrhx2RC4DdW5XfcTf+iS0FxHOTmw==" + }, + "@cspell/dict-docker": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.1.tgz", + "integrity": "sha512-UEYoeRDm7oUN9yz1mYSozz6D4+2N14S/cd2Re9et6Xzq6yi62s4ky3knF92Of2weelADjnN41UA22VBhRAf7Sw==" }, "@cspell/dict-dotnet": { - "version": "1.0.32", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-1.0.32.tgz", - "integrity": "sha512-9H9vXrgJB4KF8xsyTToXO53cXD33iyfrpT4mhCds+YLUw3P3x3E9myszgJzshnrxYBvQZ+QMII57Qr6SjZVk4Q==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-2.0.1.tgz", + "integrity": "sha512-b1n4crJRW0WZVf9Gp/52j/tDtjYiZ3N81fIyfqPlBrjsh/5AivfA697DYwQ2mr8ngNX7RsqRtYNQjealA1rEnQ==" }, "@cspell/dict-elixir": { - "version": "1.0.26", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-1.0.26.tgz", - "integrity": "sha512-hz1yETUiRJM7yjN3mITSnxcmZaEyaBbyJhpZPpg+cKUil+xhHeZ2wwfbRc83QHGmlqEuDWbdCFqKSpCDJYpYhg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-2.0.1.tgz", + "integrity": "sha512-eTTTxZt1FqGkM780yFDxsGHvTbWqvlK8YISSccK8FyrB6ULW+uflQlNS5AnWg3uWKC48b7pQott+odYCsPJ+Ow==" }, "@cspell/dict-en_us": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-2.1.3.tgz", - "integrity": "sha512-71YlVhKRBd758UNPMNeZrZQdPafEKS0e4LAgbhyuGhJhwxzAJnJolKT3vQpiFdaH4zsEGVvK1l2oTHpQDt9sng==" + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-2.3.3.tgz", + "integrity": "sha512-csyKeaNktfpvMkmE2GOPTwsrQm3wWhLKVaDRaGU0qTcIjDiCvqv/iYgrVrKRkoddA3kdNTZ8YNCcix7lb6VkOg==" }, "@cspell/dict-en-gb": { "version": "1.1.33", @@ -1407,114 +1652,139 @@ "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==" }, "@cspell/dict-filetypes": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-1.1.8.tgz", - "integrity": "sha512-EllahNkhzvLWo0ptwu0l3oEeAJOQSUpZnDfnKRIh6mJVehuSovNHwA9vrdZ8jBUjuqcfaN2e7c32zN0D/qvWJQ==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-2.1.1.tgz", + "integrity": "sha512-Oo0/mUbFHzsaATqRLdkV1RMoYns3aGzeKFIpVJg415GYtJ8EABXtEArYTXeMwlboyGTPvEk+PR2hBSTSfQTqmg==" }, "@cspell/dict-fonts": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-1.0.14.tgz", - "integrity": "sha512-VhIX+FVYAnqQrOuoFEtya6+H72J82cIicz9QddgknsTqZQ3dvgp6lmVnsQXPM3EnzA8n1peTGpLDwHzT7ociLA==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-2.1.0.tgz", + "integrity": "sha512-hk7xsbfWEUhc136Xj7I2TD7ouKAfWwzCVAQaHBxcVXAsVxu7bDOGj4FvE2jBzlkSUY8A9Ww8qS0GOFvowJshVg==" }, "@cspell/dict-fullstack": { - "version": "1.0.39", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-1.0.39.tgz", - "integrity": "sha512-Mbi+zWdiP9yzL+X4YD9Tgcm5YQ95Ql+Y3vF2LRnOY6g2QWaijTRN1rgksVuxzpFqHi//+bx2uoUb0XEKBYDi8g==" + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-2.0.6.tgz", + "integrity": "sha512-R2E2xvbHvvRwwurxfpBJDRIJjXBMfEPF5WNV3LTOEMRqkZtoYCeJK9aqc8LHlmJMtAbnN1cx//BCDIyTJ0rO0A==" + }, + "@cspell/dict-git": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-1.0.1.tgz", + "integrity": "sha512-Rk+eTof/9inF11lvxmkCRK+gODatA3qai8kSASv6OG/JfPvpj7fTHErx/rdgPw/LOTDUafnoTjTYmj7B2MOQXg==" }, "@cspell/dict-golang": { - "version": "1.1.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-1.1.24.tgz", - "integrity": "sha512-qq3Cjnx2U1jpeWAGJL1GL0ylEhUMqyaR36Xij6Y6Aq4bViCRp+HRRqk0x5/IHHbOrti45h3yy7ii1itRFo+Xkg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-3.0.1.tgz", + "integrity": "sha512-0KNfXTbxHW2l8iVjxeOf+KFv9Qrw3z5cyKnkuYJWlBTSB5KcUBfeKCb4fsds26VdANqiy6U91b4gDx5kNEmBjQ==" }, "@cspell/dict-haskell": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-1.0.13.tgz", - "integrity": "sha512-kvl8T84cnYRPpND/P3D86P6WRSqebsbk0FnMfy27zo15L5MLAb3d3MOiT1kW3vEWfQgzUD7uddX/vUiuroQ8TA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-2.0.1.tgz", + "integrity": "sha512-ooA23qIG7InOOxlLm67CNH5O2J85QsPHEAzEU9KEqVfYG5ovFs5tx6n9pHekDVk3MpQULpqfNUYDR0KigPLg5g==" }, "@cspell/dict-html": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-1.1.9.tgz", - "integrity": "sha512-vvnYia0tyIS5Fdoz+gEQm77MGZZE66kOJjuNpIYyRHCXFAhWdYz3SmkRm6YKJSWSvuO+WBJYTKDvkOxSh3Fx/w==" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-3.3.2.tgz", + "integrity": "sha512-cM5pQSEiqjrdk6cRFLrlLdWNT/J8399f/A6DjwjfYhHrGy0e/Rsjv76HZT0GlE1OqMoq9eG9jdQsfoYYgWTIpQ==" }, "@cspell/dict-html-symbol-entities": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-1.0.23.tgz", - "integrity": "sha512-PV0UBgcBFbBLf/m1wfkVMM8w96kvfHoiCGLWO6BR3Q9v70IXoE4ae0+T+f0CkxcEkacMqEQk/I7vuE9MzrjaNw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-3.0.0.tgz", + "integrity": "sha512-04K7cPTcbYXmHICfiob4gZA1yaj4hpfM+Nl5WIJ1EAZsSGHdqmGEF28GuCjyQ8ZeKiJAsPt/vXuLBbjxkHqZyQ==" }, "@cspell/dict-java": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-1.0.23.tgz", - "integrity": "sha512-LcOg9srYLDoNGd8n3kbfDBlZD+LOC9IVcnFCdua1b/luCHNVmlgBx7e677qPu7olpMYOD5TQIVW2OmM1+/6MFA==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-3.0.7.tgz", + "integrity": "sha512-IL7ubsRvKX6dZSx++TplJCfhiS7kkEGpbTPG0gMEP50DTNAVM4icZS8zmer2UBCU5PTwF85abJjdX7mRADWKVg==" }, "@cspell/dict-latex": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-1.0.25.tgz", - "integrity": "sha512-cEgg91Migqcp1SdVV7dUeMxbPDhxdNo6Fgq2eygAXQjIOFK520FFvh/qxyBvW90qdZbIRoU2AJpchyHfGuwZFA==" + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-2.0.9.tgz", + "integrity": "sha512-d1kTK6dJb5z6UcfASQWjqQlsjZvnoVOvMWxYtLpGksYf6gM4IgqoPVNMLYYK6xBS4T/uAnLIj975A6YuAeyZpg==" }, "@cspell/dict-lorem-ipsum": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-1.0.22.tgz", - "integrity": "sha512-yqzspR+2ADeAGUxLTfZ4pXvPl7FmkENMRcGDECmddkOiuEwBCWMZdMP5fng9B0Q6j91hQ8w9CLvJKBz10TqNYg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-2.0.1.tgz", + "integrity": "sha512-s7Ft8UiloUJwgz4z8uLeFvCkeTcZ43HQl7mSAlZd76eW+keLSsdeGmLDx2zaciqo+MftPGyzygVCwaJjTGxiew==" }, "@cspell/dict-lua": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-1.0.16.tgz", - "integrity": "sha512-YiHDt8kmHJ8nSBy0tHzaxiuitYp+oJ66ffCYuFWTNB3//Y0SI4OGHU3omLsQVeXIfCeVrO4DrVvRDoCls9B5zQ==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-2.0.0.tgz", + "integrity": "sha512-7WUEBEspSKtsq104WdIys1+DLqAxpJPzw74Py1TuE3fI5GvlzeSZkRFP2ya54GB2lCO4C3mq4M8EnitpibVDfw==" }, "@cspell/dict-node": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-1.0.12.tgz", - "integrity": "sha512-RPNn/7CSkflAWk0sbSoOkg0ORrgBARUjOW3QjB11KwV1gSu8f5W/ij/S50uIXtlrfoBLqd4OyE04jyON+g/Xfg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-3.0.1.tgz", + "integrity": "sha512-sK2cpuV0EAc43Amd5xeQXkI9MeRTECMw+yjap06gKSModbgI7BqJUHeKZed+0Hii+LpaJ4TYpLGiRVsO+qSk0w==" }, "@cspell/dict-npm": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-1.0.16.tgz", - "integrity": "sha512-RwkuZGcYBxL3Yux3cSG/IOWGlQ1e9HLCpHeyMtTVGYKAIkFAVUnGrz20l16/Q7zUG7IEktBz5O42kAozrEnqMQ==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-3.1.3.tgz", + "integrity": "sha512-xnGp+TMpArdMLBUSG+ZrbEuhvY016rb76Yh35/OPDDEEz4ulENxLSZJxtN2/A0tZ9FJngDNSdFh7eJsOFmciZQ==" }, "@cspell/dict-php": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-1.0.25.tgz", - "integrity": "sha512-RoBIP5MRdByyPaXcznZMfOY1JdCMYPPLua5E9gkq0TJO7bX5mC9hyAKfYBSWVQunZydd82HZixjb5MPkDFU1uw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-2.0.0.tgz", + "integrity": "sha512-29WgU77eTO985LvMHwPi1pcpfopfCWfTdffDyqya0JIfOSaFUrlYKzGPkE4mRxcz2G3hXsaM0SRvBNdIRwEdUg==" }, "@cspell/dict-powershell": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-1.0.19.tgz", - "integrity": "sha512-zF/raM/lkhXeHf4I43OtK0gP9rBeEJFArscTVwLWOCIvNk21MJcNoTYoaGw+c056+Q+hJL0psGLO7QN+mxYH1A==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-2.0.0.tgz", + "integrity": "sha512-6uvEhLiGmG3u9TFkM1TYcky6aL9Yk7Sk3KJwoTYBaQJY2KqrprgyQtW6yxIw9oU52VRHlq3KKvSAA9Q26+SIkQ==" }, "@cspell/dict-public-licenses": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-1.0.3.tgz", - "integrity": "sha512-sXjxOHJ9Q4rZvE1UbwpwJQ8EXO3fadKBjJIWmz0z+dZAbvTrmz5Ln1Ef9ruJvLPfwAps8m3TCV6Diz60RAQqHg==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-1.0.6.tgz", + "integrity": "sha512-Z9IUFPkkOpOsEdgPUfQOJNQ+qU6+iBAZWS/CR5sUqTX+s5VkPNVwQyVC2kdmgmE2U5qwzAPewG6nVKr2MVogwg==" }, "@cspell/dict-python": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-2.0.4.tgz", - "integrity": "sha512-71X/VnyFPm6OPEkqmoVXCJz28RvBgktxy6zF6D5TLt97LbWg2JyRrWSXaf2+seVoLnJQ5CHACxcs+jyEyLhBJA==" + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-3.0.6.tgz", + "integrity": "sha512-tzxJ4sd9ZGhAUKg/WJJpQGDNtoHvM8Wn+iS2+PnQj2/LTHBW4mnaCogsGsBtYu8C4b2+BEQs+tc5808AeEfLug==" + }, + "@cspell/dict-r": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-1.0.3.tgz", + "integrity": "sha512-u2qeXd4cx/TvTVcmkvA+sK6f4K1uMAMO6QPMSr1pSvqGElPRP1mIBXmuiSuBzLO3LbsJuUEHw5Cp3/bxIB6rNA==" }, "@cspell/dict-ruby": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-1.0.14.tgz", - "integrity": "sha512-XHBGN4U1y9rjRuqrCA+3yIm2TCdhwwHXpOEcWkNeyXm8K03yPnIrKFS+kap8GTTrLpfNDuFsrmkkQTa7ssXLRA==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-2.0.2.tgz", + "integrity": "sha512-vVnUpSmGDbPjs7MHq741DsLHhQcoA4CnUCM9wsTorQ9AQRDAkDTbK/LcY8nM19MoXCb3eF8PFku5Jq+gqH0u7w==" }, "@cspell/dict-rust": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-1.0.23.tgz", - "integrity": "sha512-lR4boDzs79YD6+30mmiSGAMMdwh7HTBAPUFSB0obR3Kidibfc3GZ+MHWZXay5dxZ4nBKM06vyjtanF9VJ8q1Iw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-2.0.1.tgz", + "integrity": "sha512-ATDpIh0VWpQdUIZa8zqqJY4wQz3q00BTXlQCodeOmObYSb23+L6KWWzJ8mKLgpbc1lqTkogWrqxiCxlrCmqNmg==" }, "@cspell/dict-scala": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-1.0.21.tgz", - "integrity": "sha512-5V/R7PRbbminTpPS3ywgdAalI9BHzcEjEj9ug4kWYvBIGwSnS7T6QCFCiu+e9LvEGUqQC+NHgLY4zs1NaBj2vA==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-2.0.0.tgz", + "integrity": "sha512-MUwA2YKpqaQOSR4V1/CVGRNk8Ii5kf6I8Ch+4/BhRZRQXuwWbi21rDRYWPqdQWps7VNzAbbMA+PQDWsD5YY38g==" }, "@cspell/dict-software-terms": { - "version": "1.0.48", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-1.0.48.tgz", - "integrity": "sha512-pfF3Ys2gRffu5ElqkH7FQMDMi/iZMyOzpGMb3FSH0PJ2AnRQ5rRNWght1h2L36YxvXl0mWVaFrrfwiOyRIc8ZQ==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-2.3.0.tgz", + "integrity": "sha512-rl+quUw68IxjWgeX/QDMgQsImZ1DaKzFyYMSGrCNcNPp4b4SMLwHCKoJ97/uOnUnw0jaBxueXoqp2iyN/QiOVw==" + }, + "@cspell/dict-sql": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-1.0.4.tgz", + "integrity": "sha512-+9nMcwsCzdYH0tyv2LeuVvQ+DdecS2C1N+hw6sl0FTHWI5GwULHAGW840RBwcKw0s+dl7sc0WpZhS1EW7b0pXg==" + }, + "@cspell/dict-swift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-1.0.3.tgz", + "integrity": "sha512-yOBLSaRD0AnkkkndJ8PuB82Evp6lA2xItf2AWsnPfCCgxp5Ojk6uUBC/WQBSkzkCAOGbXyHsu9D97tsOx2c6cw==" }, "@cspell/dict-typescript": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-1.0.19.tgz", - "integrity": "sha512-qmJApzoVskDeJnLZzZMaafEDGbEg5Elt4c3Mpg49SWzIHm1N4VXCp5CcFfHsOinJ30dGrs3ARAJGJZIw56kK6A==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-2.0.2.tgz", + "integrity": "sha512-OIoSJsCw9WHX4eDikoF5/0QbptMPZjElOcMYdYCyV03nqV5n4ot72ysTexW95yW4+fQU6uDPNQvnrUnhXXEkTA==" + }, + "@cspell/dict-vue": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-2.0.2.tgz", + "integrity": "sha512-/MB0RS0Gn01s4pgmjy0FvsLfr3RRMrRphEuvTRserNcM8XVtoIVAtrjig/Gg0DPwDrN8Clm0L1j7iQay6S8D0g==" }, "@types/parse-json": { "version": "4.0.0", @@ -1545,12 +1815,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "braces": { @@ -1598,17 +1867,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==" }, "comment-json": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.1.1.tgz", - "integrity": "sha512-v8gmtPvxhBlhdRBLwdHSjGy9BgA23t9H1FctdQKyUrErPjSrJcdDMqBq9B4Irtm7w3TNYLQJNH6ARKnpyag1sA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.3.tgz", + "integrity": "sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==", "requires": { "array-timsort": "^1.0.3", - "core-util-is": "^1.0.2", + "core-util-is": "^1.0.3", "esprima": "^4.0.1", "has-own-prop": "^2.0.0", "repeat-string": "^1.6.1" @@ -1617,7 +1886,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "configstore": { "version": "5.0.1", @@ -1655,78 +1924,111 @@ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" }, "cspell": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.3.tgz", - "integrity": "sha512-lPyWZHfdQh+xjUZDAQC0gnpjglMu2AEfxBWlziTm3XuYuPGTvNJQSUrkMcH180tA3fkj8q2XFwfxHkXXAxm68w==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-6.12.0.tgz", + "integrity": "sha512-ny4xVEPYFP2jVf5w71Mnk4HKj6RbPH+CMSzUrOMbYVVNnQUj3GLfzy5DrSFLG0zGa353ZRC4/s9MsEvnAL8mkA==", "requires": { + "@cspell/cspell-pipe": "^6.12.0", "chalk": "^4.1.2", - "commander": "^8.2.0", - "comment-json": "^4.1.1", - "cspell-gitignore": "^5.12.3", - "cspell-glob": "^5.12.3", - "cspell-lib": "^5.12.3", + "commander": "^9.4.0", + "cspell-gitignore": "^6.12.0", + "cspell-glob": "^6.12.0", + "cspell-lib": "^6.12.0", "fast-json-stable-stringify": "^2.1.0", "file-entry-cache": "^6.0.1", - "fs-extra": "^10.0.0", + "fs-extra": "^10.1.0", "get-stdin": "^8.0.0", - "glob": "^7.2.0", + "glob": "^8.0.3", "imurmurhash": "^0.1.4", + "semver": "^7.3.7", "strip-ansi": "^6.0.1", - "vscode-uri": "^3.0.2" + "vscode-uri": "^3.0.6" + } + }, + "cspell-dictionary": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-6.12.0.tgz", + "integrity": "sha512-I2cXSdXndt9H7yXmJzLTjgui/SAPGghXwxFeibTbvF68gyQYD5fUXvOygEIPrOEySKlAIb+aouV77SgoURxMHw==", + "requires": { + "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-types": "^6.12.0", + "cspell-trie-lib": "^6.12.0", + "fast-equals": "^4.0.3", + "gensequence": "^4.0.2" } }, "cspell-gitignore": { - "version": "5.12.6", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.6.tgz", - "integrity": "sha512-4C6kNc6y9avFvd0/1LiSi139TZwWc4o1vxWBlSEACjeJ7fMKiunIRCrDPb8QPtzDy+Ot+CGNk+ONi3nBqMX8cw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-6.12.0.tgz", + "integrity": "sha512-gtsN2AAvqdE8CHVzpxsQcd/Wn5GAMTjzHpDXX71g/k8IJn743poGU06O0O1WSVAgK0fWTRsfg+V5OegA1TAo7A==", "requires": { - "cspell-glob": "^5.12.6", + "cspell-glob": "^6.12.0", "find-up": "^5.0.0" } }, "cspell-glob": { - "version": "5.12.6", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-5.12.6.tgz", - "integrity": "sha512-trAnJLEsqpS8SbD2ZTBjLlLuauneZwC4BFiizUeb80EoCgexwMS1F2pzHngDQ+u4JmMcIuBsNgTWiYwuyu+/Wg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-6.12.0.tgz", + "integrity": "sha512-Q0rMGTxDyFFPm1LmHYM0ziuxQt2aXgr8Oi1glA2s0dBs0hg1DexlAEoLwLiMDUwSTvibEKIidPzlrmZ1AUDWEg==", + "requires": { + "micromatch": "^4.0.5" + } + }, + "cspell-grammar": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-6.12.0.tgz", + "integrity": "sha512-WXcDiWJ2pTW0jHY0Bf0DW5s8A9S0a+2tsVZsNxE/0CR5P/8yDSnznE+59uok/JN+GXOKQ6VIaqAZA3/XjDZuuA==", "requires": { - "micromatch": "^4.0.4" + "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-types": "^6.12.0" } }, "cspell-io": { - "version": "5.12.6", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-5.12.6.tgz", - "integrity": "sha512-pTcxw5+/GKD5qIxTcQzWq6pTfWmSVAZVD11kkQ9gFYwX+JYdYmm3Af2x8u5oV46IKL0eAuLp7F1kfan1IsRnEA==" + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-6.12.0.tgz", + "integrity": "sha512-1faxDj2OMgq61w7GaiXZD7ytks6PksJlG484LMl2USv58jDky4i2lujJs1C/+aP97Box9EcdwzydHX9GpnqqCw==", + "requires": { + "@cspell/cspell-service-bus": "^6.12.0", + "node-fetch": "^2.6.7" + } }, "cspell-lib": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.3.tgz", - "integrity": "sha512-wiS3X3inzkwr2d6UojVLjzGFxwhnE+HoQYg7cDyC2qqK1Q++36c5bHJGE8564lsVedeAMVbHh81bP7hibg/yUw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-6.12.0.tgz", + "integrity": "sha512-IKd2MzH/zoiXohc26Lqb1b8i+41Y2xGreyAe9ihv/7Z2dscGGVy7F/2taZvZK9kJIhaz33Yatxfx3htT6w0hqg==", "requires": { - "@cspell/cspell-bundled-dicts": "^5.12.3", - "@cspell/cspell-types": "^5.12.3", - "clear-module": "^4.1.1", - "comment-json": "^4.1.1", + "@cspell/cspell-bundled-dicts": "^6.12.0", + "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-types": "^6.12.0", + "clear-module": "^4.1.2", + "comment-json": "^4.2.3", "configstore": "^5.0.1", "cosmiconfig": "^7.0.1", - "cspell-glob": "^5.12.3", - "cspell-io": "^5.12.3", - "cspell-trie-lib": "^5.12.3", + "cspell-dictionary": "^6.12.0", + "cspell-glob": "^6.12.0", + "cspell-grammar": "^6.12.0", + "cspell-io": "^6.12.0", + "cspell-trie-lib": "^6.12.0", + "fast-equals": "^4.0.3", "find-up": "^5.0.0", - "fs-extra": "^10.0.0", - "gensequence": "^3.1.1", + "fs-extra": "^10.1.0", + "gensequence": "^4.0.2", "import-fresh": "^3.3.0", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0", - "vscode-uri": "^3.0.2" + "vscode-languageserver-textdocument": "^1.0.7", + "vscode-uri": "^3.0.6" } }, "cspell-trie-lib": { - "version": "5.12.6", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.6.tgz", - "integrity": "sha512-ahT/lzhA7WiXzkFadOaXngPfxA74n4YLXXsZi+lL8/GgdezgbcsL4OoKuiKv24pMSLQBuJ6MOSWSr6rlNrImkw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-6.12.0.tgz", + "integrity": "sha512-SJOdb51Wy3ewaKfttZwc9NYOIXaKlhyr+ykYKBExj3qMfV1J4d4iDLE95FriaRcqnq6X/qEM9jUvZHlvadDk3A==", "requires": { - "fs-extra": "^10.0.0", - "gensequence": "^3.1.1" + "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-types": "^6.12.0", + "fs-extra": "^10.1.0", + "gensequence": "^4.0.2" } }, "dot-prop": { @@ -1748,13 +2050,18 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, + "fast-equals": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz", + "integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==" + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1795,14 +2102,14 @@ } }, "flatted": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", - "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==" + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -1812,12 +2119,12 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "gensequence": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-3.1.1.tgz", - "integrity": "sha512-ys3h0hiteRwmY6BsvSttPmkhC0vEQHPJduANBRtH/dlDPZ0UBIb/dXy80IcckXyuQ6LKg+PloRqvGER9IS7F7g==" + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-4.0.2.tgz", + "integrity": "sha512-mQiFskYFPFDSUpBJ/n3ebAV2Ufu6DZGvUPXzyWYzFfJr6/DyOOZVnjx6VTWE4y0RLvYWnc5tZq5sCjzEWhRjqQ==" }, "get-stdin": { "version": "8.0.0", @@ -1825,30 +2132,29 @@ "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==" }, "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" } }, "global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", "requires": { "ini": "^1.3.4" } }, "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "has-flag": { "version": "4.0.0", @@ -1887,12 +2193,12 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1911,7 +2217,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "is-number": { "version": "7.0.0", @@ -1926,7 +2232,7 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, "js-tokens": { "version": "4.0.0", @@ -1948,9 +2254,9 @@ } }, "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "locate-path": { "version": "6.0.0", @@ -1960,35 +2266,58 @@ "p-locate": "^5.0.0" } }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "requires": { "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } } }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" + } + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } @@ -2036,7 +2365,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-type": { "version": "4.0.0", @@ -2044,14 +2373,14 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" }, "resolve-from": { "version": "5.0.0", @@ -2072,17 +2401,52 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "requires": { "glob": "^7.1.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } }, "signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "strip-ansi": { "version": "6.0.1", @@ -2108,6 +2472,11 @@ "is-number": "^7.0.0" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -2129,15 +2498,34 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" }, + "vscode-languageserver-textdocument": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz", + "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg==" + }, "vscode-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.2.tgz", - "integrity": "sha512-jkjy6pjU1fxUvI51P+gCsxg1u2n8LSt0W6KrCNQceaziKzff74GoWmjVG46KieVzybO1sttPQmYfrwSHey7GUA==" + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz", + "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "write-file-atomic": { "version": "3.0.3", @@ -2155,6 +2543,11 @@ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", diff --git a/eng/common/spelling/package.json b/eng/common/spelling/package.json index f6578fc822..533d8c8093 100644 --- a/eng/common/spelling/package.json +++ b/eng/common/spelling/package.json @@ -2,9 +2,9 @@ "name": "cspell-version-pin", "version": "0.1.1", "dependencies": { - "@cspell/cspell-bundled-dicts": "^5.12.3", - "@cspell/cspell-types": "^5.12.3", - "cspell": "^5.12.3", - "cspell-lib": "^5.12.3" + "@cspell/cspell-bundled-dicts": "^6.12.0", + "@cspell/cspell-types": "^6.12.0", + "cspell": "^6.12.0", + "cspell-lib": "^6.12.0" } } From 17a0ad54199342abbf0778b86032f23c84b73931 Mon Sep 17 00:00:00 2001 From: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> Date: Sun, 23 Oct 2022 21:03:56 -0700 Subject: [PATCH 08/21] Sync eng/common directory with azure-sdk-tools for PR 4480 (#4046) * Add extra parameters for .net readme path * Use another way for default value * Remove custom source Co-authored-by: sima-zhu --- eng/common/scripts/Update-DocsMsToc.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/eng/common/scripts/Update-DocsMsToc.ps1 b/eng/common/scripts/Update-DocsMsToc.ps1 index 5287d31575..cacc6dbf93 100644 --- a/eng/common/scripts/Update-DocsMsToc.ps1 +++ b/eng/common/scripts/Update-DocsMsToc.ps1 @@ -29,6 +29,8 @@ depending on the requirements for the domain .PARAMETER OutputLocation Output location for unified reference yml file +.PARAMETER ReadmeFolderRoot +The readme folder root path, use default value here for backward compability. E.g. docs-ref-services in Java, JS, Python, api/overview/azure #> param( @@ -36,7 +38,10 @@ param( [string] $DocRepoLocation, [Parameter(Mandatory = $true)] - [string] $OutputLocation + [string] $OutputLocation, + + [Parameter(Mandatory = $false)] + [string] $ReadmeFolderRoot = 'docs-ref-services' ) . $PSScriptRoot/common.ps1 . $PSScriptRoot/Helpers/PSModule-Helpers.ps1 @@ -208,7 +213,7 @@ foreach ($service in $serviceNameList) { $serviceReadmeBaseName = $service.ToLower().Replace(' ', '-').Replace('/', '-') $serviceTocEntry = [PSCustomObject]@{ name = $service; - href = "~/docs-ref-services/{moniker}/$serviceReadmeBaseName.md" + href = "~/$ReadmeFolderRoot/{moniker}/$serviceReadmeBaseName.md" landingPageType = 'Service' items = @($packageItems) } From 6c225cd6c9075e0cba59f01076a57f02340ec14c Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Mon, 24 Oct 2022 11:43:42 -0700 Subject: [PATCH 09/21] Converted WinHTTP to Async. (#4015) * Async WinHTTP * Added cancellation test; added support for request cancellation. Co-authored-by: Anton Kolesnyk <41349689+antkmsft@users.noreply.github.com> Co-authored-by: Ahson Khan Co-authored-by: Rick Winter --- .vscode/cspell.json | 1 + cmake-modules/AddGoogleTest.cmake | 3 +- .../test/ut/azure_core_test.cpp | 15 + sdk/core/azure-core/CMakeLists.txt | 5 +- .../azure/core/http/win_http_transport.hpp | 117 +-- .../internal/diagnostics/global_exception.hpp | 39 + sdk/core/azure-core/src/http/curl/curl.cpp | 2 +- sdk/core/azure-core/src/http/retry_policy.cpp | 1 + .../azure-core/src/http/transport_policy.cpp | 1 + .../src/http/winhttp/win_http_request.hpp | 231 +++++ .../src/http/winhttp/win_http_transport.cpp | 819 ++++++++++++------ .../azure-core/test/ut/azure_core_test.cpp | 22 +- .../test/ut/azure_libcurl_core_main_test.cpp | 35 +- .../test/ut/curl_connection_pool_test.cpp | 4 +- .../test/ut/transport_adapter_base_test.cpp | 14 +- .../test/ut/transport_adapter_base_test.hpp | 37 +- .../test/ut/transport_policy_options.cpp | 11 +- sdk/core/perf/src/program.cpp | 16 +- 18 files changed, 939 insertions(+), 434 deletions(-) create mode 100644 sdk/core/azure-core/inc/azure/core/internal/diagnostics/global_exception.hpp create mode 100644 sdk/core/azure-core/src/http/winhttp/win_http_request.hpp diff --git a/.vscode/cspell.json b/.vscode/cspell.json index cfbe17a05f..d0e48f281c 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -73,6 +73,7 @@ "HKEY", "HRESULT", "IMDS", + "immutability", "Intel", "issecret", "itfactor", diff --git a/cmake-modules/AddGoogleTest.cmake b/cmake-modules/AddGoogleTest.cmake index 508a867a1f..d273d565b0 100644 --- a/cmake-modules/AddGoogleTest.cmake +++ b/cmake-modules/AddGoogleTest.cmake @@ -78,7 +78,8 @@ macro(add_gtest TESTNAME) else() gtest_discover_tests(${TESTNAME} TEST_PREFIX "${TESTNAME}." - PROPERTIES FOLDER "Tests") + PROPERTIES FOLDER "Tests" + DISCOVERY_TIMEOUT 600) endif() else() add_test(${TESTNAME} ${TESTNAME}) diff --git a/sdk/core/azure-core-tracing-opentelemetry/test/ut/azure_core_test.cpp b/sdk/core/azure-core-tracing-opentelemetry/test/ut/azure_core_test.cpp index b847ddb3c1..959703daba 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/test/ut/azure_core_test.cpp +++ b/sdk/core/azure-core-tracing-opentelemetry/test/ut/azure_core_test.cpp @@ -1,6 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT +#include "azure/core/internal/diagnostics/global_exception.hpp" +#include "azure/core/platform.hpp" + +#include #include int main(int argc, char** argv) @@ -10,6 +14,17 @@ int main(int argc, char** argv) // End users need to decide if SIGPIPE should be ignored or not. signal(SIGPIPE, SIG_IGN); #endif + // Declare a signal handler to report unhandled exceptions on Windows - this is not needed for + // other +// OS's as they will print the exception to stderr in their terminate() function. +#if defined(AZ_PLATFORM_WINDOWS) + // Ensure that all calls to abort() no longer pop up a modal dialog on Windows. +#if defined(_DEBUG) && defined(_MSC_VER) + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); +#endif + + signal(SIGABRT, Azure::Core::Diagnostics::_internal::GlobalExceptionHandler::HandleSigAbort); +#endif // AZ_PLATFORM_WINDOWS testing::InitGoogleTest(&argc, argv); auto r = RUN_ALL_TESTS(); diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt index 1cb7ebae1b..04eea7a218 100644 --- a/sdk/core/azure-core/CMakeLists.txt +++ b/sdk/core/azure-core/CMakeLists.txt @@ -54,10 +54,11 @@ endif() if(BUILD_TRANSPORT_WINHTTP) SET(WIN_TRANSPORT_ADAPTER_SRC src/http/winhttp/win_http_transport.cpp + src/http/winhttp/win_http_request.hpp ) - SET(WIN_TRANSPORT_ADAPTER_INC + SET(WIN_TRANSPORT_ADAPTER_INC inc/azure/core/http/win_http_transport.hpp - ) + ) endif() set( diff --git a/sdk/core/azure-core/inc/azure/core/http/win_http_transport.hpp b/sdk/core/azure-core/inc/azure/core/http/win_http_transport.hpp index d28e551bef..9ce13dd502 100644 --- a/sdk/core/azure-core/inc/azure/core/http/win_http_transport.hpp +++ b/sdk/core/azure-core/inc/azure/core/http/win_http_transport.hpp @@ -5,7 +5,6 @@ * @file * @brief #Azure::Core::Http::HttpTransport implementation via WinHTTP. */ -// cspell:words HCERTIFICATECHAIN PCCERT CCERT HCERTCHAINENGINE HCERTSTORE #pragma once @@ -14,8 +13,7 @@ #include "azure/core/http/policies/policy.hpp" #include "azure/core/http/transport.hpp" #include "azure/core/internal/unique_handle.hpp" - -#include +#include "azure/core/platform.hpp" #if defined(AZ_PLATFORM_WINDOWS) #if !defined(WIN32_LEAN_AND_MEAN) @@ -57,53 +55,8 @@ namespace Azure { namespace Core { constexpr static size_t DefaultUploadChunkSize = 1024 * 64; constexpr static size_t MaximumUploadChunkSize = 1024 * 1024; - class WinHttpStream final : public Azure::Core::IO::BodyStream { - private: - Azure::Core::_internal::UniqueHandle m_requestHandle; - bool m_isEOF; - - /** - * @brief This is a copy of the value of an HTTP response header `content-length`. The value - * is received as string and parsed to size_t. This field avoids parsing the string header - * every time from HTTP RawResponse. - * - * @remark This value is also used to avoid trying to read more data from network than what - * we are expecting to. - * - * @remark A value of -1 means the transfer encoding was chunked. - * - */ - int64_t m_contentLength; - - int64_t m_streamTotalRead; - - /** - * @brief Implement #Azure::Core::IO::BodyStream::OnRead(). Calling this function pulls data - * from the wire. - * - * @param context A context to control the request lifetime. - * @param buffer Buffer where data from wire is written to. - * @param count The number of bytes to read from the network. - * @return The actual number of bytes read from the network. - */ - size_t OnRead(uint8_t* buffer, size_t count, Azure::Core::Context const& context) override; - - public: - WinHttpStream( - Azure::Core::_internal::UniqueHandle& requestHandle, - int64_t contentLength) - : m_requestHandle(std::move(requestHandle)), m_contentLength(contentLength), - m_isEOF(false), m_streamTotalRead(0) - { - } - - /** - * @brief Implement #Azure::Core::IO::BodyStream length. - * - * @return The size of the payload. - */ - int64_t Length() const override { return this->m_contentLength; } - }; + // Forward declaration for WinHttpRequest. + class WinHttpRequest; } // namespace _detail /** @@ -173,70 +126,22 @@ namespace Azure { namespace Core { class WinHttpTransport : public HttpTransport { private: WinHttpTransportOptions m_options; - - // This should remain immutable and not be modified after calling the ctor, to avoid threading - // issues. - Azure::Core::_internal::UniqueHandle m_sessionHandle; - bool m_requestHandleClosed{false}; + // m_sessionhandle is const to ensure immutability. + const Azure::Core::_internal::UniqueHandle m_sessionHandle; Azure::Core::_internal::UniqueHandle CreateSessionHandle(); Azure::Core::_internal::UniqueHandle CreateConnectionHandle( Azure::Core::Url const& url, Azure::Core::Context const& context); - Azure::Core::_internal::UniqueHandle CreateRequestHandle( + std::unique_ptr<_detail::WinHttpRequest> CreateRequestHandle( Azure::Core::_internal::UniqueHandle const& connectionHandle, Azure::Core::Url const& url, Azure::Core::Http::HttpMethod const& method); - void Upload( - Azure::Core::_internal::UniqueHandle const& requestHandle, - Azure::Core::Http::Request& request, - Azure::Core::Context const& context); - void SendRequest( - Azure::Core::_internal::UniqueHandle const& requestHandle, - Azure::Core::Http::Request& request, - Azure::Core::Context const& context); - void ReceiveResponse( - Azure::Core::_internal::UniqueHandle const& requestHandle, - Azure::Core::Context const& context); - int64_t GetContentLength( - Azure::Core::_internal::UniqueHandle const& requestHandle, - HttpMethod requestMethod, - HttpStatusCode responseStatusCode); - std::unique_ptr SendRequestAndGetResponse( - Azure::Core::_internal::UniqueHandle& requestHandle, - HttpMethod requestMethod); - - /* - * Callback from WinHTTP called after the TLS certificates are received when the caller sets - * expected TLS root certificates. - */ - static void CALLBACK StatusCallback( - HINTERNET hInternet, - DWORD_PTR dwContext, - DWORD dwInternetStatus, - LPVOID lpvStatusInformation, - DWORD dwStatusInformationLength) noexcept; - /* - * Callback from WinHTTP called after the TLS certificates are received when the caller sets - * expected TLS root certificates. - */ - void OnHttpStatusOperation(HINTERNET hInternet, DWORD dwInternetStatus); - /* - * Adds the specified trusted certificates to the specified certificate store. - */ - bool AddCertificatesToStore( - std::vector const& trustedCertificates, - HCERTSTORE const hCertStore); - /* - * Verifies that the certificate context is in the trustedCertificates set of certificates. - */ - bool VerifyCertificatesInChain( - std::vector const& trustedCertificates, - PCCERT_CONTEXT serverCertificate); // Callback to allow a derived transport to extract the request handle. Used for WebSocket // transports. - virtual void OnUpgradedConnection(Azure::Core::_internal::UniqueHandle const&){}; + virtual void OnUpgradedConnection(std::unique_ptr<_detail::WinHttpRequest> const&){}; + /** * @brief Throw an exception based on the Win32 Error code * @@ -266,8 +171,8 @@ namespace Azure { namespace Core { WinHttpTransport(Azure::Core::Http::Policies::TransportOptions const& options); /** - * @brief Implements the HTTP transport interface to send an HTTP Request and produce an HTTP - * RawResponse. + * @brief Implements the HTTP transport interface to send an HTTP Request and produce an + * HTTP RawResponse. * * @param context A context to control the request lifetime. * @param request an HTTP request to be send. @@ -279,7 +184,7 @@ namespace Azure { namespace Core { // [Core Guidelines C.35: "A base class destructor should be either public // and virtual or protected and // non-virtual"](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c35-a-base-class-destructor-should-be-either-public-and-virtual-or-protected-and-non-virtual) - virtual ~WinHttpTransport() = default; + virtual ~WinHttpTransport(); }; } // namespace Http diff --git a/sdk/core/azure-core/inc/azure/core/internal/diagnostics/global_exception.hpp b/sdk/core/azure-core/inc/azure/core/internal/diagnostics/global_exception.hpp new file mode 100644 index 0000000000..d051efb97a --- /dev/null +++ b/sdk/core/azure-core/inc/azure/core/internal/diagnostics/global_exception.hpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#pragma once +#include +#include + +namespace Azure { namespace Core { namespace Diagnostics { namespace _internal { + /** + * @brief Global Exception handler used for test collateral. This is not intended to be used by + * any non-test code. + * + * The GlobalExceptionHandler class is used to catch any unhandled exceptions and report them as a + * part of test collateral, it is intended to be called as a SIGABRT handler set by: + * + * ``` + * signal(SIGABRT, Azure::Core::Diagnostics::_internal::GlobalExceptionHandler); + * ``` + * + */ + struct GlobalExceptionHandler + { + static void HandleSigAbort(int) + { + // Rethrow any exceptions on the current stack - this will cause any pending exceptions to + // be thrown so we can catch them and report them to the caller. This is needed because the + // terminate() function on Windows calls abort() which normally pops up a modal dialog box + // after which it terminates the application without reporting the exception. + try + { + throw; + } + catch (std::exception const& ex) + { + std::cerr << "SIGABRT raised, exception: " << ex.what() << std::endl; + } + } + }; +}}}} // namespace Azure::Core::Diagnostics::_internal diff --git a/sdk/core/azure-core/src/http/curl/curl.cpp b/sdk/core/azure-core/src/http/curl/curl.cpp index c534b10bed..fc70778a9d 100644 --- a/sdk/core/azure-core/src/http/curl/curl.cpp +++ b/sdk/core/azure-core/src/http/curl/curl.cpp @@ -134,7 +134,7 @@ int pollSocketUntilEventOrTimeout( auto deadline = now + std::chrono::milliseconds(timeout); while (now < deadline) { - // check cancelation + // Before doing any work, check to make sure that the context hasn't already been cancelled. context.ThrowIfCancelled(); int pollTimeoutMs = static_cast( std::min( diff --git a/sdk/core/azure-core/src/http/retry_policy.cpp b/sdk/core/azure-core/src/http/retry_policy.cpp index 84b037e66c..d2066b6ec3 100644 --- a/sdk/core/azure-core/src/http/retry_policy.cpp +++ b/sdk/core/azure-core/src/http/retry_policy.cpp @@ -176,6 +176,7 @@ std::unique_ptr RetryPolicy::Send( // we proceed immediately if it is 0. if (retryAfter.count() > 0) { + // Before sleeping, check to make sure that the context hasn't already been cancelled. context.ThrowIfCancelled(); std::this_thread::sleep_for(retryAfter); } diff --git a/sdk/core/azure-core/src/http/transport_policy.cpp b/sdk/core/azure-core/src/http/transport_policy.cpp index ec90e0253c..119dc31683 100644 --- a/sdk/core/azure-core/src/http/transport_policy.cpp +++ b/sdk/core/azure-core/src/http/transport_policy.cpp @@ -97,6 +97,7 @@ std::unique_ptr TransportPolicy::Send( NextHttpPolicy, Context const& context) const { + // Before doing any work, check to make sure that the context hasn't already been cancelled. context.ThrowIfCancelled(); /* diff --git a/sdk/core/azure-core/src/http/winhttp/win_http_request.hpp b/sdk/core/azure-core/src/http/winhttp/win_http_request.hpp new file mode 100644 index 0000000000..41c3b694ec --- /dev/null +++ b/sdk/core/azure-core/src/http/winhttp/win_http_request.hpp @@ -0,0 +1,231 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +// cspell:words PCCERT HCERTSTORE + +/** + * @file + * @brief #Azure::Core::Http::HttpTransport request support classes. + */ + +#pragma once + +#include "azure/core/http/win_http_transport.hpp" +#include "azure/core/url.hpp" +#include +#include +#include +#include +#include + +namespace Azure { namespace Core { namespace Http { namespace _detail { + + class WinHttpRequest; + /** + * @brief An outstanding WinHTTP action. This object is used to process asynchronous WinHTTP + * actions. + * + * The WinHttpRequest object has a WinHttpAction associated with it to convert asynchronous + * WinHTTP operations to synchronous operations. + * + */ + class WinHttpAction final { + + // Containing HTTP request, used during the status operation callback. + WinHttpRequest* const m_httpRequest{}; + wil::unique_event m_actionCompleteEvent; + // Mutex protecting all mutable members of the class. + std::mutex m_actionCompleteMutex; + DWORD m_expectedStatus{}; + DWORD m_stowedError{}; + DWORD_PTR m_stowedErrorInformation{}; + DWORD m_bytesAvailable{}; + + /* + * Callback from WinHTTP called after the TLS certificates are received when the caller sets + * expected TLS root certificates. + */ + static void CALLBACK StatusCallback( + HINTERNET hInternet, + DWORD_PTR dwContext, + DWORD dwInternetStatus, + LPVOID lpvStatusInformation, + DWORD dwStatusInformationLength) noexcept; + + /* + * Callback from WinHTTP called after the TLS certificates are received when the caller sets + * expected TLS root certificates. + */ + void OnHttpStatusOperation( + HINTERNET hInternet, + DWORD internetStatus, + LPVOID statusInformation, + DWORD statusInformationLength); + + public: + /** + * @brief Create a new WinHttpAction object associated with a specific WinHttpRequest. + * + * @param request Http Request associated with the action. + */ + WinHttpAction(WinHttpRequest* request) + // Create a non-inheritable anonymous manual reset event intialized as unset. + : m_httpRequest(request), m_actionCompleteEvent(CreateEvent(nullptr, TRUE, FALSE, nullptr)) + { + if (!m_actionCompleteEvent) + { + throw std::runtime_error("Error creating Action Complete Event."); + } + } + + /** + * Register the WinHTTP Status callback used by the action. + * + * @param internetHandle HINTERNET to register the callback. + * @returns The status of the operation. + */ + bool RegisterWinHttpStatusCallback( + Azure::Core::_internal::UniqueHandle const& internetHandle); + + /** + * @brief WaitForAction - Waits for an action to complete. + * + * @remarks The WaitForAction method waits until an action initiated by the `callback` function + * has completed. Every pollDuration milliseconds, it checks to see if the context specified for + * the request has been cancelled (or times out). + * + * @param initiateAction - Function called to initiate an action. Always called in the waiting + * thread. + * @param expectedCallbackStatus - Wait until the expectedStatus event occurs. + * @param pollDuration - The time to wait for a ping to complete. Defaults to 800ms because it + * seems like a reasonable minimum responsiveness value (also this is the default retry + * policy delay). + * @param context - Context for the operation. + * + * @returns true if the action completed normally, false if there was an error. + + * @remarks If there is an error, the caller can determine the error code by calling + * GetStowedError() and GetStowedErrorInformation() + */ + bool WaitForAction( + std::function initiateAction, + DWORD expectedCallbackStatus, + Azure::Core::Context const& context, + Azure::DateTime::duration const& pollDuration = std::chrono::milliseconds(800)); + + /** + * @brief Notify a caller that the action has completed successfully. + */ + void CompleteAction(); + + /** + * @brief Notify a caller that the action has completed successfully and reflect the bytes + * available + */ + void CompleteActionWithData(DWORD bytesAvailable); + + /** + * @brief Notify a caller that the action has completed with an error and save the error code + * and information. + */ + void CompleteActionWithError(DWORD_PTR stowedErrorInformation, DWORD stowedError); + DWORD GetStowedError(); + DWORD_PTR GetStowedErrorInformation(); + DWORD GetBytesAvailable(); + }; + + /** + * @brief A WinHttpRequest object encapsulates an HTTP operation. + */ + class WinHttpRequest final { + bool m_requestHandleClosed{false}; + Azure::Core::_internal::UniqueHandle m_requestHandle; + std::unique_ptr m_httpAction; + std::vector m_expectedTlsRootCertificates; + + /* + * Adds the specified trusted certificates to the specified certificate store. + */ + bool AddCertificatesToStore( + std::vector const& trustedCertificates, + HCERTSTORE const hCertStore) const; + /* + * Verifies that the certificate context is in the trustedCertificates set of certificates. + */ + bool VerifyCertificatesInChain( + std::vector const& trustedCertificates, + PCCERT_CONTEXT serverCertificate) const; + /** + * @brief Throw an exception based on the Win32 Error code + * + * @param exceptionMessage Message describing error. + * @param error Win32 Error code. + */ + void GetErrorAndThrow(const std::string& exceptionMessage, DWORD error = GetLastError()) const; + + public: + WinHttpRequest( + Azure::Core::_internal::UniqueHandle const& connectionHandle, + Azure::Core::Url const& url, + Azure::Core::Http::HttpMethod const& method, + WinHttpTransportOptions const& options); + + ~WinHttpRequest(); + + void Upload(Azure::Core::Http::Request& request, Azure::Core::Context const& context); + void SendRequest(Azure::Core::Http::Request& request, Azure::Core::Context const& context); + void ReceiveResponse(Azure::Core::Context const& context); + int64_t GetContentLength(HttpMethod requestMethod, HttpStatusCode responseStatusCode); + std::unique_ptr SendRequestAndGetResponse(HttpMethod requestMethod); + size_t ReadData(uint8_t* buffer, size_t bufferSize, Azure::Core::Context const& context); + void EnableWebSocketsSupport(); + void HandleExpectedTlsRootCertificates(HINTERNET hInternet); + }; + + class WinHttpStream final : public Azure::Core::IO::BodyStream { + private: + std::unique_ptr<_detail::WinHttpRequest> m_requestHandle; + bool m_isEOF; + + /** + * @brief This is a copy of the value of an HTTP response header `content-length`. The value + * is received as string and parsed to size_t. This field avoids parsing the string header + * every time from HTTP RawResponse. + * + * @remark This value is also used to avoid trying to read more data from network than what + * we are expecting to. + * + * @remark A value of -1 means the transfer encoding was chunked. + * + */ + int64_t m_contentLength; + + int64_t m_streamTotalRead; + + /** + * @brief Implement #Azure::Core::IO::BodyStream::OnRead(). Calling this function pulls data + * from the wire. + * + * @param context A context to control the request lifetime. + * @param buffer Buffer where data from wire is written to. + * @param count The number of bytes to read from the network. + * @return The actual number of bytes read from the network. + */ + size_t OnRead(uint8_t* buffer, size_t count, Azure::Core::Context const& context) override; + + public: + WinHttpStream(std::unique_ptr<_detail::WinHttpRequest>& requestHandle, int64_t contentLength) + : m_requestHandle(std::move(requestHandle)), m_contentLength(contentLength), m_isEOF(false), + m_streamTotalRead(0) + { + } + + /** + * @brief Implement #Azure::Core::IO::BodyStream length. + * + * @return The size of the payload. + */ + int64_t Length() const override { return this->m_contentLength; } + }; + +}}}} // namespace Azure::Core::Http::_detail diff --git a/sdk/core/azure-core/src/http/winhttp/win_http_transport.cpp b/sdk/core/azure-core/src/http/winhttp/win_http_transport.cpp index 2d51637cf5..79a968e6b3 100644 --- a/sdk/core/azure-core/src/http/winhttp/win_http_transport.cpp +++ b/sdk/core/azure-core/src/http/winhttp/win_http_transport.cpp @@ -12,7 +12,9 @@ #if defined(BUILD_TRANSPORT_WINHTTP_ADAPTER) #include "azure/core/http/win_http_transport.hpp" +#include "win_http_request.hpp" #endif + #include #include #include @@ -212,9 +214,9 @@ std::string GetHeadersAsString(Azure::Core::Http::Request const& request) } // namespace // For each certificate specified in trustedCertificate, add to certificateStore. -bool WinHttpTransport::AddCertificatesToStore( +bool _detail::WinHttpRequest::AddCertificatesToStore( std::vector const& trustedCertificates, - HCERTSTORE certificateStore) + HCERTSTORE certificateStore) const { for (auto const& trustedCertificate : trustedCertificates) { @@ -236,9 +238,9 @@ bool WinHttpTransport::AddCertificatesToStore( // VerifyCertificateInChain determines whether the certificate in serverCertificate // chains up to one of the certificates represented by trustedCertificate or not. -bool WinHttpTransport::VerifyCertificatesInChain( +bool _detail::WinHttpRequest::VerifyCertificatesInChain( std::vector const& trustedCertificates, - PCCERT_CONTEXT serverCertificate) + PCCERT_CONTEXT serverCertificate) const { if ((trustedCertificates.empty()) || !serverCertificate) { @@ -327,121 +329,349 @@ bool WinHttpTransport::VerifyCertificatesInChain( return true; } -/** - * Called by WinHTTP when sending a request to the server. This callback allows us to inspect the - * TLS certificate before sending it to the server. - */ -void WinHttpTransport::StatusCallback( - HINTERNET hInternet, - DWORD_PTR dwContext, - DWORD dwInternetStatus, - LPVOID, - DWORD) noexcept +namespace { + +// If the `internetStatus` value has `id` bit set, then append the name of `id` to the string `rv`. +#define APPEND_ENUM_STRING(id) \ + if (internetStatus & (id)) \ + { \ + rv += #id " "; \ + } +std::string InternetStatusToString(DWORD internetStatus) { - // If we're called before our context has been set (on Open and Close callbacks), ignore the - // status callback. - if (dwContext == 0) + std::string rv; + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_RESOLVING_NAME); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_NAME_RESOLVED); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_SENDING_REQUEST); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_REQUEST_SENT); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_HANDLE_CREATED); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_DETECTING_PROXY); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_REDIRECT); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_SECURE_FAILURE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_READ_COMPLETE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_REQUEST_ERROR); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE); + // For this is not defined on the Win2022 Azure DevOps image, so manually expand it. + // APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_GETPROXYSETTINGS_COMPLETE); + if (internetStatus & 0x08000000) { - return; + rv += std::string("WINHTTP_CALLBACK_STATUS_GETPROXYSETTINGS_COMPLETE") + " "; } + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE); + APPEND_ENUM_STRING(WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE); + return rv; +} +#undef APPEND_ENUM_STRING - try +std::string GetErrorMessage(DWORD error) +{ + std::string errorMessage = " Error Code: " + std::to_string(error); + + char* errorMsg = nullptr; + if (FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER, + GetModuleHandle("winhttp.dll"), + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&errorMsg), + 0, + nullptr) + != 0) + { + // Use a unique_ptr to manage the lifetime of errorMsg. + std::unique_ptr errorString(errorMsg, &LocalFree); + errorMsg = nullptr; + + errorMessage += ": "; + errorMessage += errorString.get(); + } + errorMessage += '.'; + return errorMessage; +} +} // namespace + +namespace Azure { namespace Core { namespace Http { namespace _detail { + + bool WinHttpAction::RegisterWinHttpStatusCallback( + Azure::Core::_internal::UniqueHandle const& internetHandle) { - WinHttpTransport* httpTransport = reinterpret_cast(dwContext); - httpTransport->OnHttpStatusOperation(hInternet, dwInternetStatus); + return ( + WinHttpSetStatusCallback( + internetHandle.get(), + &WinHttpAction::StatusCallback, + WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, + 0) + != WINHTTP_INVALID_STATUS_CALLBACK); } - catch (Azure::Core::RequestFailedException& rfe) + + /** + * Wait for an action to complete. + * + */ + bool WinHttpAction::WaitForAction( + std::function initiateAction, + DWORD expectedCallbackStatus, + Azure::Core::Context const& context, + Azure::DateTime::duration const& pollInterval) { - // If an exception is thrown in the handler, log the error and terminate the connection. - Log::Write( - Logger::Level::Error, - "Request Failed Exception Thrown: " + std::string(rfe.what()) + rfe.Message); - WinHttpCloseHandle(hInternet); + // Before doing any work, check to make sure that the context hasn't already been cancelled. + context.ThrowIfCancelled(); + + // By definition, there cannot be any actions outstanding at this point because we have not + // yet called initiateAction. So it's safe to reset our state here. + ResetEvent(m_actionCompleteEvent.get()); + m_expectedStatus = expectedCallbackStatus; + m_stowedError = 0; + m_stowedErrorInformation = 0; + m_bytesAvailable = 0; + + // Call the provided callback to start the WinHTTP action. + initiateAction(); + + DWORD waitResult; + do + { + waitResult = WaitForSingleObject( + m_actionCompleteEvent.get(), + static_cast( + std::chrono::duration_cast(pollInterval).count())); + if (waitResult == WAIT_TIMEOUT) + { + // If the request was cancelled while we were waiting, throw an exception. + context.ThrowIfCancelled(); + } + else if (waitResult != WAIT_OBJECT_0) + { + return false; + } + } while (waitResult != WAIT_OBJECT_0); + if (m_stowedError != NO_ERROR) + { + return false; + } + return true; } - catch (std::exception& ex) + + void WinHttpAction::CompleteAction() { - // If an exception is thrown in the handler, log the error and terminate the connection. - Log::Write(Logger::Level::Error, "Exception Thrown: " + std::string(ex.what())); + auto scope_exit{m_actionCompleteEvent.SetEvent_scope_exit()}; + } + void WinHttpAction::CompleteActionWithData(DWORD bytesAvailable) + { + // Note that the order of scope_exit and lock is important - this ensures that scope_exit is + // destroyed *after* lock is destroyed, ensuring that the event is not set to the signalled + // state before the lock is released. + auto scope_exit{m_actionCompleteEvent.SetEvent_scope_exit()}; + std::unique_lock lock(m_actionCompleteMutex); + m_bytesAvailable = bytesAvailable; + } + void WinHttpAction::CompleteActionWithError(DWORD_PTR stowedErrorInformation, DWORD stowedError) + { + // Note that the order of scope_exit and lock is important - this ensures that scope_exit is + // destroyed *after* lock is destroyed, ensuring that the event is not set to the signalled + // state before the lock is released. + auto scope_exit{m_actionCompleteEvent.SetEvent_scope_exit()}; + std::unique_lock lock(m_actionCompleteMutex); + m_stowedErrorInformation = stowedErrorInformation; + m_stowedError = stowedError; } -} -/** - * @brief HTTP Callback to enable private certificate checks. - * - * This method is called by WinHTTP when a certificate is received. This method is called multiple - * times based on the state of the TLS connection. We are only interested in - * WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, which is called during the TLS handshake. - * - * When called, we verify that the certificate chain sent from the server contains the certificate - * the HTTP client was configured with. If it is, we accept the connection, if it is not, - * we abort the connection, closing the incoming request handle. - */ -void WinHttpTransport::OnHttpStatusOperation(HINTERNET hInternet, DWORD dwInternetStatus) -{ - if (dwInternetStatus != WINHTTP_CALLBACK_STATUS_SENDING_REQUEST) + DWORD WinHttpAction::GetStowedError() { - if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) + std::unique_lock lock(m_actionCompleteMutex); + return m_stowedError; + } + DWORD_PTR WinHttpAction::GetStowedErrorInformation() + { + std::unique_lock lock(m_actionCompleteMutex); + return m_stowedErrorInformation; + } + DWORD WinHttpAction::GetBytesAvailable() + { + std::unique_lock lock(m_actionCompleteMutex); + return m_bytesAvailable; + } + + /** + * Called by WinHTTP when sending a request to the server. This callback allows us to inspect + * the TLS certificate before sending it to the server. + */ + void WinHttpAction::StatusCallback( + HINTERNET hInternet, + DWORD_PTR dwContext, + DWORD internetStatus, + LPVOID statusInformation, + DWORD statusInformationLength) noexcept + { + // If we're called before our context has been set (on Open and Close callbacks), ignore the + // status callback. + if (dwContext == 0) { - Log::Write(Logger::Level::Error, "Security failure. :("); + return; } - // Silently ignore if there's any statuses we get that we can't handle - return; - } - // We will only set the Status callback if a root certificate has been set. - AZURE_ASSERT(!m_options.ExpectedTlsRootCertificates.empty()); + try + { + WinHttpAction* httpAction = reinterpret_cast(dwContext); + httpAction->OnHttpStatusOperation( + hInternet, internetStatus, statusInformation, statusInformationLength); + } + catch (Azure::Core::RequestFailedException const& rfe) + { + // If an exception is thrown in the handler, log the error and terminate the connection. + Log::Write( + Logger::Level::Error, + "Request Failed Exception Thrown: " + std::string(rfe.what()) + rfe.Message); + WinHttpCloseHandle(hInternet); + } + catch (std::exception const& ex) + { + // If an exception is thrown in the handler, log the error and terminate the connection. + Log::Write(Logger::Level::Error, "Exception Thrown: " + std::string(ex.what())); + } + } - // Ask WinHTTP for the server certificate - this won't be valid outside a status callback. - wil::unique_cert_context serverCertificate; + /** + * @brief HTTP Callback to enable private certificate checks. + * + * This method is called by WinHTTP when a certificate is received. This method is called + * multiple times based on the state of the TLS connection. + * + * Special consideration for the WINHTTP_CALLBACK_STATUS_SENDING_REQUEST - this callback is + * called during the TLS connection - if a TLS root certificate is configured, we verify that the + * certificate chain sent from the server contains the certificate the HTTP client was configured + * with. If it is, we accept the connection, if it is not, we abort the connection, closing the + * incoming request handle. + */ + void WinHttpAction::OnHttpStatusOperation( + HINTERNET hInternet, + DWORD internetStatus, + LPVOID statusInformation, + DWORD statusInformationLength) { - DWORD bufferLength = sizeof(PCCERT_CONTEXT); - if (!WinHttpQueryOption( - hInternet, - WINHTTP_OPTION_SERVER_CERT_CONTEXT, - reinterpret_cast(serverCertificate.addressof()), - &bufferLength)) + Log::Write( + Logger::Level::Informational, + "Status operation: " + std::to_string(internetStatus) + "(" + + InternetStatusToString(internetStatus) + ")"); + if (internetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) { - GetErrorAndThrow("Could not retrieve TLS server certificate."); + Log::Write(Logger::Level::Error, "Security failure. :("); + } + else if (internetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) + { + WINHTTP_ASYNC_RESULT* asyncResult = static_cast(statusInformation); + Log::Write( + Logger::Level::Error, + "Request error. " + GetErrorMessage(asyncResult->dwError) + " " + + std::to_string(asyncResult->dwResult)); + CompleteActionWithError(asyncResult->dwResult, asyncResult->dwError); + } + else if (internetStatus == WINHTTP_CALLBACK_STATUS_SENDING_REQUEST) + { + // We will only set the Status callback if a root certificate has been set. There is no action + // which needs to be completed for this notification. + m_httpRequest->HandleExpectedTlsRootCertificates(hInternet); + } + else if (internetStatus == m_expectedStatus) + { + switch (internetStatus) + { + case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: + // A WinHttpSendRequest API call has completed, complete the current action. + CompleteAction(); + break; + case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: + // A WinHttpWriteData call has completed, complete the current action. + CompleteAction(); + break; + case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: + // Headers for an HTTP response are available, complete the current action. + CompleteAction(); + break; + case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: + // A WinHttpReadData call has completed. Complete the current action, including the amount + // of data read. + CompleteActionWithData(statusInformationLength); + break; + case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING: + // An HINTERNET handle is closing, complete the outstanding close request. + Log::Write( + Logger::Level::Verbose, "Closing handle; completing outstanding Close request"); + CompleteAction(); + break; + default: + Log::Write( + Logger::Level::Error, + "Received expected status " + InternetStatusToString(internetStatus) + + " but it was not handled."); + break; + } } } - if (!VerifyCertificatesInChain(m_options.ExpectedTlsRootCertificates, serverCertificate.get())) + void WinHttpRequest::HandleExpectedTlsRootCertificates(HINTERNET hInternet) { - Log::Write(Logger::Level::Error, "Server certificate is not trusted. Aborting HTTP request"); + if (!m_expectedTlsRootCertificates.empty()) + { + // Ask WinHTTP for the server certificate - this won't be valid outside a status callback. + wil::unique_cert_context serverCertificate; + { + DWORD bufferLength = sizeof(PCCERT_CONTEXT); + if (!WinHttpQueryOption( + hInternet, + WINHTTP_OPTION_SERVER_CERT_CONTEXT, + reinterpret_cast(serverCertificate.addressof()), + &bufferLength)) + { + GetErrorAndThrow("Could not retrieve TLS server certificate."); + } + } - // To signal to caller that the request is to be terminated, the callback closes the handle. - // This ensures that no message is sent to the server. - WinHttpCloseHandle(hInternet); + if (!VerifyCertificatesInChain(m_expectedTlsRootCertificates, serverCertificate.get())) + { + Log::Write( + Logger::Level::Error, "Server certificate is not trusted. Aborting HTTP request"); - // To avoid a double free of this handle record that we've - // already closed the handle. - m_requestHandleClosed = true; - } -} + // To signal to caller that the request is to be terminated, the callback closes the + // handle. This ensures that no message is sent to the server. + WinHttpCloseHandle(hInternet); -void WinHttpTransport::GetErrorAndThrow(const std::string& exceptionMessage, DWORD error) -{ - std::string errorMessage = exceptionMessage + " Error Code: " + std::to_string(error); + // To avoid a double free of this handle record that we've + // already closed the handle. + m_requestHandleClosed = true; - char* errorMsg = nullptr; - if (FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER, - GetModuleHandle("winhttp.dll"), - error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast(&errorMsg), - 0, - nullptr) - != 0) + // And we're done processing the request, return because there's nothing + // else to do. + return; + } + } + } + + void WinHttpRequest::GetErrorAndThrow(const std::string& exceptionMessage, DWORD error) const { - // Use a unique_ptr to manage the lifetime of errorMsg. - std::unique_ptr errorString(errorMsg, &LocalFree); - errorMsg = nullptr; + std::string errorMessage = exceptionMessage + GetErrorMessage(error); - errorMessage += ": "; - errorMessage += errorString.get(); + throw Azure::Core::Http::TransportException(errorMessage); } - errorMessage += '.'; +}}}} // namespace Azure::Core::Http::_detail + +void WinHttpTransport::GetErrorAndThrow(const std::string& exceptionMessage, DWORD error) +{ + std::string errorMessage = exceptionMessage + GetErrorMessage(error); throw Azure::Core::Http::TransportException(errorMessage); } @@ -458,7 +688,7 @@ Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateSessionH : WINHTTP_ACCESS_TYPE_NO_PROXY), WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, - 0)); + WINHTTP_FLAG_ASYNC)); // All requests on this session are performed asynchronously. if (!sessionHandle) { @@ -495,21 +725,6 @@ Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateSessionH GetErrorAndThrow("Error while enforcing TLS 1.2 for connection request."); } - if (!m_options.ExpectedTlsRootCertificates.empty()) - { - - // Set the callback function to be called when a server certificate is received. - if (WinHttpSetStatusCallback( - sessionHandle.get(), - &WinHttpTransport::StatusCallback, - WINHTTP_CALLBACK_FLAG_SEND_REQUEST /* WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS*/, - 0) - == WINHTTP_INVALID_STATUS_CALLBACK) - { - GetErrorAndThrow("Error while setting up the status callback."); - } - } - return sessionHandle; } @@ -563,6 +778,8 @@ WinHttpTransport::WinHttpTransport( { } +WinHttpTransport::~WinHttpTransport() = default; + Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateConnectionHandle( Azure::Core::Url const& url, Azure::Core::Context const& context) @@ -570,6 +787,7 @@ Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateConnecti // If port is 0, i.e. INTERNET_DEFAULT_PORT, it uses port 80 for HTTP and port 443 for HTTPS. uint16_t port = url.GetPort(); + // Before doing any work, check to make sure that the context hasn't already been cancelled. context.ThrowIfCancelled(); // Specify an HTTP server. @@ -595,10 +813,24 @@ Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateConnecti return rv; } -Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateRequestHandle( +void _detail::WinHttpRequest::EnableWebSocketsSupport() +{ +#pragma warning(push) + // warning C6387: _Param_(3) could be '0'. +#pragma warning(disable : 6387) + if (!WinHttpSetOption(m_requestHandle.get(), WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, nullptr, 0)) +#pragma warning(pop) + { + GetErrorAndThrow("Error while Enabling WebSocket upgrade."); + } +} + +_detail::WinHttpRequest::WinHttpRequest( Azure::Core::_internal::UniqueHandle const& connectionHandle, Azure::Core::Url const& url, - Azure::Core::Http::HttpMethod const& method) + Azure::Core::Http::HttpMethod const& method, + WinHttpTransportOptions const& options) + : m_expectedTlsRootCertificates(options.ExpectedTlsRootCertificates) { const std::string& path = url.GetRelativeUrl(); HttpMethod requestMethod = method; @@ -609,7 +841,7 @@ Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateRequestH url.GetScheme(), WebSocketScheme)); // Create an HTTP request handle. - Azure::Core::_internal::UniqueHandle request(WinHttpOpenRequest( + m_requestHandle.reset(WinHttpOpenRequest( connectionHandle.get(), HttpMethodToWideString(requestMethod).c_str(), path.empty() ? NULL : StringToWideString(path).c_str(), // Name of the target resource of @@ -618,7 +850,7 @@ Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateRequestH WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, // No media types are accepted by the client requestSecureHttp ? WINHTTP_FLAG_SECURE : 0)); // Uses secure transaction semantics (SSL/TLS) - if (!request) + if (!m_requestHandle) { // Errors include: // ERROR_WINHTTP_INCORRECT_HANDLE_TYPE @@ -638,73 +870,106 @@ Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateRequestH // Note: If/When TLS client certificate support is added to the pipeline, this line may need to // be revisited. if (!WinHttpSetOption( - request.get(), WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)) + m_requestHandle.get(), + WINHTTP_OPTION_CLIENT_CERT_CONTEXT, + WINHTTP_NO_CLIENT_CERT_CONTEXT, + 0)) { GetErrorAndThrow("Error while setting client cert context to ignore."); } } - if (!m_options.ProxyInformation.empty()) + if (!options.ProxyInformation.empty()) { WINHTTP_PROXY_INFO proxyInfo{}; - std::wstring proxyWide{StringToWideString(m_options.ProxyInformation)}; + std::wstring proxyWide{StringToWideString(options.ProxyInformation)}; proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; proxyInfo.lpszProxy = const_cast(proxyWide.c_str()); proxyInfo.lpszProxyBypass = WINHTTP_NO_PROXY_BYPASS; - if (!WinHttpSetOption(request.get(), WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo))) + if (!WinHttpSetOption( + m_requestHandle.get(), WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo))) { GetErrorAndThrow("Error while setting Proxy information."); } } - if (m_options.ProxyUserName.HasValue() || m_options.ProxyPassword.HasValue()) + if (options.ProxyUserName.HasValue() || options.ProxyPassword.HasValue()) { if (!WinHttpSetCredentials( - request.get(), + m_requestHandle.get(), WINHTTP_AUTH_TARGET_PROXY, WINHTTP_AUTH_SCHEME_BASIC, - StringToWideString(m_options.ProxyUserName.Value()).c_str(), - StringToWideString(m_options.ProxyPassword.Value()).c_str(), + StringToWideString(options.ProxyUserName.Value()).c_str(), + StringToWideString(options.ProxyPassword.Value()).c_str(), 0)) { GetErrorAndThrow("Error while setting Proxy credentials."); } } - if (m_options.IgnoreUnknownCertificateAuthority || !m_options.ExpectedTlsRootCertificates.empty()) + if (options.IgnoreUnknownCertificateAuthority || !options.ExpectedTlsRootCertificates.empty()) { auto option = SECURITY_FLAG_IGNORE_UNKNOWN_CA; - if (!WinHttpSetOption(request.get(), WINHTTP_OPTION_SECURITY_FLAGS, &option, sizeof(option))) + if (!WinHttpSetOption( + m_requestHandle.get(), WINHTTP_OPTION_SECURITY_FLAGS, &option, sizeof(option))) { GetErrorAndThrow("Error while setting ignore unknown server certificate."); } } - if (m_options.EnableCertificateRevocationListCheck) + if (options.EnableCertificateRevocationListCheck) { DWORD value = WINHTTP_ENABLE_SSL_REVOCATION; - if (!WinHttpSetOption(request.get(), WINHTTP_OPTION_ENABLE_FEATURE, &value, sizeof(value))) + if (!WinHttpSetOption( + m_requestHandle.get(), WINHTTP_OPTION_ENABLE_FEATURE, &value, sizeof(value))) { GetErrorAndThrow("Error while enabling CRL validation."); } } + // Set the callback function to be called whenever the state of the request handle changes. + m_httpAction = std::make_unique<_detail::WinHttpAction>(this); + + if (!m_httpAction->RegisterWinHttpStatusCallback(m_requestHandle)) + { + GetErrorAndThrow("Error while setting up the status callback."); + } +} + +/* + * Destructor for WinHTTP request. Closes the request handle. + */ +_detail::WinHttpRequest::~WinHttpRequest() +{ + if (!m_requestHandleClosed) + { + Log::Write( + Logger::Level::Verbose, "WinHttpRequest::~WinHttpRequest. Closing handle synchronously."); + + // Close the outstanding request handle, waiting until the HANDLE_CLOSING status is received. + m_httpAction->WaitForAction( + [this]() { m_requestHandle.reset(); }, + WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, + Azure::Core::Context{}); + } +} + +std::unique_ptr<_detail::WinHttpRequest> WinHttpTransport::CreateRequestHandle( + Azure::Core::_internal::UniqueHandle const& connectionHandle, + Azure::Core::Url const& url, + Azure::Core::Http::HttpMethod const& method) +{ + auto request{std::make_unique<_detail::WinHttpRequest>(connectionHandle, url, method, m_options)}; // If we are supporting WebSockets, then let WinHTTP know that it should // prepare to upgrade the HttpRequest to a WebSocket. -#pragma warning(push) -// warning C6387: _Param_(3) could be '0'. -#pragma warning(disable : 6387) - if (HasWebSocketSupport() - && !WinHttpSetOption(request.get(), WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, nullptr, 0)) -#pragma warning(pop) + if (HasWebSocketSupport()) { - GetErrorAndThrow("Error while Enabling WebSocket upgrade."); + request->EnableWebSocketsSupport(); } return request; } // For PUT/POST requests, send additional data using WinHttpWriteData. -void WinHttpTransport::Upload( - Azure::Core::_internal::UniqueHandle const& requestHandle, +void _detail::WinHttpRequest::Upload( Azure::Core::Http::Request& request, Azure::Core::Context const& context) { @@ -729,22 +994,27 @@ void WinHttpTransport::Upload( DWORD dwBytesWritten = 0; - context.ThrowIfCancelled(); + if (!m_httpAction->WaitForAction( + [&]() { // Write data to the server. + if (!WinHttpWriteData( + m_requestHandle.get(), + unique_buffer.get(), + static_cast(rawRequestLen), + &dwBytesWritten)) + { + GetErrorAndThrow("Error while uploading/sending data."); + } + }, + WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, + context)) - // Write data to the server. - if (!WinHttpWriteData( - requestHandle.get(), - unique_buffer.get(), - static_cast(rawRequestLen), - &dwBytesWritten)) { - GetErrorAndThrow("Error while uploading/sending data."); + GetErrorAndThrow("Error sending HTTP request asynchronously", m_httpAction->GetStowedError()); } } } -void WinHttpTransport::SendRequest( - Azure::Core::_internal::UniqueHandle const& requestHandle, +void _detail::WinHttpRequest::SendRequest( Azure::Core::Http::Request& request, Azure::Core::Context const& context) { @@ -764,78 +1034,110 @@ void WinHttpTransport::SendRequest( int64_t streamLength = request.GetBodyStream()->Length(); - context.ThrowIfCancelled(); - - // Send a request. - if (!WinHttpSendRequest( - requestHandle.get(), - requestHeaders.size() == 0 ? WINHTTP_NO_ADDITIONAL_HEADERS : encodedHeaders.c_str(), - encodedHeadersLength, - WINHTTP_NO_REQUEST_DATA, - 0, - streamLength > 0 ? static_cast(streamLength) : 0, - reinterpret_cast(this))) + try { - // Errors include: - // ERROR_WINHTTP_CANNOT_CONNECT - // ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED - // ERROR_WINHTTP_CONNECTION_ERROR - // ERROR_WINHTTP_INCORRECT_HANDLE_STATE - // ERROR_WINHTTP_INCORRECT_HANDLE_TYPE - // ERROR_WINHTTP_INTERNAL_ERROR - // ERROR_WINHTTP_INVALID_URL - // ERROR_WINHTTP_LOGIN_FAILURE - // ERROR_WINHTTP_NAME_NOT_RESOLVED - // ERROR_WINHTTP_OPERATION_CANCELLED - // ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW - // ERROR_WINHTTP_SECURE_FAILURE - // ERROR_WINHTTP_SHUTDOWN - // ERROR_WINHTTP_TIMEOUT - // ERROR_WINHTTP_UNRECOGNIZED_SCHEME - // ERROR_NOT_ENOUGH_MEMORY - // ERROR_INVALID_PARAMETER - // ERROR_WINHTTP_RESEND_REQUEST - GetErrorAndThrow("Error while sending a request."); - } + if (!m_httpAction->WaitForAction( + [&]() { + { + // Send a request. + // NB: DO NOT CHANGE THE TYPE OF THE CONTEXT PARAMETER WITHOUT UPDATING THE + // HttpAction::StatusCallback method. + if (!WinHttpSendRequest( + m_requestHandle.get(), + requestHeaders.size() == 0 ? WINHTTP_NO_ADDITIONAL_HEADERS + : encodedHeaders.c_str(), + encodedHeadersLength, + WINHTTP_NO_REQUEST_DATA, + 0, + streamLength > 0 ? static_cast(streamLength) : 0, + reinterpret_cast( + m_httpAction + .get()))) // Context for WinHTTP status callbacks for this request. + { + // Errors include: + // ERROR_WINHTTP_CANNOT_CONNECT + // ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED + // ERROR_WINHTTP_CONNECTION_ERROR + // ERROR_WINHTTP_INCORRECT_HANDLE_STATE + // ERROR_WINHTTP_INCORRECT_HANDLE_TYPE + // ERROR_WINHTTP_INTERNAL_ERROR + // ERROR_WINHTTP_INVALID_URL + // ERROR_WINHTTP_LOGIN_FAILURE + // ERROR_WINHTTP_NAME_NOT_RESOLVED + // ERROR_WINHTTP_OPERATION_CANCELLED + // ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW + // ERROR_WINHTTP_SECURE_FAILURE + // ERROR_WINHTTP_SHUTDOWN + // ERROR_WINHTTP_TIMEOUT + // ERROR_WINHTTP_UNRECOGNIZED_SCHEME + // ERROR_NOT_ENOUGH_MEMORY + // ERROR_INVALID_PARAMETER + // ERROR_WINHTTP_RESEND_REQUEST + GetErrorAndThrow("Error while sending a request."); + } + } + }, + WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, + context)) + { + GetErrorAndThrow( + "Error while waiting for a send to complete.", m_httpAction->GetStowedError()); + } - // Chunked transfer encoding is not supported and the content length needs to be known up front. - if (streamLength == -1) - { - throw Azure::Core::Http::TransportException( - "When uploading data, the body stream must have a known length."); - } + // Chunked transfer encoding is not supported and the content length needs to be known up + // front. + if (streamLength == -1) + { + throw Azure::Core::Http::TransportException( + "When uploading data, the body stream must have a known length."); + } - if (streamLength > 0) + if (streamLength > 0) + { + Upload(request, context); + } + } + catch (TransportException const&) { - Upload(requestHandle, request, context); + // If there was a TLS validation error, then we will have closed the request handle + // during the TLS validation callback. So if an exception was thrown, if we force closed the + // request handle, clear the handle in the requestHandle to prevent a double free. + if (m_requestHandleClosed) + { + m_requestHandle.release(); + } + throw; } } -void WinHttpTransport::ReceiveResponse( - Azure::Core::_internal::UniqueHandle const& requestHandle, - Azure::Core::Context const& context) +void _detail::WinHttpRequest::ReceiveResponse(Azure::Core::Context const& context) { - context.ThrowIfCancelled(); - // Wait to receive the response to the HTTP request initiated by WinHttpSendRequest. // When WinHttpReceiveResponse completes successfully, the status code and response headers have // been received. - if (!WinHttpReceiveResponse(requestHandle.get(), NULL)) + if (!m_httpAction->WaitForAction( + [this]() { + if (!WinHttpReceiveResponse(m_requestHandle.get(), NULL)) + { + // Errors include: + // ERROR_WINHTTP_CANNOT_CONNECT + // ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW + // ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED + // ... + // ERROR_WINHTTP_TIMEOUT + // ERROR_WINHTTP_UNRECOGNIZED_SCHEME + // ERROR_NOT_ENOUGH_MEMORY + GetErrorAndThrow("Error while receiving a response."); + } + }, + WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, + context)) { - // Errors include: - // ERROR_WINHTTP_CANNOT_CONNECT - // ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW - // ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED - // ... - // ERROR_WINHTTP_TIMEOUT - // ERROR_WINHTTP_UNRECOGNIZED_SCHEME - // ERROR_NOT_ENOUGH_MEMORY - GetErrorAndThrow("Error while receiving a response."); + GetErrorAndThrow("Error while receiving a response.", m_httpAction->GetStowedError()); } } -int64_t WinHttpTransport::GetContentLength( - Azure::Core::_internal::UniqueHandle const& requestHandle, +int64_t _detail::WinHttpRequest::GetContentLength( HttpMethod requestMethod, HttpStatusCode responseStatusCode) { @@ -852,7 +1154,7 @@ int64_t WinHttpTransport::GetContentLength( if (requestMethod != HttpMethod::Head && responseStatusCode != HttpStatusCode::NoContent) { if (!WinHttpQueryHeaders( - requestHandle.get(), + m_requestHandle.get(), WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &dwContentLength, @@ -870,15 +1172,14 @@ int64_t WinHttpTransport::GetContentLength( return contentLength; } -std::unique_ptr WinHttpTransport::SendRequestAndGetResponse( - Azure::Core::_internal::UniqueHandle& requestHandle, +std::unique_ptr _detail::WinHttpRequest::SendRequestAndGetResponse( HttpMethod requestMethod) { // First, use WinHttpQueryHeaders to obtain the size of the buffer. // The call is expected to fail since no destination buffer is provided. DWORD sizeOfHeaders = 0; if (WinHttpQueryHeaders( - requestHandle.get(), + m_requestHandle.get(), WINHTTP_QUERY_RAW_HEADERS, WINHTTP_HEADER_NAME_BY_INDEX, NULL, @@ -903,7 +1204,7 @@ std::unique_ptr WinHttpTransport::SendRequestAndGetResponse( // Now, use WinHttpQueryHeaders to retrieve all the headers. // Each header is terminated by "\0". An additional "\0" terminates the list of headers. if (!WinHttpQueryHeaders( - requestHandle.get(), + m_requestHandle.get(), WINHTTP_QUERY_RAW_HEADERS, WINHTTP_HEADER_NAME_BY_INDEX, outputBuffer.data(), @@ -923,7 +1224,7 @@ std::unique_ptr WinHttpTransport::SendRequestAndGetResponse( // Get the HTTP version. if (!WinHttpQueryHeaders( - requestHandle.get(), + m_requestHandle.get(), WINHTTP_QUERY_VERSION, WINHTTP_HEADER_NAME_BY_INDEX, outputBuffer.data(), @@ -946,7 +1247,7 @@ std::unique_ptr WinHttpTransport::SendRequestAndGetResponse( // Get the status code as a number. if (!WinHttpQueryHeaders( - requestHandle.get(), + m_requestHandle.get(), WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, @@ -967,7 +1268,7 @@ std::unique_ptr WinHttpTransport::SendRequestAndGetResponse( if (majorVersion == 1) { if (WinHttpQueryHeaders( - requestHandle.get(), + m_requestHandle.get(), WINHTTP_QUERY_STATUS_TEXT, WINHTTP_HEADER_NAME_BY_INDEX, outputBuffer.data(), @@ -992,14 +1293,29 @@ std::unique_ptr WinHttpTransport::SendRequestAndGetResponse( SetHeaders(responseHeaders, rawResponse); - if (HasWebSocketSupport() && (httpStatusCode == HttpStatusCode::SwitchingProtocols)) + return rawResponse; +} + +std::unique_ptr WinHttpTransport::Send(Request& request, Context const& context) +{ + Azure::Core::_internal::UniqueHandle connectionHandle + = CreateConnectionHandle(request.GetUrl(), context); + std::unique_ptr<_detail::WinHttpRequest> requestHandle( + CreateRequestHandle(connectionHandle, request.GetUrl(), request.GetMethod())); + + requestHandle->SendRequest(request, context); + requestHandle->ReceiveResponse(context); + + auto rawResponse{requestHandle->SendRequestAndGetResponse(request.GetMethod())}; + if (rawResponse && HasWebSocketSupport() + && (rawResponse->GetStatusCode() == HttpStatusCode::SwitchingProtocols)) { OnUpgradedConnection(requestHandle); } else { int64_t contentLength - = GetContentLength(requestHandle, requestMethod, rawResponse->GetStatusCode()); + = requestHandle->GetContentLength(request.GetMethod(), rawResponse->GetStatusCode()); rawResponse->SetBodyStream( std::make_unique<_detail::WinHttpStream>(requestHandle, contentLength)); @@ -1007,32 +1323,53 @@ std::unique_ptr WinHttpTransport::SendRequestAndGetResponse( return rawResponse; } -std::unique_ptr WinHttpTransport::Send(Request& request, Context const& context) +size_t _detail::WinHttpRequest::ReadData( + uint8_t* buffer, + size_t count, + Azure::Core::Context const& context) { - Azure::Core::_internal::UniqueHandle connectionHandle - = CreateConnectionHandle(request.GetUrl(), context); - Azure::Core::_internal::UniqueHandle requestHandle - = CreateRequestHandle(connectionHandle, request.GetUrl(), request.GetMethod()); - try + DWORD numberOfBytesRead = 0; + if (!m_httpAction->WaitForAction( + [&]() { + if (!WinHttpReadData( + this->m_requestHandle.get(), + (LPVOID)(buffer), + static_cast(count), + &numberOfBytesRead)) + { + // Errors include: + // ERROR_WINHTTP_CONNECTION_ERROR + // ERROR_WINHTTP_INCORRECT_HANDLE_STATE + // ERROR_WINHTTP_INCORRECT_HANDLE_TYPE + // ERROR_WINHTTP_INTERNAL_ERROR + // ERROR_WINHTTP_OPERATION_CANCELLED + // ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW + // ERROR_WINHTTP_TIMEOUT + // ERROR_NOT_ENOUGH_MEMORY + + DWORD error = GetLastError(); + throw Azure::Core::Http::TransportException( + "Error while reading available data from the wire. Error Code: " + + std::to_string(error) + "."); + } + Log::Write( + Logger::Level::Verbose, + "Read Data read from wire. Size: " + std::to_string(numberOfBytesRead) + "."); + }, + WINHTTP_CALLBACK_STATUS_READ_COMPLETE, + context)) { - SendRequest(requestHandle, request, context); + GetErrorAndThrow("Error sending HTTP request asynchronously", m_httpAction->GetStowedError()); } - catch (TransportException&) + if (numberOfBytesRead == 0) { - // If there was a TLS validation error, then we will have closed the request handle - // during the TLS validation callback. So if an exception was thrown, if we force closed the - // request handle, clear the handle in the requestHandle to prevent a double free. - if (m_requestHandleClosed) - { - requestHandle.release(); - } - - throw; + numberOfBytesRead = m_httpAction->GetBytesAvailable(); } - ReceiveResponse(requestHandle, context); + Log::Write( + Logger::Level::Verbose, "ReadData returned size: " + std::to_string(numberOfBytesRead) + "."); - return SendRequestAndGetResponse(requestHandle, request.GetMethod()); + return numberOfBytesRead; } // Read the response from the sent request. @@ -1043,33 +1380,7 @@ size_t _detail::WinHttpStream::OnRead(uint8_t* buffer, size_t count, Context con return 0; } - // No need to check for context cancellation before the first I/O because the base class - // BodyStream::Read already does that. - (void)context; - - DWORD numberOfBytesRead = 0; - - if (!WinHttpReadData( - this->m_requestHandle.get(), - (LPVOID)(buffer), - static_cast(count), - &numberOfBytesRead)) - { - // Errors include: - // ERROR_WINHTTP_CONNECTION_ERROR - // ERROR_WINHTTP_INCORRECT_HANDLE_STATE - // ERROR_WINHTTP_INCORRECT_HANDLE_TYPE - // ERROR_WINHTTP_INTERNAL_ERROR - // ERROR_WINHTTP_OPERATION_CANCELLED - // ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW - // ERROR_WINHTTP_TIMEOUT - // ERROR_NOT_ENOUGH_MEMORY - - DWORD error = GetLastError(); - throw Azure::Core::Http::TransportException( - "Error while reading available data from the wire. Error Code: " + std::to_string(error) - + "."); - } + size_t numberOfBytesRead = m_requestHandle->ReadData(buffer, count, context); this->m_streamTotalRead += numberOfBytesRead; diff --git a/sdk/core/azure-core/test/ut/azure_core_test.cpp b/sdk/core/azure-core/test/ut/azure_core_test.cpp index bf312f1565..1b257efd75 100644 --- a/sdk/core/azure-core/test/ut/azure_core_test.cpp +++ b/sdk/core/azure-core/test/ut/azure_core_test.cpp @@ -3,15 +3,10 @@ #include -#if defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER) -#include -#endif +#include "azure/core/internal/diagnostics/global_exception.hpp" +#include "azure/core/platform.hpp" +#include #include -#include - -// C Runtime Library errors trigger SIGABRT. Catch that signal handler and report it on the test -// log. -void AbortHandler(int signal) { std::cout << "abort() has been called: " << signal << std::endl; } int main(int argc, char** argv) { @@ -21,7 +16,16 @@ int main(int argc, char** argv) signal(SIGPIPE, SIG_IGN); #endif - signal(SIGABRT, AbortHandler); + // Declare a signal handler to report unhandled exceptions on Windows - this is not needed for + // other OS's as they will print the exception to stderr in their terminate() function. +#if defined(AZ_PLATFORM_WINDOWS) + // Ensure that all calls to abort() no longer pop up a modal dialog on Windows. +#if defined(_DEBUG) && defined(_MSC_VER) + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); +#endif + + signal(SIGABRT, Azure::Core::Diagnostics::_internal::GlobalExceptionHandler::HandleSigAbort); +#endif // AZ_PLATFORM_WINDOWS testing::InitGoogleTest(&argc, argv); auto r = RUN_ALL_TESTS(); diff --git a/sdk/core/azure-core/test/ut/azure_libcurl_core_main_test.cpp b/sdk/core/azure-core/test/ut/azure_libcurl_core_main_test.cpp index feadd5f1c5..56d090f6c3 100644 --- a/sdk/core/azure-core/test/ut/azure_libcurl_core_main_test.cpp +++ b/sdk/core/azure-core/test/ut/azure_libcurl_core_main_test.cpp @@ -13,21 +13,21 @@ #if !defined(NOMINMAX) #define NOMINMAX #endif +#include +#include #include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include +#include "azure/core/context.hpp" +#include "azure/core/http/curl_transport.hpp" +#include "azure/core/http/http.hpp" +#include "azure/core/http/policies/policy.hpp" +#include "azure/core/internal/diagnostics/global_exception.hpp" +#include "azure/core/io/body_stream.hpp" +#include "azure/core/response.hpp" +#include "http/curl/curl_connection_pool_private.hpp" +#include "http/curl/curl_connection_private.hpp" +#include "http/curl/curl_session_private.hpp" namespace Azure { namespace Core { namespace Test { TEST(SdkWithLibcurl, globalCleanUp) @@ -57,6 +57,17 @@ namespace Azure { namespace Core { namespace Test { int main(int argc, char** argv) { + // Declare a signal handler to report unhandled exceptions on Windows - this is not needed for + // other OS's as they will print the exception to stderr in their terminate() function. +#if defined(AZ_PLATFORM_WINDOWS) + // Ensure that all calls to abort() no longer pop up a modal dialog on Windows. +#if defined(_DEBUG) && defined(_MSC_VER) + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); +#endif + + signal(SIGABRT, Azure::Core::Diagnostics::_internal::GlobalExceptionHandler::HandleSigAbort); +#endif // AZ_PLATFORM_WINDOWS + testing::InitGoogleTest(&argc, argv); auto r = RUN_ALL_TESTS(); return r; diff --git a/sdk/core/azure-core/test/ut/curl_connection_pool_test.cpp b/sdk/core/azure-core/test/ut/curl_connection_pool_test.cpp index 94dc7fa1ad..6ec133b8ac 100644 --- a/sdk/core/azure-core/test/ut/curl_connection_pool_test.cpp +++ b/sdk/core/azure-core/test/ut/curl_connection_pool_test.cpp @@ -467,7 +467,7 @@ namespace Azure { namespace Core { namespace Test { { // Request with port - std::string const authority(AzureSdkHttpbinServer::WithPort()); + std::string const authority(AzureSdkHttpbinServer::GetWithPort()); Azure::Core::Http::Request req( Azure::Core::Http::HttpMethod::Get, Azure::Core::Url(authority)); std::string const expectedConnectionKey(CreateConnectionKey( @@ -543,7 +543,7 @@ namespace Azure { namespace Core { namespace Test { } { // Request with port - std::string const authority(AzureSdkHttpbinServer::WithPort()); + std::string const authority(AzureSdkHttpbinServer::GetWithPort()); Azure::Core::Http::Request req( Azure::Core::Http::HttpMethod::Get, Azure::Core::Url(authority)); std::string const expectedConnectionKey(CreateConnectionKey( diff --git a/sdk/core/azure-core/test/ut/transport_adapter_base_test.cpp b/sdk/core/azure-core/test/ut/transport_adapter_base_test.cpp index 0da2ce131e..8f34dfe6b7 100644 --- a/sdk/core/azure-core/test/ut/transport_adapter_base_test.cpp +++ b/sdk/core/azure-core/test/ut/transport_adapter_base_test.cpp @@ -311,7 +311,7 @@ namespace Azure { namespace Core { namespace Test { // Test that calling getValue again will return empty result = std::move(responseT.Value); EXPECT_STREQ(result.data(), expectedType.data()); - result = responseT.Value; + result = responseT.Value; // Not 100% sure what this is testing - that std::move works? EXPECT_STREQ(result.data(), std::string("").data()); } @@ -376,6 +376,18 @@ namespace Azure { namespace Core { namespace Test { t1.join(); } + TEST_P(TransportAdapter, cancelRequest) + { + Azure::Core::Url hostPath(AzureSdkHttpbinServer::Delay() + "/10"); // 10 seconds delay on server + Azure::Core::Context cancelThis = Azure::Core::Context::ApplicationContext.WithDeadline( + std::chrono::system_clock::now() + std::chrono::seconds(3)); + + auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, hostPath); + + // Request will be cancelled 3 seconds after sending the request. + EXPECT_THROW(m_pipeline->Send(request, cancelThis), Azure::Core::OperationCancelledException); + } + TEST_P(TransportAdapter, cancelTransferDownload) { // public big blob (321MB) diff --git a/sdk/core/azure-core/test/ut/transport_adapter_base_test.hpp b/sdk/core/azure-core/test/ut/transport_adapter_base_test.hpp index c1aa59a781..6c357ce9fa 100644 --- a/sdk/core/azure-core/test/ut/transport_adapter_base_test.hpp +++ b/sdk/core/azure-core/test/ut/transport_adapter_base_test.hpp @@ -26,36 +26,13 @@ namespace Azure { namespace Core { namespace Test { struct AzureSdkHttpbinServer final { - inline static std::string Get() - { - return std::string(_detail::AzureSdkHttpbinServerSchema) + "://" - + std::string(_detail::AzureSdkHttpbinServer) + "/get"; - } - inline static std::string Headers() - { - return std::string(_detail::AzureSdkHttpbinServerSchema) + "://" - + std::string(_detail::AzureSdkHttpbinServer) + "/headers"; - } - inline static std::string WithPort() - { - return std::string(_detail::AzureSdkHttpbinServerSchema) + "://" - + std::string(_detail::AzureSdkHttpbinServer) + ":443/get"; - } - inline static std::string Put() - { - return std::string(_detail::AzureSdkHttpbinServerSchema) + "://" - + std::string(_detail::AzureSdkHttpbinServer) + "/put"; - } - inline static std::string Delete() - { - return std::string(_detail::AzureSdkHttpbinServerSchema) + "://" - + std::string(_detail::AzureSdkHttpbinServer) + "/delete"; - } - inline static std::string Patch() - { - return std::string(_detail::AzureSdkHttpbinServerSchema) + "://" - + std::string(_detail::AzureSdkHttpbinServer) + "/patch"; - } + inline static std::string Get() { return Schema() + "://" + Host() + "/get"; } + inline static std::string Headers() { return Schema() + "://" + Host() + "/headers"; } + inline static std::string GetWithPort() { return Schema() + "://" + Host() + ":443/get"; } + inline static std::string Put() { return Schema() + "://" + Host() + "/put"; } + inline static std::string Delete() { return Schema() + "://" + Host() + "/delete"; } + inline static std::string Patch() { return Schema() + "://" + Host() + "/patch"; } + inline static std::string Delay() { return Schema() + "://" + Host() + "/delay"; } inline static std::string Host() { return std::string(_detail::AzureSdkHttpbinServer); } inline static std::string Schema() { return std::string(_detail::AzureSdkHttpbinServerSchema); } }; diff --git a/sdk/core/azure-core/test/ut/transport_policy_options.cpp b/sdk/core/azure-core/test/ut/transport_policy_options.cpp index 1c930ca7a2..4483a65155 100644 --- a/sdk/core/azure-core/test/ut/transport_policy_options.cpp +++ b/sdk/core/azure-core/test/ut/transport_policy_options.cpp @@ -526,11 +526,14 @@ namespace Azure { namespace Core { namespace Test { TEST_F(TransportAdapterOptions, MultipleCrlOperations) { + // LetsEncrypt certificates don't contain a distribution point URL extension. While this seems + // to work when run locally, it fails in the CI pipeline. "https://www.wikipedia.org" uses a + // LetsEncrypt certificate, so when testing manually, it is important to add it to the list. std::vector testUrls{ - AzureSdkHttpbinServer::Get(), - "https://twitter.com/", - "https://www.example.com/", - "https://www.google.com/", + AzureSdkHttpbinServer::Get(), // Uses a Microsoft/DigiCert certificate. + "https://aws.amazon.com", // Uses a Amazon/Starfield Technologies certificate. + "https://www.example.com/", // Uses a DigiCert certificate. + "https://www.google.com/", // Uses a google certificate. }; GTEST_LOG_(INFO) << "Basic test calls."; diff --git a/sdk/core/perf/src/program.cpp b/sdk/core/perf/src/program.cpp index 73a68440f7..c788388c72 100644 --- a/sdk/core/perf/src/program.cpp +++ b/sdk/core/perf/src/program.cpp @@ -4,6 +4,7 @@ #include "azure/perf/program.hpp" #include "azure/perf/argagg.hpp" +#include #include #include #include @@ -286,19 +287,10 @@ void Azure::Perf::Program::Run( _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); #endif -// Declare a signal handler to report unhandled exceptions on Windows - this is not needed for other -// OS's as they will print the exception to stderr in their terminate() function. + // Declare a signal handler to report unhandled exceptions on Windows - this is not needed for + // other OS's as they will print the exception to stderr in their terminate() function. #if defined(AZ_PLATFORM_WINDOWS) - signal(SIGABRT, [](int) { - try - { - throw; - } - catch (std::exception const& ex) - { - std::cout << "Exception thrown: " << ex.what() << std::endl; - } - }); + signal(SIGABRT, Azure::Core::Diagnostics::_internal::GlobalExceptionHandler::HandleSigAbort); #endif // AZ_PLATFORM_WINDOWS // Parse args only to get the test name first From 66fd7dabb911e9767c3b3215a27b0491f4a6adba Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Mon, 24 Oct 2022 12:55:30 -0700 Subject: [PATCH 10/21] Updated OpenTelemetry tests to use their own `SpanExporter` rather than depend on the `InMemorySpanExporter`. (#4042) * Removed version override for opentelemetry * Disable deprecation warnings for open telemety tests to guard against future deprecations * Added explanation for 4996 error; removed InMemoryExporter from documentation * Checkpoint adding manual telemetry exporter * Switch from using OpenTelemetry's InMemoryExporter (which is an internal-to-opentelemetry test hook) to our own SpanExporter * removed unused variables because gcc doesn't like them * Fixed doxygen comments * Removed a bunch of unnecessary headers * Update sdk/core/azure-core-tracing-opentelemetry/test/ut/test_exporter.hpp Co-authored-by: Rick Winter Co-authored-by: Rick Winter --- .../test/ut/service_support_test.cpp | 59 ++--- .../test/ut/test_exporter.hpp | 224 ++++++++++++++++++ 2 files changed, 244 insertions(+), 39 deletions(-) create mode 100644 sdk/core/azure-core-tracing-opentelemetry/test/ut/test_exporter.hpp diff --git a/sdk/core/azure-core-tracing-opentelemetry/test/ut/service_support_test.cpp b/sdk/core/azure-core-tracing-opentelemetry/test/ut/service_support_test.cpp index b183fcf3fa..c28ecafa4b 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/test/ut/service_support_test.cpp +++ b/sdk/core/azure-core-tracing-opentelemetry/test/ut/service_support_test.cpp @@ -1,36 +1,22 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT -#define USE_MEMORY_EXPORTER 1 -#include "azure/core/internal/tracing/service_tracing.hpp" -#include "azure/core/tracing/opentelemetry/opentelemetry.hpp" +#include + +#include +#include + #include #include +#include #include +#include -#if defined(_MSC_VER) -// The OpenTelemetry headers generate a couple of warnings on MSVC in the OTel 1.2 package, suppress -// the warnings across the includes. -#pragma warning(push) -#pragma warning(disable : 4100) -#pragma warning(disable : 4244) -#pragma warning(disable : 6323) // Disable "Use of arithmetic operator on Boolean type" warning. -#endif -#include -#include -#include +#include "test_exporter.hpp" // Span Exporter used for OpenTelemetry tests. #include -#include #include #include #include -#include -#if defined(_MSC_VER) -#pragma warning(pop) -#endif -#include -#include -#include using namespace Azure::Core::Http::Policies; using namespace Azure::Core::Http::Policies::_internal; @@ -95,18 +81,13 @@ class CustomLogHandler : public opentelemetry::sdk::common::internal_log::LogHan class OpenTelemetryServiceTests : public Azure::Core::Test::TestBase { private: protected: - std::shared_ptr m_spanData; + std::shared_ptr m_spanData; opentelemetry::nostd::shared_ptr CreateOpenTelemetryProvider() { -#if USE_MEMORY_EXPORTER - auto exporter = std::make_unique(); - m_spanData = exporter->GetData(); -#else - // logging exporter - auto exporter = std::make_unique(); -#endif + auto exporter = std::make_unique(); + m_spanData = exporter->GetTestData(); // simple processor auto simple_processor = std::unique_ptr( @@ -143,7 +124,7 @@ class OpenTelemetryServiceTests : public Azure::Core::Test::TestBase { } bool VerifySpan( - std::unique_ptr const& span, + std::unique_ptr const& span, std::string const& expectedSpanContentsJson) { Azure::Core::Json::_internal::json expectedSpanContents( @@ -199,7 +180,7 @@ class OpenTelemetryServiceTests : public Azure::Core::Test::TestBase { EXPECT_EQ(expectedAttributes.size(), attributes.size()); - for (const auto& foundAttribute : attributes) + for (auto const& foundAttribute : attributes) { EXPECT_TRUE(expectedAttributes.contains(foundAttribute.first)); switch (foundAttribute.second.index()) @@ -219,7 +200,7 @@ class OpenTelemetryServiceTests : public Azure::Core::Test::TestBase { std::regex expectedRegex(expectedVal); GTEST_LOG_(INFO) << "expected Regex: " << expectedVal << std::endl; GTEST_LOG_(INFO) << "actual val: " << actualVal << std::endl; - EXPECT_TRUE(std::regex_match(actualVal, expectedRegex)); + EXPECT_TRUE(std::regex_match(std::string(actualVal), expectedRegex)); break; } case opentelemetry::common::kTypeDouble: { @@ -327,7 +308,7 @@ TEST_F(OpenTelemetryServiceTests, CreateWithExplicitProvider) EXPECT_FALSE(contextAndSpan.Context.IsCancelled()); } // Now let's verify what was logged via OpenTelemetry. - auto spans = m_spanData->GetSpans(); + auto const& spans = m_spanData->ExtractSpans(); EXPECT_EQ(1ul, spans.size()); VerifySpan(spans[0], R"( @@ -367,7 +348,7 @@ TEST_F(OpenTelemetryServiceTests, CreateWithImplicitProvider) } // Now let's verify what was logged via OpenTelemetry. - auto spans = m_spanData->GetSpans(); + auto const& spans = m_spanData->ExtractSpans(); EXPECT_EQ(1ul, spans.size()); VerifySpan(spans[0], R"( @@ -415,7 +396,7 @@ TEST_F(OpenTelemetryServiceTests, CreateSpanWithOptions) } // Now let's verify what was logged via OpenTelemetry. - auto spans = m_spanData->GetSpans(); + auto const& spans = m_spanData->ExtractSpans(); EXPECT_EQ(1ul, spans.size()); VerifySpan(spans[0], R"( @@ -476,7 +457,7 @@ TEST_F(OpenTelemetryServiceTests, NestSpans) } } // Now let's verify what was logged via OpenTelemetry. - auto spans = m_spanData->GetSpans(); + auto const& spans = m_spanData->ExtractSpans(); EXPECT_EQ(2ul, spans.size()); // Because Nested API goes out of scope before My API, it will be logged first in the @@ -676,7 +657,7 @@ TEST_F(OpenTelemetryServiceTests, ServiceApiImplementation) myServiceClient.GetConfigurationString("Fred"); } // Now let's verify what was logged via OpenTelemetry. - auto spans = m_spanData->GetSpans(); + auto const& spans = m_spanData->ExtractSpans(); EXPECT_EQ(2ul, spans.size()); VerifySpan(spans[0], R"( @@ -722,7 +703,7 @@ TEST_F(OpenTelemetryServiceTests, ServiceApiImplementation) myServiceClient.GetConfigurationString("George"); } // Now let's verify what was logged via OpenTelemetry. - auto spans = m_spanData->GetSpans(); + auto const& spans = m_spanData->ExtractSpans(); EXPECT_EQ(0ul, spans.size()); } } diff --git a/sdk/core/azure-core-tracing-opentelemetry/test/ut/test_exporter.hpp b/sdk/core/azure-core-tracing-opentelemetry/test/ut/test_exporter.hpp new file mode 100644 index 0000000000..b3f19084a6 --- /dev/null +++ b/sdk/core/azure-core-tracing-opentelemetry/test/ut/test_exporter.hpp @@ -0,0 +1,224 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +class RecordedSpan : public opentelemetry::sdk::trace::Recordable { + struct Event + { + std::string Name; + std::chrono::system_clock::time_point Timestamp; + opentelemetry::sdk::common::AttributeMap Attributes; + }; + opentelemetry::trace::SpanId m_parentSpan; + opentelemetry::trace::SpanId m_spanId; + opentelemetry::sdk::common::AttributeMap m_attributes; + std::vector m_events; + opentelemetry::trace::StatusCode m_statusCode{}; + std::string m_statusDescription; + std::string m_name; + opentelemetry::trace::SpanKind m_spanKind{}; + std::chrono::system_clock::time_point m_startTime; + std::chrono::nanoseconds m_duration{}; + std::unique_ptr m_scope; + std::unique_ptr m_resource; + +public: + ~RecordedSpan() = default; + + /** + * Set the span context and parent span id + * @param span_context the span context to set + * @param parent_span_id the parent span id to set + */ + void SetIdentity( + const opentelemetry::trace::SpanContext& span_context, + opentelemetry::trace::SpanId parent_span_id) noexcept override + { + m_parentSpan = parent_span_id; + m_spanId = span_context.span_id(); + }; + + /** + * Set an attribute of a span. + * @param key the name of the attribute + * @param value the attribute value + */ + void SetAttribute( + opentelemetry::nostd::string_view key, + const opentelemetry::common::AttributeValue& value) noexcept override + { + m_attributes.SetAttribute(key, value); + }; + + /** + * Add an event to a span. + * @param name the name of the event + * @param timestamp the timestamp of the event + * @param attributes the attributes associated with the event + */ + void AddEvent( + opentelemetry::nostd::string_view name, + opentelemetry::common::SystemTimestamp timestamp, + const opentelemetry::common::KeyValueIterable& attributes) noexcept override + { + Event event; + event.Name = std::string(name); + event.Timestamp = timestamp; + + attributes.ForEachKeyValue( + [&event]( + opentelemetry::nostd::string_view name, opentelemetry::common::AttributeValue value) { + event.Attributes.SetAttribute(name, value); + return true; + }); + m_events.push_back(event); + }; + + /** + * Add a link to a span. + */ + void AddLink( + const opentelemetry::trace::SpanContext&, + const opentelemetry::common::KeyValueIterable&) noexcept override{ + // TODO, when we use this, we need to test this. + // NO-OP since this exporter silences link data. + }; + + /** + * Set the status of the span. + * @param code the status code + * @param description a description of the status + */ + void SetStatus( + opentelemetry::trace::StatusCode code, + opentelemetry::nostd::string_view description) noexcept override + { + m_statusCode = code; + m_statusDescription = std::string(description); + }; + + /** + * Set the name of the span. + * @param name the name to set + */ + void SetName(opentelemetry::nostd::string_view name) noexcept override + { + m_name = std::string(name); + }; + + /** + * Set the spankind of the span. + * @param span_kind the spankind to set + */ + void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override + { + m_spanKind = span_kind; + }; + + /** + * Set Resource of the span + * @param resource the resource to set + */ + void SetResource(const opentelemetry::sdk::resource::Resource& resource) noexcept override + { + m_resource = std::make_unique(resource); + }; + + /** + * Set the start time of the span. + * @param start_time the start time to set + */ + void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept override + { + m_startTime = start_time; + }; + + /** + * Set the duration of the span. + * @param duration the duration to set + */ + void SetDuration(std::chrono::nanoseconds duration) noexcept override { m_duration = duration; } + + /** + * Set the instrumentation scope of the span. + * @param instrumentation_scope the instrumentation scope to set + */ + void SetInstrumentationScope(const opentelemetry::sdk::instrumentationscope::InstrumentationScope& + instrumentation_scope) noexcept override + { + m_scope = std::make_unique( + instrumentation_scope); + }; + + std::string GetName() { return m_name; } + opentelemetry::trace::StatusCode GetStatus() { return m_statusCode; } + opentelemetry::trace::SpanId GetParentSpanId() { return m_parentSpan; } + opentelemetry::trace::SpanKind GetSpanKind() { return m_spanKind; } + opentelemetry::trace::SpanId GetSpanId() { return m_spanId; } + opentelemetry::sdk::common::AttributeMap const& GetAttributes() { return m_attributes; } + opentelemetry::sdk::instrumentationscope::InstrumentationScope& GetInstrumentationScope() + { + return *m_scope; + } +}; + +class TestExporter final : public opentelemetry::sdk::trace::SpanExporter { + +public: + class TestData { + std::vector> m_spans; + + public: + // Returns a copy of the recorded spans and clears the set of recorded spans. + std::vector> const ExtractSpans() { return std::move(m_spans); } + void AddSpan(std::unique_ptr&& span) { m_spans.push_back(std::move(span)); } + }; + std::shared_ptr const& GetTestData() { return m_testData; } + + TestExporter() : m_testData{std::make_shared()} {} + virtual ~TestExporter() = default; + + /** + * Create a span recordable. This object will be used to record span data and + * will subsequently be passed to SpanExporter::Export. Vendors can implement + * custom recordables or use the default SpanData recordable provided by the + * SDK. + * @return a newly initialized Recordable object + * + * Note: This method must be callable from multiple threads. + */ + std::unique_ptr MakeRecordable() noexcept override + { + return std::unique_ptr(new (std::nothrow) RecordedSpan); + } + + /** + * Exports a batch of span recordables. This method must not be called + * concurrently for the same exporter instance. + * @param spans a span of unique pointers to span recordables + */ + opentelemetry::sdk::common::ExportResult Export( + const opentelemetry::nostd::span>& + spans) noexcept override + { + for (auto& recordable : spans) + { + auto span = std::unique_ptr(static_cast(recordable.release())); + m_testData->AddSpan(std::move(span)); + } + return opentelemetry::sdk::common::ExportResult::kSuccess; + } + + /** + * Shut down the exporter. + * @return return the status of the operation. + */ + bool Shutdown(std::chrono::microseconds) noexcept override { return true; } + +private: + std::shared_ptr m_testData; +}; From fd24627a82b1b37f61ede1b923fb96ab168fd28a Mon Sep 17 00:00:00 2001 From: Mike Harder Date: Tue, 25 Oct 2022 11:20:16 -0700 Subject: [PATCH 11/21] [Perf] Include GA versions of core package (#4053) --- sdk/core/perf.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/core/perf.yml b/sdk/core/perf.yml index 6708e23dfa..cb2fc9cc3f 100644 --- a/sdk/core/perf.yml +++ b/sdk/core/perf.yml @@ -2,7 +2,7 @@ parameters: - name: PackageVersions displayName: PackageVersions (regex of package versions to run) type: string - default: 'source' + default: '1|source' - name: Tests displayName: Tests (regex of tests to run) type: string From 34485a7ab78aaa5c914cf7c52ba43142e17701fb Mon Sep 17 00:00:00 2001 From: Rick Winter Date: Tue, 25 Oct 2022 11:37:25 -0700 Subject: [PATCH 12/21] Fix to for a SAL annotation (#4054) --- sdk/core/azure-core/src/http/winhttp/win_http_request.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/core/azure-core/src/http/winhttp/win_http_request.hpp b/sdk/core/azure-core/src/http/winhttp/win_http_request.hpp index 41c3b694ec..d067e103c0 100644 --- a/sdk/core/azure-core/src/http/winhttp/win_http_request.hpp +++ b/sdk/core/azure-core/src/http/winhttp/win_http_request.hpp @@ -15,7 +15,10 @@ #include #include #include +#pragma warning(push) +#pragma warning(disable : 6553) #include +#pragma warning(pop) #include namespace Azure { namespace Core { namespace Http { namespace _detail { From 4de2423934cc5526bcca9439d5e643052d3201db Mon Sep 17 00:00:00 2001 From: Anton Kolesnyk <41349689+antkmsft@users.noreply.github.com> Date: Tue, 25 Oct 2022 13:23:22 -0700 Subject: [PATCH 13/21] In-memory Identity token cache (#4024) --- sdk/core/azure-core/CHANGELOG.md | 2 + .../azure/core/credentials/credentials.hpp | 8 + .../bearer_token_authentication_policy.cpp | 4 +- sdk/identity/azure-identity/CHANGELOG.md | 2 + sdk/identity/azure-identity/CMakeLists.txt | 6 + .../identity/client_secret_credential.hpp | 19 +- .../identity/managed_identity_credential.hpp | 2 + .../src/client_secret_credential.cpp | 89 ++-- .../src/managed_identity_source.cpp | 254 ++++++---- .../src/private/managed_identity_source.hpp | 16 +- .../src/private/token_cache.hpp | 62 +++ .../src/private/token_cache_internals.hpp | 88 ++++ .../azure-identity/src/token_cache.cpp | 154 ++++++ .../azure-identity/test/ut/CMakeLists.txt | 1 + .../test/ut/credential_test_helper.cpp | 3 + .../test/ut/token_cache_test.cpp | 450 ++++++++++++++++++ .../test/ut/token_credential_impl_test.cpp | 5 + .../test/ut/token_credential_test.cpp | 6 + 18 files changed, 1043 insertions(+), 128 deletions(-) create mode 100644 sdk/identity/azure-identity/src/private/token_cache.hpp create mode 100644 sdk/identity/azure-identity/src/private/token_cache_internals.hpp create mode 100644 sdk/identity/azure-identity/src/token_cache.cpp create mode 100644 sdk/identity/azure-identity/test/ut/token_cache_test.cpp diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index 2baa79229b..abc9f97fcc 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -10,6 +10,8 @@ ### Other Changes +- Added support for Identity token caching, and for configuring token refresh offset in `BearerTokenAuthenticationPolicy`. + ## 1.8.0-beta.1 (2022-10-06) ### Features Added diff --git a/sdk/core/azure-core/inc/azure/core/credentials/credentials.hpp b/sdk/core/azure-core/inc/azure/core/credentials/credentials.hpp index 94a033eebb..27a9e62d33 100644 --- a/sdk/core/azure-core/inc/azure/core/credentials/credentials.hpp +++ b/sdk/core/azure-core/inc/azure/core/credentials/credentials.hpp @@ -48,6 +48,12 @@ namespace Azure { namespace Core { namespace Credentials { * */ std::vector Scopes; + + /** + * @brief Minimum token expiration suggestion. + * + */ + DateTime::duration MinimumExpiration = std::chrono::minutes(2); }; /** @@ -61,6 +67,8 @@ namespace Azure { namespace Core { namespace Credentials { * @param tokenRequestContext A context to get the token in. * @param context A context to control the request lifetime. * + * @return Authentication token. + * * @throw Azure::Core::Credentials::AuthenticationException Authentication error occurred. */ virtual AccessToken GetToken( diff --git a/sdk/core/azure-core/src/http/bearer_token_authentication_policy.cpp b/sdk/core/azure-core/src/http/bearer_token_authentication_policy.cpp index 46a71a58b7..7099584f4d 100644 --- a/sdk/core/azure-core/src/http/bearer_token_authentication_policy.cpp +++ b/sdk/core/azure-core/src/http/bearer_token_authentication_policy.cpp @@ -18,8 +18,8 @@ std::unique_ptr BearerTokenAuthenticationPolicy::Send( { std::lock_guard lock(m_accessTokenMutex); - // Refresh the token in 2 or less minutes before the actual expiration. - if (std::chrono::system_clock::now() > (m_accessToken.ExpiresOn - std::chrono::minutes(2))) + if (std::chrono::system_clock::now() + > (m_accessToken.ExpiresOn - m_tokenRequestContext.MinimumExpiration)) { m_accessToken = m_credential->GetToken(m_tokenRequestContext, context); } diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index 14e620b1d6..552e371cc4 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -4,6 +4,8 @@ ### Features Added +- Added token caching. + ### Breaking Changes ### Bugs Fixed diff --git a/sdk/identity/azure-identity/CMakeLists.txt b/sdk/identity/azure-identity/CMakeLists.txt index 8cc8f7414c..6b686d6337 100644 --- a/sdk/identity/azure-identity/CMakeLists.txt +++ b/sdk/identity/azure-identity/CMakeLists.txt @@ -60,6 +60,8 @@ set( AZURE_IDENTITY_SOURCE src/private/managed_identity_source.hpp src/private/package_version.hpp + src/private/token_cache.hpp + src/private/token_cache_internals.hpp src/private/token_credential_impl.hpp src/chained_token_credential.cpp src/client_certificate_credential.cpp @@ -67,6 +69,7 @@ set( src/environment_credential.cpp src/managed_identity_credential.cpp src/managed_identity_source.cpp + src/token_cache.cpp src/token_credential_impl.cpp ) @@ -106,6 +109,9 @@ az_rtti_setup( ) if(BUILD_TESTING) + # define a symbol that enables some test hooks in code + add_compile_definitions(TESTING_BUILD) + # tests if (NOT AZ_ALL_LIBRARIES OR FETCH_SOURCE_DEPS) include(AddGoogleTest) diff --git a/sdk/identity/azure-identity/inc/azure/identity/client_secret_credential.hpp b/sdk/identity/azure-identity/inc/azure/identity/client_secret_credential.hpp index 8e1d43b02d..206c77108e 100644 --- a/sdk/identity/azure-identity/inc/azure/identity/client_secret_credential.hpp +++ b/sdk/identity/azure-identity/inc/azure/identity/client_secret_credential.hpp @@ -51,13 +51,18 @@ namespace Azure { namespace Identity { std::unique_ptr<_detail::TokenCredentialImpl> m_tokenCredentialImpl; Core::Url m_requestUrl; std::string m_requestBody; + + std::string m_tenantId; + std::string m_clientId; + std::string m_authorityHost; + bool m_isAdfs; ClientSecretCredential( - std::string const& tenantId, - std::string const& clientId, + std::string tenantId, + std::string clientId, std::string const& clientSecret, - std::string const& authorityHost, + std::string authorityHost, Core::Credentials::TokenCredentialOptions const& options); public: @@ -70,8 +75,8 @@ namespace Azure { namespace Identity { * @param options Options for token retrieval. */ explicit ClientSecretCredential( - std::string const& tenantId, - std::string const& clientId, + std::string tenantId, + std::string clientId, std::string const& clientSecret, ClientSecretCredentialOptions const& options); @@ -86,7 +91,7 @@ namespace Azure { namespace Identity { explicit ClientSecretCredential( std::string tenantId, std::string clientId, - std::string clientSecret, + std::string const& clientSecret, Core::Credentials::TokenCredentialOptions const& options = Core::Credentials::TokenCredentialOptions()); @@ -102,6 +107,8 @@ namespace Azure { namespace Identity { * @param tokenRequestContext A context to get the token in. * @param context A context to control the request lifetime. * + * @return Authentication token. + * * @throw Azure::Core::Credentials::AuthenticationException Authentication error occurred. */ Core::Credentials::AccessToken GetToken( diff --git a/sdk/identity/azure-identity/inc/azure/identity/managed_identity_credential.hpp b/sdk/identity/azure-identity/inc/azure/identity/managed_identity_credential.hpp index 3e4863ec5c..0017bd8817 100644 --- a/sdk/identity/azure-identity/inc/azure/identity/managed_identity_credential.hpp +++ b/sdk/identity/azure-identity/inc/azure/identity/managed_identity_credential.hpp @@ -59,6 +59,8 @@ namespace Azure { namespace Identity { * @param tokenRequestContext A context to get the token in. * @param context A context to control the request lifetime. * + * @return Authentication token. + * * @throw Azure::Core::Credentials::AuthenticationException Authentication error occurred. */ Core::Credentials::AccessToken GetToken( diff --git a/sdk/identity/azure-identity/src/client_secret_credential.cpp b/sdk/identity/azure-identity/src/client_secret_credential.cpp index 5b04416c59..78cdac88a0 100644 --- a/sdk/identity/azure-identity/src/client_secret_credential.cpp +++ b/sdk/identity/azure-identity/src/client_secret_credential.cpp @@ -3,9 +3,11 @@ #include "azure/identity/client_secret_credential.hpp" +#include "private/token_cache.hpp" #include "private/token_credential_impl.hpp" #include +#include using namespace Azure::Identity; @@ -13,29 +15,33 @@ std::string const Azure::Identity::_detail::g_aadGlobalAuthority = "https://login.microsoftonline.com/"; ClientSecretCredential::ClientSecretCredential( - std::string const& tenantId, - std::string const& clientId, + std::string tenantId, + std::string clientId, std::string const& clientSecret, - std::string const& authorityHost, + std::string authorityHost, Azure::Core::Credentials::TokenCredentialOptions const& options) : m_tokenCredentialImpl(std::make_unique<_detail::TokenCredentialImpl>(options)), - m_isAdfs(tenantId == "adfs") + m_tenantId(std::move(tenantId)), m_clientId(std::move(clientId)), + m_authorityHost(std::move(authorityHost)) { using Azure::Core::Url; - m_requestUrl = Url(authorityHost); - m_requestUrl.AppendPath(tenantId); + + m_isAdfs = (m_tenantId == "adfs"); + + m_requestUrl = Url(m_authorityHost); + m_requestUrl.AppendPath(m_tenantId); m_requestUrl.AppendPath(m_isAdfs ? "oauth2/token" : "oauth2/v2.0/token"); std::ostringstream body; - body << "grant_type=client_credentials&client_id=" << Url::Encode(clientId) + body << "grant_type=client_credentials&client_id=" << Url::Encode(m_clientId) << "&client_secret=" << Url::Encode(clientSecret); m_requestBody = body.str(); } ClientSecretCredential::ClientSecretCredential( - std::string const& tenantId, - std::string const& clientId, + std::string tenantId, + std::string clientId, std::string const& clientSecret, ClientSecretCredentialOptions const& options) : ClientSecretCredential(tenantId, clientId, clientSecret, options.AuthorityHost, options) @@ -45,7 +51,7 @@ ClientSecretCredential::ClientSecretCredential( ClientSecretCredential::ClientSecretCredential( std::string tenantId, std::string clientId, - std::string clientSecret, + std::string const& clientSecret, Core::Credentials::TokenCredentialOptions const& options) : ClientSecretCredential( tenantId, @@ -62,28 +68,49 @@ Azure::Core::Credentials::AccessToken ClientSecretCredential::GetToken( Azure::Core::Credentials::TokenRequestContext const& tokenRequestContext, Azure::Core::Context const& context) const { - return m_tokenCredentialImpl->GetToken(context, [&]() { - using _detail::TokenCredentialImpl; - using Azure::Core::Http::HttpMethod; - - std::ostringstream body; - body << m_requestBody; - { - auto const& scopes = tokenRequestContext.Scopes; - if (!scopes.empty()) - { - body << "&scope=" << TokenCredentialImpl::FormatScopes(scopes, m_isAdfs); - } - } - - auto request = std::make_unique( - HttpMethod::Post, m_requestUrl, body.str()); + using _detail::TokenCache; + using _detail::TokenCredentialImpl; - if (m_isAdfs) + std::string scopesStr; + { + auto const& scopes = tokenRequestContext.Scopes; + if (!scopes.empty()) { - request->HttpRequest.SetHeader("Host", m_requestUrl.GetHost()); + scopesStr = TokenCredentialImpl::FormatScopes(scopes, m_isAdfs); } - - return request; - }); + } + + // TokenCache::GetToken() and m_tokenCredentialImpl->GetToken() can only use the lambda argument + // when they are being executed. They are not supposed to keep a reference to lambda argument to + // call it later. Therefore, any capture made here will outlive the possible time frame when the + // lambda might get called. + return TokenCache::GetToken( + m_tenantId, + m_clientId, + m_authorityHost, + scopesStr, + tokenRequestContext.MinimumExpiration, + [&]() { + return m_tokenCredentialImpl->GetToken(context, [&]() { + using Azure::Core::Http::HttpMethod; + + std::ostringstream body; + body << m_requestBody; + + if (!scopesStr.empty()) + { + body << "&scope=" << scopesStr; + } + + auto request = std::make_unique( + HttpMethod::Post, m_requestUrl, body.str()); + + if (m_isAdfs) + { + request->HttpRequest.SetHeader("Host", m_requestUrl.GetHost()); + } + + return request; + }); + }); } diff --git a/sdk/identity/azure-identity/src/managed_identity_source.cpp b/sdk/identity/azure-identity/src/managed_identity_source.cpp index 56fbf51273..3dcb4d38ad 100644 --- a/sdk/identity/azure-identity/src/managed_identity_source.cpp +++ b/sdk/identity/azure-identity/src/managed_identity_source.cpp @@ -3,6 +3,8 @@ #include "private/managed_identity_source.hpp" +#include "private/token_cache.hpp" + #include #include @@ -59,7 +61,7 @@ AppServiceManagedIdentitySource::AppServiceManagedIdentitySource( std::string const& apiVersion, std::string const& secretHeaderName, std::string const& clientIdHeaderName) - : ManagedIdentitySource(options), + : ManagedIdentitySource(clientId, endpointUrl.GetHost(), options), m_request(Azure::Core::Http::HttpMethod::Get, std::move(endpointUrl)) { { @@ -81,18 +83,37 @@ Azure::Core::Credentials::AccessToken AppServiceManagedIdentitySource::GetToken( Azure::Core::Credentials::TokenRequestContext const& tokenRequestContext, Azure::Core::Context const& context) const { - return TokenCredentialImpl::GetToken(context, [&]() { - auto request = std::make_unique(m_request); + std::string scopesStr; + { + auto const& scopes = tokenRequestContext.Scopes; + if (!scopes.empty()) { - auto const& scopes = tokenRequestContext.Scopes; - if (!scopes.empty()) - { - request->HttpRequest.GetUrl().AppendQueryParameter("resource", FormatScopes(scopes, true)); - } + scopesStr = TokenCredentialImpl::FormatScopes(scopes, true); } + } - return request; - }); + // TokenCache::GetToken() and TokenCredentialImpl::GetToken() can only use the lambda argument + // when they are being executed. They are not supposed to keep a reference to lambda argument to + // call it later. Therefore, any capture made here will outlive the possible time frame when the + // lambda might get called. + return TokenCache::GetToken( + std::string(), + GetClientId(), + GetAuthorityHost(), + scopesStr, + tokenRequestContext.MinimumExpiration, + [&]() { + return TokenCredentialImpl::GetToken(context, [&]() { + auto request = std::make_unique(m_request); + + if (!scopesStr.empty()) + { + request->HttpRequest.GetUrl().AppendQueryParameter("resource", scopesStr); + } + + return request; + }); + }); } std::unique_ptr AppServiceV2017ManagedIdentitySource::Create( @@ -128,7 +149,7 @@ CloudShellManagedIdentitySource::CloudShellManagedIdentitySource( std::string const& clientId, Azure::Core::Credentials::TokenCredentialOptions const& options, Azure::Core::Url endpointUrl) - : ManagedIdentitySource(options), m_url(std::move(endpointUrl)) + : ManagedIdentitySource(clientId, endpointUrl.GetHost(), options), m_url(std::move(endpointUrl)) { using Azure::Core::Url; if (!clientId.empty()) @@ -141,28 +162,47 @@ Azure::Core::Credentials::AccessToken CloudShellManagedIdentitySource::GetToken( Azure::Core::Credentials::TokenRequestContext const& tokenRequestContext, Azure::Core::Context const& context) const { - return TokenCredentialImpl::GetToken(context, [&]() { - using Azure::Core::Url; - using Azure::Core::Http::HttpMethod; - - std::string resource; + std::string scopesStr; + { + auto const& scopes = tokenRequestContext.Scopes; + if (!scopes.empty()) { - auto const& scopes = tokenRequestContext.Scopes; - if (!scopes.empty()) - { - resource = "resource=" + FormatScopes(scopes, true); - if (!m_body.empty()) - { - resource += "&"; - } - } + scopesStr = TokenCredentialImpl::FormatScopes(scopes, true); } + } - auto request = std::make_unique(HttpMethod::Post, m_url, resource + m_body); - request->HttpRequest.SetHeader("Metadata", "true"); - - return request; - }); + // TokenCache::GetToken() and TokenCredentialImpl::GetToken() can only use the lambda argument + // when they are being executed. They are not supposed to keep a reference to lambda argument to + // call it later. Therefore, any capture made here will outlive the possible time frame when the + // lambda might get called. + return TokenCache::GetToken( + std::string(), + GetClientId(), + GetAuthorityHost(), + scopesStr, + tokenRequestContext.MinimumExpiration, + [&]() { + return TokenCredentialImpl::GetToken(context, [&]() { + using Azure::Core::Url; + using Azure::Core::Http::HttpMethod; + + std::string resource; + + if (!scopesStr.empty()) + { + resource = "resource=" + scopesStr; + if (!m_body.empty()) + { + resource += "&"; + } + } + + auto request = std::make_unique(HttpMethod::Post, m_url, resource + m_body); + request->HttpRequest.SetHeader("Metadata", "true"); + + return request; + }); + }); } std::unique_ptr AzureArcManagedIdentitySource::Create( @@ -194,7 +234,8 @@ std::unique_ptr AzureArcManagedIdentitySource::Create( AzureArcManagedIdentitySource::AzureArcManagedIdentitySource( Azure::Core::Credentials::TokenCredentialOptions const& options, Azure::Core::Url endpointUrl) - : ManagedIdentitySource(options), m_url(std::move(endpointUrl)) + : ManagedIdentitySource(std::string(), endpointUrl.GetHost(), options), + m_url(std::move(endpointUrl)) { m_url.AppendQueryParameter("api-version", "2019-11-01"); @@ -204,6 +245,15 @@ Azure::Core::Credentials::AccessToken AzureArcManagedIdentitySource::GetToken( Azure::Core::Credentials::TokenRequestContext const& tokenRequestContext, Azure::Core::Context const& context) const { + std::string scopesStr; + { + auto const& scopes = tokenRequestContext.Scopes; + if (!scopes.empty()) + { + scopesStr = TokenCredentialImpl::FormatScopes(scopes, true); + } + } + auto const createRequest = [&]() { using Azure::Core::Http::HttpMethod; using Azure::Core::Http::Request; @@ -212,59 +262,70 @@ Azure::Core::Credentials::AccessToken AzureArcManagedIdentitySource::GetToken( { auto& httpRequest = request->HttpRequest; httpRequest.SetHeader("Metadata", "true"); + + if (!scopesStr.empty()) { - auto const& scopes = tokenRequestContext.Scopes; - if (!scopes.empty()) - { - httpRequest.GetUrl().AppendQueryParameter("resource", FormatScopes(scopes, true)); - } + httpRequest.GetUrl().AppendQueryParameter("resource", scopesStr); } } return request; }; - return TokenCredentialImpl::GetToken( - context, - createRequest, - [&](auto const statusCode, auto const& response) -> std::unique_ptr { - using Core::Credentials::AuthenticationException; - using Core::Http::HttpStatusCode; - - if (statusCode != HttpStatusCode::Unauthorized) - { - return nullptr; - } - - auto const& headers = response.GetHeaders(); - auto authHeader = headers.find("WWW-Authenticate"); - if (authHeader == headers.end()) - { - throw AuthenticationException( - "Did not receive expected WWW-Authenticate header " - "in the response from Azure Arc Managed Identity Endpoint."); - } - - constexpr auto ChallengeValueSeparator = '='; - auto const& challenge = authHeader->second; - auto eq = challenge.find(ChallengeValueSeparator); - if (eq == std::string::npos - || challenge.find(ChallengeValueSeparator, eq + 1) != std::string::npos) - { - throw AuthenticationException("The WWW-Authenticate header in the response from Azure " - "Arc Managed Identity Endpoint " - "did not match the expected format."); - } - - auto request = createRequest(); - std::ifstream secretFile(challenge.substr(eq + 1)); - request->HttpRequest.SetHeader( - "Authorization", - "Basic " - + std::string( - std::istreambuf_iterator(secretFile), std::istreambuf_iterator())); - - return request; + // TokenCache::GetToken() and TokenCredentialImpl::GetToken() can only use the lambda argument + // when they are being executed. They are not supposed to keep a reference to lambda argument to + // call it later. Therefore, any capture made here will outlive the possible time frame when the + // lambda might get called. + return TokenCache::GetToken( + std::string(), + GetClientId(), + GetAuthorityHost(), + scopesStr, + tokenRequestContext.MinimumExpiration, + [&]() { + return TokenCredentialImpl::GetToken( + context, + createRequest, + [&](auto const statusCode, auto const& response) -> std::unique_ptr { + using Core::Credentials::AuthenticationException; + using Core::Http::HttpStatusCode; + + if (statusCode != HttpStatusCode::Unauthorized) + { + return nullptr; + } + + auto const& headers = response.GetHeaders(); + auto authHeader = headers.find("WWW-Authenticate"); + if (authHeader == headers.end()) + { + throw AuthenticationException( + "Did not receive expected WWW-Authenticate header " + "in the response from Azure Arc Managed Identity Endpoint."); + } + + constexpr auto ChallengeValueSeparator = '='; + auto const& challenge = authHeader->second; + auto eq = challenge.find(ChallengeValueSeparator); + if (eq == std::string::npos + || challenge.find(ChallengeValueSeparator, eq + 1) != std::string::npos) + { + throw AuthenticationException( + "The WWW-Authenticate header in the response from Azure Arc " + "Managed Identity Endpoint did not match the expected format."); + } + + auto request = createRequest(); + std::ifstream secretFile(challenge.substr(eq + 1)); + request->HttpRequest.SetHeader( + "Authorization", + "Basic " + + std::string( + std::istreambuf_iterator(secretFile), + std::istreambuf_iterator())); + + return request; + }); }); } @@ -278,7 +339,7 @@ std::unique_ptr ImdsManagedIdentitySource::Create( ImdsManagedIdentitySource::ImdsManagedIdentitySource( std::string const& clientId, Azure::Core::Credentials::TokenCredentialOptions const& options) - : ManagedIdentitySource(options), + : ManagedIdentitySource(clientId, std::string(), options), m_request( Azure::Core::Http::HttpMethod::Get, Azure::Core::Url("http://169.254.169.254/metadata/identity/oauth2/token")) @@ -302,16 +363,35 @@ Azure::Core::Credentials::AccessToken ImdsManagedIdentitySource::GetToken( Azure::Core::Credentials::TokenRequestContext const& tokenRequestContext, Azure::Core::Context const& context) const { - return TokenCredentialImpl::GetToken(context, [&]() { - auto request = std::make_unique(m_request); + std::string scopesStr; + { + auto const& scopes = tokenRequestContext.Scopes; + if (!scopes.empty()) { - auto const& scopes = tokenRequestContext.Scopes; - if (!scopes.empty()) - { - request->HttpRequest.GetUrl().AppendQueryParameter("resource", FormatScopes(scopes, true)); - } + scopesStr = TokenCredentialImpl::FormatScopes(scopes, true); } + } - return request; - }); + // TokenCache::GetToken() and TokenCredentialImpl::GetToken() can only use the lambda argument + // when they are being executed. They are not supposed to keep a reference to lambda argument to + // call it later. Therefore, any capture made here will outlive the possible time frame when the + // lambda might get called. + return TokenCache::GetToken( + std::string(), + GetClientId(), + GetAuthorityHost(), + scopesStr, + tokenRequestContext.MinimumExpiration, + [&]() { + return TokenCredentialImpl::GetToken(context, [&]() { + auto request = std::make_unique(m_request); + + if (!scopesStr.empty()) + { + request->HttpRequest.GetUrl().AppendQueryParameter("resource", scopesStr); + } + + return request; + }); + }); } diff --git a/sdk/identity/azure-identity/src/private/managed_identity_source.hpp b/sdk/identity/azure-identity/src/private/managed_identity_source.hpp index 40d66fc589..04ec7b6a70 100644 --- a/sdk/identity/azure-identity/src/private/managed_identity_source.hpp +++ b/sdk/identity/azure-identity/src/private/managed_identity_source.hpp @@ -11,9 +11,14 @@ #include #include +#include namespace Azure { namespace Identity { namespace _detail { class ManagedIdentitySource : protected TokenCredentialImpl { + private: + std::string m_clientId; + std::string m_authorityHost; + public: virtual Core::Credentials::AccessToken GetToken( Core::Credentials::TokenRequestContext const& tokenRequestContext, @@ -22,10 +27,17 @@ namespace Azure { namespace Identity { namespace _detail { protected: static Core::Url ParseEndpointUrl(std::string const& url, char const* envVarName); - explicit ManagedIdentitySource(Core::Credentials::TokenCredentialOptions const& options) - : TokenCredentialImpl(options) + explicit ManagedIdentitySource( + std::string clientId, + std::string authorityHost, + Core::Credentials::TokenCredentialOptions const& options) + : TokenCredentialImpl(options), m_clientId(std::move(clientId)), + m_authorityHost(std::move(authorityHost)) { } + + std::string const& GetClientId() const { return m_clientId; } + std::string const& GetAuthorityHost() const { return m_authorityHost; } }; class AppServiceManagedIdentitySource : public ManagedIdentitySource { diff --git a/sdk/identity/azure-identity/src/private/token_cache.hpp b/sdk/identity/azure-identity/src/private/token_cache.hpp new file mode 100644 index 0000000000..fa88a2b125 --- /dev/null +++ b/sdk/identity/azure-identity/src/private/token_cache.hpp @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/** + * @file + * @brief Token cache. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace Azure { namespace Identity { namespace _detail { + /** + * @brief Implements an access token cache. + * + */ + class TokenCache final { + TokenCache() = delete; + ~TokenCache() = delete; + + public: + /** + * @brief Attempts to get token from cache, and if not found, gets the token using the function + * provided, caches it, and returns its value. + * + * @param tenantId Azure Tenant ID. + * @param clientId Azure Client ID. + * @param authorityHost Authentication authority URL. + * @param scopes Authentication scopes. + * + * @return Authentication token. + * + * @throw Azure::Core::Credentials::AuthenticationException Authentication error occurred. + */ + static Core::Credentials::AccessToken GetToken( + std::string const& tenantId, + std::string const& clientId, + std::string const& authorityHost, + std::string const& scopes, + DateTime::duration minimumExpiration, + std::function const& getNewToken); + + /** + * @brief Provides access to internal aspects of the cache as a test hook. + * + */ + class Internals; + +#if defined(TESTING_BUILD) + /** + * @brief Clears token cache. Intended to only be used in tests. + * + */ + static void Clear(); +#endif + }; +}}} // namespace Azure::Identity::_detail diff --git a/sdk/identity/azure-identity/src/private/token_cache_internals.hpp b/sdk/identity/azure-identity/src/private/token_cache_internals.hpp new file mode 100644 index 0000000000..d3d67b30f6 --- /dev/null +++ b/sdk/identity/azure-identity/src/private/token_cache_internals.hpp @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/** + * @file + * @brief Token cache internals and test hooks. + */ + +#pragma once + +#include "token_cache.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +namespace Azure { namespace Identity { namespace _detail { + /** + * @brief Implements internal aspects of token cache and provides test hooks. + * + */ + class TokenCache::Internals final { + Internals() = delete; + ~Internals() = delete; + + public: + /** + * @brief Represents a unique set of characteristics that are used to distinguish between cache + * entries. + * + */ + struct CacheKey final + { + std::string TenantId; ///< Tenant ID. + std::string ClientId; ///< Client ID. + std::string AuthorityHost; ///< Authority Host. + std::string Scopes; ///< Authentication Scopes as a single string. + + bool operator<(TokenCache::Internals::CacheKey const& other) const + { + return std::tie(TenantId, ClientId, AuthorityHost, Scopes) + < std::tie(other.TenantId, other.ClientId, other.AuthorityHost, other.Scopes); + } + }; + + /** + * @brief Represents immediate cache value (token) and a synchronization primitive to handle its + * updates. + * + */ + struct CacheValue final + { + std::shared_timed_mutex ElementMutex; + Core::Credentials::AccessToken AccessToken; + }; + + /** + * @brief The cache itself. + * + */ + static std::map> Cache; + + /** + * @brief Mutex to access the cache container. + * + */ + static std::shared_timed_mutex CacheMutex; + +#if defined(TESTING_BUILD) + /** + * A test hook that gets invoked before cache write lock gets acquired. + * + */ + static std::function OnBeforeCacheWriteLock; + + /** + * A test hook that gets invoked before item write lock gets acquired. + * + */ + static std::function OnBeforeItemWriteLock; +#endif + }; +}}} // namespace Azure::Identity::_detail diff --git a/sdk/identity/azure-identity/src/token_cache.cpp b/sdk/identity/azure-identity/src/token_cache.cpp new file mode 100644 index 0000000000..4f88476e8e --- /dev/null +++ b/sdk/identity/azure-identity/src/token_cache.cpp @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include "private/token_cache.hpp" +#include "private/token_cache_internals.hpp" + +#include +#include + +using Azure::Identity::_detail::TokenCache; + +using Azure::DateTime; +using Azure::Core::Credentials::AccessToken; + +decltype(TokenCache::Internals::Cache) TokenCache::Internals::Cache; +decltype(TokenCache::Internals::CacheMutex) TokenCache::Internals::CacheMutex; + +#if defined(TESTING_BUILD) +std::function TokenCache::Internals::OnBeforeCacheWriteLock; +std::function TokenCache::Internals::OnBeforeItemWriteLock; +#endif + +namespace { +bool IsFresh( + std::shared_ptr const& item, + DateTime::duration minimumExpiration, + std::chrono::system_clock::time_point now) +{ + return item->AccessToken.ExpiresOn > (DateTime(now) + minimumExpiration); +} + +std::shared_ptr GetOrCreateValue( + TokenCache::Internals::CacheKey const& key, + DateTime::duration minimumExpiration) +{ + { + std::shared_lock cacheReadLock(TokenCache::Internals::CacheMutex); + + auto const found = TokenCache::Internals::Cache.find(key); + if (found != TokenCache::Internals::Cache.end()) + { + return found->second; + } + } + +#if defined(TESTING_BUILD) + if (TokenCache::Internals::OnBeforeCacheWriteLock != nullptr) + { + TokenCache::Internals::OnBeforeCacheWriteLock(); + } +#endif + + std::unique_lock cacheWriteLock(TokenCache::Internals::CacheMutex); + + // Search cache for the second time, in case the item was inserted between releasing the read lock + // and acquiring the write lock. + auto const found = TokenCache::Internals::Cache.find(key); + if (found != TokenCache::Internals::Cache.end()) + { + return found->second; + } + + // Clean up cache from expired items (once every N insertions). + { + auto const cacheSize = TokenCache::Internals::Cache.size(); + + // N: cacheSize (before insertion) is >= 32 and is a power of two. + // 32 as a starting point does not have any special meaning. + // + // Power of 2 trick: + // https://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/ + + if (cacheSize >= 32 && (cacheSize & (cacheSize - 1)) == 0) + { + auto now = std::chrono::system_clock::now(); + + auto iter = TokenCache::Internals::Cache.begin(); + while (iter != TokenCache::Internals::Cache.end()) + { + // Should we end up erasing the element, iterator to current will become invalid, after + // which we can't increment it. So we copy current, and safely advance the loop iterator. + auto const curr = iter; + ++iter; + + // We will try to obtain a write lock, but in a non-blocking way. We only lock it if no one + // was holding it for read and write at a time. If it's busy in any way, we don't wait, but + // move on. + auto const item = curr->second; + { + std::unique_lock lock(item->ElementMutex, std::defer_lock); + if (lock.try_lock() && !IsFresh(item, minimumExpiration, now)) + { + TokenCache::Internals::Cache.erase(curr); + } + } + } + } + } + + // Insert the blank value value and return it. + return TokenCache::Internals::Cache[key] = std::make_shared(); +} +} // namespace + +AccessToken TokenCache::GetToken( + std::string const& tenantId, + std::string const& clientId, + std::string const& authorityHost, + std::string const& scopes, + DateTime::duration minimumExpiration, + std::function const& getNewToken) +{ + auto const item + = GetOrCreateValue({tenantId, clientId, authorityHost, scopes}, minimumExpiration); + + { + std::shared_lock itemReadLock(item->ElementMutex); + + if (IsFresh(item, minimumExpiration, std::chrono::system_clock::now())) + { + return item->AccessToken; + } + } + + { +#if defined(TESTING_BUILD) + if (TokenCache::Internals::OnBeforeItemWriteLock != nullptr) + { + TokenCache::Internals::OnBeforeItemWriteLock(); + } +#endif + + std::unique_lock itemWriteLock(item->ElementMutex); + + // Check the expiration for the second time, in case it just got updated, after releasing the + // itemReadLock, and before acquiring itemWriteLock. + if (IsFresh(item, minimumExpiration, std::chrono::system_clock::now())) + { + return item->AccessToken; + } + + auto const newToken = getNewToken(); + item->AccessToken = newToken; + return newToken; + } +} + +#if defined(TESTING_BUILD) +void TokenCache::Clear() +{ + std::unique_lock cacheWriteLock(TokenCache::Internals::CacheMutex); + Internals::Cache.clear(); +} +#endif diff --git a/sdk/identity/azure-identity/test/ut/CMakeLists.txt b/sdk/identity/azure-identity/test/ut/CMakeLists.txt index 784e32018b..243f4d567c 100644 --- a/sdk/identity/azure-identity/test/ut/CMakeLists.txt +++ b/sdk/identity/azure-identity/test/ut/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable ( macro_guard_test.cpp managed_identity_credential_test.cpp simplified_header_test.cpp + token_cache_test.cpp token_credential_impl_test.cpp token_credential_test.cpp ) diff --git a/sdk/identity/azure-identity/test/ut/credential_test_helper.cpp b/sdk/identity/azure-identity/test/ut/credential_test_helper.cpp index 8c0868535e..6285b4e782 100644 --- a/sdk/identity/azure-identity/test/ut/credential_test_helper.cpp +++ b/sdk/identity/azure-identity/test/ut/credential_test_helper.cpp @@ -3,6 +3,7 @@ #include "credential_test_helper.hpp" +#include "private/token_cache_internals.hpp" #include #include @@ -70,6 +71,8 @@ CredentialTestHelper::TokenRequestSimulationResult CredentialTestHelper::Simulat std::vector const& responses, GetTokenCallback getToken) { + Azure::Identity::_detail::TokenCache::Clear(); + using Azure::Core::Context; using Azure::Core::Http::HttpStatusCode; using Azure::Core::Http::RawResponse; diff --git a/sdk/identity/azure-identity/test/ut/token_cache_test.cpp b/sdk/identity/azure-identity/test/ut/token_cache_test.cpp new file mode 100644 index 0000000000..78c4368227 --- /dev/null +++ b/sdk/identity/azure-identity/test/ut/token_cache_test.cpp @@ -0,0 +1,450 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include "private/token_cache_internals.hpp" + +#include + +#include + +using Azure::DateTime; +using Azure::Core::Credentials::AccessToken; +using Azure::Identity::_detail::TokenCache; + +using namespace std::chrono_literals; + +TEST(TokenCache, KeyComparison) +{ + using Key = TokenCache::Internals::CacheKey; + Key const key1{"a", "b", "c", "d"}; + EXPECT_FALSE(key1 < key1); + + { + Key const key1dup{"a", "b", "c", "d"}; + + EXPECT_FALSE(key1 < key1dup); + EXPECT_FALSE(key1dup < key1); + } + + Key const key2{"a", "b", "c", "~"}; + Key const key3{"a", "b", "~", "d"}; + Key const key4{"a", "~", "c", "d"}; + Key const key5{"~", "b", "c", "d"}; + + EXPECT_TRUE(key1 < key2); + EXPECT_TRUE(key1 < key3); + EXPECT_TRUE(key1 < key4); + EXPECT_TRUE(key1 < key5); + EXPECT_FALSE(key2 < key1); + EXPECT_FALSE(key3 < key1); + EXPECT_FALSE(key4 < key1); + EXPECT_FALSE(key5 < key1); + + EXPECT_TRUE(key2 < key3); + EXPECT_TRUE(key2 < key4); + EXPECT_TRUE(key2 < key5); + EXPECT_FALSE(key3 < key2); + EXPECT_FALSE(key4 < key2); + EXPECT_FALSE(key5 < key2); + + EXPECT_TRUE(key3 < key4); + EXPECT_TRUE(key3 < key5); + EXPECT_FALSE(key4 < key3); + EXPECT_FALSE(key5 < key3); + + EXPECT_TRUE(key4 < key5); + EXPECT_FALSE(key5 < key4); +} + +TEST(TokenCache, GetReuseRefresh) +{ + TokenCache::Clear(); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 0UL); + + DateTime const Tomorrow = std::chrono::system_clock::now() + 24h; + auto const Yesterday = Tomorrow - 48h; + + { + auto const token1 = TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + AccessToken result; + result.Token = "T1"; + result.ExpiresOn = Tomorrow; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token1.ExpiresOn, Tomorrow); + EXPECT_EQ(token1.Token, "T1"); + + auto const token2 = TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + EXPECT_FALSE("getNewToken does not get invoked when the existing cache value is good"); + AccessToken result; + result.Token = "T2"; + result.ExpiresOn = Tomorrow + 24h; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token1.ExpiresOn, token2.ExpiresOn); + EXPECT_EQ(token1.Token, token2.Token); + } + + { + TokenCache::Internals::Cache[{"A", "B", "C", "D"}]->AccessToken.ExpiresOn = Yesterday; + + auto const token = TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + AccessToken result; + result.Token = "T3"; + result.ExpiresOn = Tomorrow + 1min; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token.ExpiresOn, Tomorrow + 1min); + EXPECT_EQ(token.Token, "T3"); + } +} + +TEST(TokenCache, TwoThreadsAttemptToInsertTheSameKey) +{ + TokenCache::Clear(); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 0UL); + + DateTime const Tomorrow = std::chrono::system_clock::now() + 24h; + + TokenCache::Internals::OnBeforeCacheWriteLock = [=]() { + TokenCache::Internals::OnBeforeCacheWriteLock = nullptr; + static_cast(TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + AccessToken result; + result.Token = "T1"; + result.ExpiresOn = Tomorrow; + return result; + })); + }; + + auto const token = TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + EXPECT_FALSE("getNewToken does not get invoked when the fresh value was inserted just before " + "acquiring cache write lock"); + AccessToken result; + result.Token = "T2"; + result.ExpiresOn = Tomorrow + 1min; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token.ExpiresOn, Tomorrow); + EXPECT_EQ(token.Token, "T1"); +} + +TEST(TokenCache, TwoThreadsAttemptToUpdateTheSameToken) +{ + TokenCache::Clear(); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 0UL); + + DateTime const Tomorrow = std::chrono::system_clock::now() + 24h; + auto const Yesterday = Tomorrow - 48h; + + { + TokenCache::Internals::OnBeforeItemWriteLock = [=]() { + TokenCache::Internals::OnBeforeItemWriteLock = nullptr; + auto const item = TokenCache::Internals::Cache[{"A", "B", "C", "D"}]; + item->AccessToken.Token = "T1"; + item->AccessToken.ExpiresOn = Tomorrow; + }; + + auto const token = TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + EXPECT_FALSE("getNewToken does not get invoked when the fresh value was inserted just before " + "acquiring item write lock"); + AccessToken result; + result.Token = "T2"; + result.ExpiresOn = Tomorrow + 1min; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token.ExpiresOn, Tomorrow); + EXPECT_EQ(token.Token, "T1"); + } + + // Same as above, but the token that was inserted is already expired. + { + TokenCache::Clear(); + + TokenCache::Internals::OnBeforeItemWriteLock = [=]() { + TokenCache::Internals::OnBeforeItemWriteLock = nullptr; + auto const item = TokenCache::Internals::Cache[{"A", "B", "C", "D"}]; + item->AccessToken.Token = "T3"; + item->AccessToken.ExpiresOn = Yesterday; + }; + + auto const token = TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + AccessToken result; + result.Token = "T4"; + result.ExpiresOn = Tomorrow + 3min; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token.ExpiresOn, Tomorrow + 3min); + EXPECT_EQ(token.Token, "T4"); + } +} + +TEST(TokenCache, ExpiredCleanup) +{ + DateTime const Tomorrow = std::chrono::system_clock::now() + 24h; + auto const Yesterday = Tomorrow - 48h; + + TokenCache::Clear(); + EXPECT_EQ(TokenCache::Internals::Cache.size(), 0UL); + + for (auto i = 1; i <= 65; ++i) + { + auto const n = std::to_string(i); + static_cast(TokenCache::GetToken(n, n, n, n, 2min, [=]() { + AccessToken result; + result.Token = "T1"; + result.ExpiresOn = Tomorrow; + return result; + })); + } + + // Simply: we added 64+1 token, none of them has expired. None are expected to be cleaned up. + EXPECT_EQ(TokenCache::Internals::Cache.size(), 65UL); + + // Let's expire 3 of them, with numbers from 1 to 3. + for (auto i = 1; i <= 3; ++i) + { + auto const n = std::to_string(i); + TokenCache::Internals::Cache[{n, n, n, n}]->AccessToken.ExpiresOn = Yesterday; + } + + // Add tokens up to 128 total. When 129th gets added, clean up should get triggered. + for (auto i = 66; i <= 128; ++i) + { + auto const n = std::to_string(i); + static_cast(TokenCache::GetToken(n, n, n, n, 2min, [=]() { + AccessToken result; + result.Token = "T1"; + result.ExpiresOn = Tomorrow; + return result; + })); + } + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 128UL); + + // Count is at 128. Tokens from 1 to 3 are still in cache even though they are expired. + for (auto i = 1; i <= 3; ++i) + { + auto const n = std::to_string(i); + EXPECT_NE(TokenCache::Internals::Cache.find({n, n, n, n}), TokenCache::Internals::Cache.end()); + } + + // One more addition to the cache and cleanup for the expired ones will get triggered. + static_cast(TokenCache::GetToken("129", "129", "129", "129", 2min, [=]() { + AccessToken result; + result.Token = "T1"; + result.ExpiresOn = Tomorrow; + return result; + })); + + // We were at 128 before we added 1 more, and now we're at 126. 3 were deleted, 1 was added. + EXPECT_EQ(TokenCache::Internals::Cache.size(), 126UL); + + // Items from 1 to 3 should no longer be in the cache. + for (auto i = 1; i <= 3; ++i) + { + auto const n = std::to_string(i); + EXPECT_EQ(TokenCache::Internals::Cache.find({n, n, n, n}), TokenCache::Internals::Cache.end()); + } + + // Let's expire items from 21 all the way up to 129. + for (auto i = 21; i <= 129; ++i) + { + auto const n = std::to_string(i); + TokenCache::Internals::Cache[{n, n, n, n}]->AccessToken.ExpiresOn = Yesterday; + } + + // Re-add items 2 and 3. Adding them should not trigger cleanup. After adding, cache should get to + // 128 items (with numbers from 2 to 129, and number 1 missing). + for (auto i = 2; i <= 3; ++i) + { + auto const n = std::to_string(i); + static_cast(TokenCache::GetToken(n, n, n, n, 2min, [=]() { + AccessToken result; + result.Token = "T2"; + result.ExpiresOn = Tomorrow; + return result; + })); + } + + // Cache is now at 128 again (items from 2 to 129). Adding 1 more will trigger cleanup. + EXPECT_EQ(TokenCache::Internals::Cache.size(), 128UL); + + // Now let's lock some of the items for reading, and some for writing. Cleanup should not block on + // token release, but will simply move on, without doing anything to the ones that were locked. + // Out of 4 locked, two are expired, so they should get cleared under normla circumstances, but + // this time they will remain in the cache. + std::shared_lock readLockForUnexpired( + TokenCache::Internals::Cache[{"2", "2", "2", "2"}]->ElementMutex); + + std::shared_lock readLockForExpired( + TokenCache::Internals::Cache[{"127", "127", "127", "127"}]->ElementMutex); + + std::unique_lock writeLockForUnexpired( + TokenCache::Internals::Cache[{"3", "3", "3", "3"}]->ElementMutex); + + std::unique_lock writeLockForExpired( + TokenCache::Internals::Cache[{"128", "128", "128", "128"}]->ElementMutex); + + // Count is at 128. Inserting the 129th element, and it will trigger cleanup. + static_cast(TokenCache::GetToken("1", "1", "1", "1", 2min, [=]() { + AccessToken result; + result.Token = "T2"; + result.ExpiresOn = Tomorrow; + return result; + })); + + // These should be 20 unexpired items + two that are expired but were locked, so 22 total. + EXPECT_EQ(TokenCache::Internals::Cache.size(), 22UL); + + for (auto i = 1; i <= 20; ++i) + { + auto const n = std::to_string(i); + EXPECT_NE(TokenCache::Internals::Cache.find({n, n, n, n}), TokenCache::Internals::Cache.end()); + } + + EXPECT_NE( + TokenCache::Internals::Cache.find({"127", "127", "127", "127"}), + TokenCache::Internals::Cache.end()); + + EXPECT_NE( + TokenCache::Internals::Cache.find({"128", "128", "128", "128"}), + TokenCache::Internals::Cache.end()); + + for (auto i = 21; i <= 126; ++i) + { + auto const n = std::to_string(i); + EXPECT_EQ(TokenCache::Internals::Cache.find({n, n, n, n}), TokenCache::Internals::Cache.end()); + } +} + +TEST(TokenCache, MinimumExpiration) +{ + TokenCache::Clear(); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 0UL); + + DateTime const Tomorrow = std::chrono::system_clock::now() + 24h; + + auto const token1 = TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + AccessToken result; + result.Token = "T1"; + result.ExpiresOn = Tomorrow; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token1.ExpiresOn, Tomorrow); + EXPECT_EQ(token1.Token, "T1"); + + auto const token2 = TokenCache::GetToken("A", "B", "C", "D", 24h, [=]() { + AccessToken result; + result.Token = "T2"; + result.ExpiresOn = Tomorrow + 1h; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token2.ExpiresOn, Tomorrow + 1h); + EXPECT_EQ(token2.Token, "T2"); +} + +TEST(TokenCache, MultithreadedAccess) +{ + TokenCache::Clear(); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 0UL); + + DateTime const Tomorrow = std::chrono::system_clock::now() + 24h; + + auto const token1 = TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + AccessToken result; + result.Token = "T1"; + result.ExpiresOn = Tomorrow; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token1.ExpiresOn, Tomorrow); + EXPECT_EQ(token1.Token, "T1"); + + { + std::shared_lock itemReadLock( + TokenCache::Internals::Cache[{"A", "B", "C", "D"}]->ElementMutex); + + { + std::shared_lock cacheReadLock(TokenCache::Internals::CacheMutex); + + // Parallel threads read both the container and the item we're accessing, and we can access it + // in parallel as well. + auto const token2 = TokenCache::GetToken("A", "B", "C", "D", 2min, [=]() { + EXPECT_FALSE("getNewToken does not get invoked when the existing cache value is good"); + AccessToken result; + result.Token = "T2"; + result.ExpiresOn = Tomorrow + 1h; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 1UL); + + EXPECT_EQ(token2.ExpiresOn, token1.ExpiresOn); + EXPECT_EQ(token2.Token, token1.Token); + } + + // The cache is unlocked, but one item is being read in a parallel thread, which does not + // prevent new items (with different key) from being appended to cache. + auto const token3 = TokenCache::GetToken("E", "F", "G", "H", 2min, [=]() { + AccessToken result; + result.Token = "T3"; + result.ExpiresOn = Tomorrow + 2h; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 2UL); + + EXPECT_EQ(token3.ExpiresOn, Tomorrow + 2h); + EXPECT_EQ(token3.Token, "T3"); + } + + { + std::unique_lock itemWriteLock( + TokenCache::Internals::Cache[{"A", "B", "C", "D"}]->ElementMutex); + + // The cache is unlocked, but one item is being written in a parallel thread, which does not + // prevent new items (with different key) from being appended to cache. + auto const token3 = TokenCache::GetToken("I", "J", "K", "L", 2min, [=]() { + AccessToken result; + result.Token = "T4"; + result.ExpiresOn = Tomorrow + 3h; + return result; + }); + + EXPECT_EQ(TokenCache::Internals::Cache.size(), 3UL); + + EXPECT_EQ(token3.ExpiresOn, Tomorrow + 3h); + EXPECT_EQ(token3.Token, "T4"); + } +} diff --git a/sdk/identity/azure-identity/test/ut/token_credential_impl_test.cpp b/sdk/identity/azure-identity/test/ut/token_credential_impl_test.cpp index dc9b7e0752..d2693f7ab2 100644 --- a/sdk/identity/azure-identity/test/ut/token_credential_impl_test.cpp +++ b/sdk/identity/azure-identity/test/ut/token_credential_impl_test.cpp @@ -3,6 +3,8 @@ #include "private/token_credential_impl.hpp" +#include "private/token_cache.hpp" + #include "credential_test_helper.hpp" #include @@ -18,6 +20,7 @@ using Azure::Core::Credentials::TokenCredential; using Azure::Core::Credentials::TokenCredentialOptions; using Azure::Core::Credentials::TokenRequestContext; using Azure::Core::Http::HttpMethod; +using Azure::Identity::_detail::TokenCache; using Azure::Identity::_detail::TokenCredentialImpl; using Azure::Identity::Test::_detail::CredentialTestHelper; @@ -50,6 +53,8 @@ class TokenCredentialImplTester : public TokenCredential { AccessToken GetToken(TokenRequestContext const& tokenRequestContext, Context const& context) const override { + TokenCache::Clear(); + return m_tokenCredentialImpl->GetToken(context, [&]() { m_throwingFunction(); diff --git a/sdk/identity/azure-identity/test/ut/token_credential_test.cpp b/sdk/identity/azure-identity/test/ut/token_credential_test.cpp index 1ad894727d..5dca4c58ce 100644 --- a/sdk/identity/azure-identity/test/ut/token_credential_test.cpp +++ b/sdk/identity/azure-identity/test/ut/token_credential_test.cpp @@ -7,6 +7,8 @@ #include #include +#include "private/token_cache.hpp" + #include #include @@ -58,6 +60,8 @@ TEST_F(TokenCredentialTest, ClientSecret) std::string const testName(GetTestName()); auto const clientSecretCredential = GetClientSecretCredential(testName); + _detail::TokenCache::Clear(); + auto const token = clientSecretCredential->GetToken( {{"https://vault.azure.net/.default"}}, Azure::Core::Context::ApplicationContext); @@ -70,6 +74,8 @@ TEST_F(TokenCredentialTest, EnvironmentCredential) std::string const testName(GetTestName()); auto const clientSecretCredential = GetEnvironmentCredential(testName); + _detail::TokenCache::Clear(); + auto const token = clientSecretCredential->GetToken( {{"https://vault.azure.net/.default"}}, Azure::Core::Context::ApplicationContext); From 673bacba0870a970a0ffccbb69f9c20a1be24183 Mon Sep 17 00:00:00 2001 From: George Arama <50641385+gearama@users.noreply.github.com> Date: Wed, 26 Oct 2022 10:16:32 -0700 Subject: [PATCH 14/21] identicalize the comments type (#4063) --- .../src/private/package_version.hpp | 17 ++++++++++++----- .../azure-core/src/private/package_version.hpp | 17 ++++++++++++----- .../src/private/package_version.hpp | 14 ++++++++++++-- .../src/private/package_version.hpp | 17 ++++++++++++----- .../src/private/package_version.hpp | 17 ++++++++++++----- .../src/private/package_version.hpp | 17 ++++++++++++----- .../src/private/package_version.hpp | 16 ++++++++++++---- .../src/private/package_version.hpp | 16 ++++++++++++---- .../src/private/package_version.hpp | 16 ++++++++++++---- .../src/private/package_version.hpp | 16 ++++++++++++---- .../src/private/package_version.hpp | 16 ++++++++++++---- .../src/private/package_version.hpp | 16 ++++++++++++---- 12 files changed, 144 insertions(+), 51 deletions(-) diff --git a/sdk/core/azure-core-tracing-opentelemetry/src/private/package_version.hpp b/sdk/core/azure-core-tracing-opentelemetry/src/private/package_version.hpp index fb747ab534..ae3a040e8b 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/src/private/package_version.hpp +++ b/sdk/core/azure-core-tracing-opentelemetry/src/private/package_version.hpp @@ -21,20 +21,27 @@ namespace Azure { namespace Core { namespace OpenTelemetry { namespace _detail { /** * @brief Provides version information. - * */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int32_t Major = AZURE_CORE_OPENTELEMETRY_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int32_t Minor = AZURE_CORE_OPENTELEMETRY_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int32_t Patch = AZURE_CORE_OPENTELEMETRY_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_CORE_OPENTELEMETRY_VERSION_PRERELEASE) != sizeof(""); diff --git a/sdk/core/azure-core/src/private/package_version.hpp b/sdk/core/azure-core/src/private/package_version.hpp index b3019f0bc6..8b58e77937 100644 --- a/sdk/core/azure-core/src/private/package_version.hpp +++ b/sdk/core/azure-core/src/private/package_version.hpp @@ -21,20 +21,27 @@ namespace Azure { namespace Core { namespace _detail { /** * @brief Provides version information. - * */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int32_t Major = AZURE_CORE_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int32_t Minor = AZURE_CORE_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int32_t Patch = AZURE_CORE_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_CORE_VERSION_PRERELEASE) != sizeof(""); /** diff --git a/sdk/identity/azure-identity/src/private/package_version.hpp b/sdk/identity/azure-identity/src/private/package_version.hpp index 31cb9c049b..be447f6879 100644 --- a/sdk/identity/azure-identity/src/private/package_version.hpp +++ b/sdk/identity/azure-identity/src/private/package_version.hpp @@ -21,20 +21,30 @@ namespace Azure { namespace Identity { namespace _detail { /** * @brief Provides version information. - * */ class PackageVersion final { public: + /** + * @brief Major numeric identifier. + */ /// Major numeric identifier. static constexpr int32_t Major = AZURE_IDENTITY_VERSION_MAJOR; + /** + * @brief Minor numeric identifier. + */ /// Minor numeric identifier. static constexpr int32_t Minor = AZURE_IDENTITY_VERSION_MINOR; + /** + * @brief Patch numeric identifier. + */ /// Patch numeric identifier. static constexpr int32_t Patch = AZURE_IDENTITY_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_IDENTITY_VERSION_PRERELEASE) != sizeof(""); /** diff --git a/sdk/keyvault/azure-security-keyvault-certificates/src/private/package_version.hpp b/sdk/keyvault/azure-security-keyvault-certificates/src/private/package_version.hpp index 848ce84366..cdbc9936a1 100644 --- a/sdk/keyvault/azure-security-keyvault-certificates/src/private/package_version.hpp +++ b/sdk/keyvault/azure-security-keyvault-certificates/src/private/package_version.hpp @@ -23,20 +23,27 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Certificat namespace _detail { /** * @brief Provides version information. - * */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int32_t Major = AZURE_SECURITY_KEYVAULT_CERTIFICATES_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int32_t Minor = AZURE_SECURITY_KEYVAULT_CERTIFICATES_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int32_t Patch = AZURE_SECURITY_KEYVAULT_CERTIFICATES_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_SECURITY_KEYVAULT_CERTIFICATES_VERSION_PRERELEASE) != sizeof(""); diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/private/package_version.hpp b/sdk/keyvault/azure-security-keyvault-keys/src/private/package_version.hpp index e6c31ee742..7d3ca63093 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/private/package_version.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/private/package_version.hpp @@ -22,20 +22,27 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { namespace _detail { /** * @brief Provides version information. - * */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int32_t Major = AZURE_SECURITY_KEYVAULT_KEYS_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int32_t Minor = AZURE_SECURITY_KEYVAULT_KEYS_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int32_t Patch = AZURE_SECURITY_KEYVAULT_KEYS_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_SECURITY_KEYVAULT_KEYS_VERSION_PRERELEASE) != sizeof(""); diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/private/package_version.hpp b/sdk/keyvault/azure-security-keyvault-secrets/src/private/package_version.hpp index 3abc18be21..671d7e26fc 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/src/private/package_version.hpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/src/private/package_version.hpp @@ -22,20 +22,27 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { namespace _detail { /** * @brief Provides version information. - * */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int32_t Major = AZURE_SECURITY_KEYVAULT_SECRETS_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int32_t Minor = AZURE_SECURITY_KEYVAULT_SECRETS_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int32_t Patch = AZURE_SECURITY_KEYVAULT_SECRETS_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_SECURITY_KEYVAULT_SECRETS_VERSION_PRERELEASE) != sizeof(""); diff --git a/sdk/storage/azure-storage-blobs/src/private/package_version.hpp b/sdk/storage/azure-storage-blobs/src/private/package_version.hpp index 6f21bf905b..14e2ca0d86 100644 --- a/sdk/storage/azure-storage-blobs/src/private/package_version.hpp +++ b/sdk/storage/azure-storage-blobs/src/private/package_version.hpp @@ -22,16 +22,24 @@ namespace Azure { namespace Storage { namespace Blobs { namespace _detail { */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int32_t Major = AZURE_STORAGE_BLOBS_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int32_t Minor = AZURE_STORAGE_BLOBS_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int32_t Patch = AZURE_STORAGE_BLOBS_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_STORAGE_BLOBS_VERSION_PRERELEASE) != sizeof(""); diff --git a/sdk/storage/azure-storage-common/src/private/package_version.hpp b/sdk/storage/azure-storage-common/src/private/package_version.hpp index 94b97b625e..1f1c6a167a 100644 --- a/sdk/storage/azure-storage-common/src/private/package_version.hpp +++ b/sdk/storage/azure-storage-common/src/private/package_version.hpp @@ -24,16 +24,24 @@ namespace Azure { namespace Storage { namespace Common { namespace _detail { */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int Major = AZURE_STORAGE_COMMON_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int Minor = AZURE_STORAGE_COMMON_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int Patch = AZURE_STORAGE_COMMON_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_STORAGE_COMMON_VERSION_PRERELEASE) != sizeof(""); diff --git a/sdk/storage/azure-storage-files-datalake/src/private/package_version.hpp b/sdk/storage/azure-storage-files-datalake/src/private/package_version.hpp index 680278e994..b90a56c115 100644 --- a/sdk/storage/azure-storage-files-datalake/src/private/package_version.hpp +++ b/sdk/storage/azure-storage-files-datalake/src/private/package_version.hpp @@ -23,16 +23,24 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int32_t Major = AZURE_STORAGE_FILES_DATALAKE_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int32_t Minor = AZURE_STORAGE_FILES_DATALAKE_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int32_t Patch = AZURE_STORAGE_FILES_DATALAKE_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_STORAGE_FILES_DATALAKE_VERSION_PRERELEASE) != sizeof(""); diff --git a/sdk/storage/azure-storage-files-shares/src/private/package_version.hpp b/sdk/storage/azure-storage-files-shares/src/private/package_version.hpp index 28dcd87313..a2568e1051 100644 --- a/sdk/storage/azure-storage-files-shares/src/private/package_version.hpp +++ b/sdk/storage/azure-storage-files-shares/src/private/package_version.hpp @@ -22,16 +22,24 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { names */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int32_t Major = AZURE_STORAGE_FILES_SHARES_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int32_t Minor = AZURE_STORAGE_FILES_SHARES_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int32_t Patch = AZURE_STORAGE_FILES_SHARES_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_STORAGE_FILES_SHARES_VERSION_PRERELEASE) != sizeof(""); diff --git a/sdk/storage/azure-storage-queues/src/private/package_version.hpp b/sdk/storage/azure-storage-queues/src/private/package_version.hpp index 817761f962..914877b02e 100644 --- a/sdk/storage/azure-storage-queues/src/private/package_version.hpp +++ b/sdk/storage/azure-storage-queues/src/private/package_version.hpp @@ -22,16 +22,24 @@ namespace Azure { namespace Storage { namespace Queues { namespace _detail { */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int32_t Major = AZURE_STORAGE_QUEUES_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int32_t Minor = AZURE_STORAGE_QUEUES_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int32_t Patch = AZURE_STORAGE_QUEUES_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_STORAGE_QUEUES_VERSION_PRERELEASE) != sizeof(""); diff --git a/sdk/template/azure-template/src/private/package_version.hpp b/sdk/template/azure-template/src/private/package_version.hpp index 4d3ab24461..cc45e0bca3 100644 --- a/sdk/template/azure-template/src/private/package_version.hpp +++ b/sdk/template/azure-template/src/private/package_version.hpp @@ -22,16 +22,24 @@ namespace Azure { namespace Template { namespace _detail { */ class PackageVersion final { public: - /// Major numeric identifier. + /** + * @brief Major numeric identifier. + */ static constexpr int Major = AZURE_TEMPLATE_VERSION_MAJOR; - /// Minor numeric identifier. + /** + * @brief Minor numeric identifier. + */ static constexpr int Minor = AZURE_TEMPLATE_VERSION_MINOR; - /// Patch numeric identifier. + /** + * @brief Patch numeric identifier. + */ static constexpr int Patch = AZURE_TEMPLATE_VERSION_PATCH; - /// Indicates whether the SDK is in a pre-release state. + /** + * @brief Indicates whether the SDK is in a pre-release state. + */ static constexpr bool IsPreRelease = sizeof(AZURE_TEMPLATE_VERSION_PRERELEASE) != sizeof(""); /** From f174d97e8a0f1a9aa37c6c7e388c2b2fff84cf08 Mon Sep 17 00:00:00 2001 From: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> Date: Wed, 26 Oct 2022 12:51:22 -0700 Subject: [PATCH 15/21] Improve scenario matrix edge case handling (#4065) Co-authored-by: Ben Broderick Phillips --- .../stress-testing/generate-scenario-matrix.ps1 | 14 +++++++++----- .../stress-testing/stress-test-deployment-lib.ps1 | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/eng/common/scripts/stress-testing/generate-scenario-matrix.ps1 b/eng/common/scripts/stress-testing/generate-scenario-matrix.ps1 index aba8be3451..1ddb05cd0c 100644 --- a/eng/common/scripts/stress-testing/generate-scenario-matrix.ps1 +++ b/eng/common/scripts/stress-testing/generate-scenario-matrix.ps1 @@ -39,12 +39,16 @@ function GenerateScenarioMatrix( $scenariosMatrix += $entry } - $valuesYaml = Get-Content -Raw (Join-Path (Split-Path $matrixFilePath) 'values.yaml') - $values = $valuesYaml | ConvertFrom-Yaml -Ordered - if (!$values) {$values = @{}} + $valuesConfig = Join-Path (Split-Path $matrixFilePath) 'values.yaml' + $values = [ordered]@{} + if (Test-Path $valuesConfig) { + $valuesYaml = Get-Content -Raw $valuesConfig + $values = $valuesYaml | ConvertFrom-Yaml -Ordered + if (!$values) {$values = @{}} - if ($values.ContainsKey('Scenarios')) { - throw "Please use matrix generation for stress test scenarios." + if ($values.ContainsKey('Scenarios')) { + throw "Please use matrix generation for stress test scenarios." + } } $values.scenarios = $scenariosMatrix diff --git a/eng/common/scripts/stress-testing/stress-test-deployment-lib.ps1 b/eng/common/scripts/stress-testing/stress-test-deployment-lib.ps1 index a082477779..0365bbb30c 100644 --- a/eng/common/scripts/stress-testing/stress-test-deployment-lib.ps1 +++ b/eng/common/scripts/stress-testing/stress-test-deployment-lib.ps1 @@ -248,7 +248,7 @@ function DeployStressPackage( } } } - $genVal.scenarios = foreach ($scenario in $genVal.scenarios) { + $genVal.scenarios = @( foreach ($scenario in $genVal.scenarios) { $dockerPath = Join-Path $pkg.Directory $scenario.image if ("image" -notin $scenario) { $dockerPath = $dockerFilePath @@ -257,7 +257,7 @@ function DeployStressPackage( $scenario.imageTag = $imageTag } $scenario - } + } ) $genVal | ConvertTo-Yaml | Out-File -FilePath $genValFile } From 4c550469ee7632993ba0efa13f6abefd35d086c3 Mon Sep 17 00:00:00 2001 From: George Arama <50641385+gearama@users.noreply.github.com> Date: Thu, 27 Oct 2022 11:45:53 -0700 Subject: [PATCH 16/21] docV1 (#4051) * docV1 * Update doc/PerformanceTesting.md Co-authored-by: Larry Osterman * Update doc/PerformanceTesting.md Co-authored-by: Larry Osterman * Update doc/PerformanceTesting.md Co-authored-by: Larry Osterman * Update doc/PerformanceTesting.md Co-authored-by: Larry Osterman * comment * some more updates * Update doc/PerformanceTesting.md Co-authored-by: Larry Osterman * Update doc/PerformanceTesting.md Co-authored-by: Larry Osterman * Update doc/PerformanceTesting.md Co-authored-by: Larry Osterman * PR * Update doc/PerformanceTesting.md Co-authored-by: Larry Osterman Co-authored-by: Larry Osterman --- doc/PerformanceTesting.md | 171 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 doc/PerformanceTesting.md diff --git a/doc/PerformanceTesting.md b/doc/PerformanceTesting.md new file mode 100644 index 0000000000..625e121c43 --- /dev/null +++ b/doc/PerformanceTesting.md @@ -0,0 +1,171 @@ +# Performance Testing + +## Writing a test + +Adding tests , at the moment relies in making modifications in a couple of repositories. + +## Azure-SDK-For-Cpp repo + +E.G. https://github.com/Azure/azure-sdk-for-cpp/tree/main/sdk/storage/azure-storage-blobs + +### Location + +Performance tests are located under **"test/perf"** folder under the service folder(e.g. alongside ut folder). + +The perf test folder should be added in the parent CMakeLists.txt guarded by the **BUILD_PERFORMANCE_TESTS** flag. + +E.G. + +```markdown + + if(BUILD_PERFORMANCE_TESTS) + add_subdirectory(test/perf) + endif() + +``` + +### Structure + +As any other CPP project you will need a **CMakeLists.txt** file , along side **src** and **inc** folders + +#### Contents of the **inc** directory + +Under inc folder create a subfolder structure following your namespace hierarchy ending with another test folder since these are in the ...Test namespace. + +E.G. test/perf/inc/azure/storage/blobs/test + +The tests are defined in .hpp files under this folder. + +##### Test definition + +In a .hpp file we define a class that will be contain the tests methods. The class is defined in the ::Test namespace for your service. + +The class will inherit from the **PerfTest** base class and will override several methods as follows: +- Constructor(Azure::Perf::TestOptions options) : PerfTest(options) + Options field are passed from the perf test framework and constain the various options defined for running the test. +- void Run(Azure::Core::Context const&) override {...}. + Runs the actual test code. It is strongly recommended that the test code does as little extra work here as possible, it should consist solely of the actual test invocation. The test code should remove all assert, conditional statements ("if"/"else") or any other unnecessary work as any extra work will skew the results. +- std::vector GetTestOptions() override + Defines the various parameters for the test run that can be passed to the test from the performance framework. The perf framework uses these params to run various combinations(e.g. blob size) +- static Azure::Perf::TestMetadata GetTestMetadata() + Returns TestMetadate object used to identify the test. + +#### Contents of the **src** directory + +Contains one cpp file that contains the main method defintion + +```cpp + int main(int argc, char** argv) + { + std::cout << "SERVICE VERSION " << VCPKG_SERVICE_VERSION << std::endl; + // Create the test list + std::vector tests{ + Service::Namespace::Test::TestName::GetTestMetadata(), + }; + + Azure::Perf::Program::Run(Azure::Core::Context::ApplicationContext, tests, argc, argv); + + return 0; + } +``` + +#### CMakeLists.txt + +Beyond the regular cmake defintion in your cmake file make sure to add + +```makefile +include(AzureVcpkg) +az_vcpkg_integrate() +... +include(PerfTest) +SETPERFDEPS(azure-storage-blobs-cpp VCPKG_SERVICE_VERSION) +``` + +The crucial part here is the SETPERFDEPS cmake macro. +The perf framework will set an environment variable based on the service name with the value representing a version, thus allowing to run the tests against diffrent VCPKG published versions. If the env is not defined then the test will build against the current source code of the service. +There can be multiple set perf for each dependency of the service ( e.g. identity, storage). + +## Pipeline definition +The file should be named `perf.yml`, and should be located in the service directory that is to be tested, for consistency and to keep service related resources in the service folder. + +```yml +parameters: +- name: PackageVersions + displayName: PackageVersions (regex of package versions to run) + type: string + default: '12|source' +- name: Tests + displayName: Tests (regex of tests to run) + type: string + default: '^(download|upload|list-blobs)$' +- name: Arguments + displayName: Arguments (regex of arguments to run) + type: string + default: '(10240)|(10485760)|(1073741824)|(5 )|(500 )|(50000 )' +- name: Iterations + displayName: Iterations (times to run each test) + type: number + default: '5' +- name: AdditionalArguments + displayName: AdditionalArguments (passed to PerfAutomation) + type: string + default: ' ' + +extends: + template: /eng/pipelines/templates/jobs/perf.yml + parameters: + ServiceDirectory: service folder + Services: "^service name$" + PackageVersions: ${{ parameters.PackageVersions }} + Tests: ${{ parameters.Tests }} + Arguments: ${{ parameters.Arguments }} + Iterations: ${{ parameters.Iterations }} + AdditionalArguments: ${{ parameters.AdditionalArguments }} + InstallLanguageSteps: + - pwsh: | + Write-Host "##vso[task.setvariable variable=VCPKG_BINARY_SOURCES_SECRET;issecret=true;]clear;x-azblob,https://cppvcpkgcache.blob.core.windows.net/public-vcpkg-container,,read" + displayName: Set Vcpkg Variables + + EnvVars: + # This is set in the InstallLanguageSteps + VCPKG_BINARY_SOURCES_SECRET: $(VCPKG_BINARY_SOURCES_SECRET) + +``` + +The fields of interest here are the parameters: +- Tests which define which test s run in this pipeline ( which tests are available) +- Arguments which allow to filter which subset of parameters are acceptable for the tests from the plurality in the framework +- ServiceDirectory which represents the root folder of the service +- Services which represents the services which these tests target. + +## Resources + +If the tests require certain resources to exist beforehand the pipeline can deploy them based on the presence of the **perf-resources.bicep** file which will be used to deploy the required resources defined within. + +## Azure-SDK-Tools repo + +## Location + +The performance automation is located under azure-sdk-tools\tools\perf-automation\Azure.Sdk.Tools.PerfAutomation folder. +(https://github.com/Azure/azure-sdk-tools/tree/main/tools/perf-automation/Azure.Sdk.Tools.PerfAutomation) + +## Test definition + +in the above mentioned folder resided the test defintion file "tests.yml". + +### The tests exists in other languages + +If the test exists in other languages then making the CPP version visible to the framework requires adding an entry with the name **CPP** under **Service**/**Languages** followed by the pakages and versions available for the testing(this ties into the CMakeLists SetPerfDeps macro). + +Next under the **Tests**/**Test** node with the desired name add the CPP test name. In this section mind the aArguments list , this ies with the regex in the cpp sdk pipeline.yml definition. + +### The test does not exist in other languages + +In this case you are the first to add the required nodes. The defintion is fairly simple and straightforward. + +## Pipeline + +Once you have everything in place create a pipeline using the definition in your in the cpp repo by going to https://dev.azure.com/azure-sdk/internal/_build?definitionScope=%5Cperf and create a new one under the cpp node. + +To test intermediate definitions of your pipeline you can run the https://dev.azure.com/azure-sdk/internal/_build?definitionId=5121 pipline and set the proper values for the cpp node( make sure to deselect all other languages except cpp unless you want to run them). + From 7cc5f4628be5fab7c77710d3ec7f589113b4eeeb Mon Sep 17 00:00:00 2001 From: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> Date: Thu, 27 Oct 2022 14:25:49 -0700 Subject: [PATCH 17/21] bump version to newest (#4066) Co-authored-by: scbedd <45376673+scbedd@users.noreply.github.com> --- eng/common/testproxy/target_version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/common/testproxy/target_version.txt b/eng/common/testproxy/target_version.txt index ae57303e6a..95166fc1a8 100644 --- a/eng/common/testproxy/target_version.txt +++ b/eng/common/testproxy/target_version.txt @@ -1 +1 @@ -1.0.0-dev.20221007.3 +1.0.0-dev.20221026.3 From 214f4a364eb7e536384368e1a7d319fbbc422c47 Mon Sep 17 00:00:00 2001 From: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> Date: Thu, 27 Oct 2022 18:07:33 -0700 Subject: [PATCH 18/21] Sync eng/common directory with azure-sdk-tools for PR 4543 (#4071) * stress test addons version check * cleanup Co-authored-by: Albert Cheng --- .../stress-testing/find-all-stress-packages.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/eng/common/scripts/stress-testing/find-all-stress-packages.ps1 b/eng/common/scripts/stress-testing/find-all-stress-packages.ps1 index f949b03ad8..673e64e73b 100644 --- a/eng/common/scripts/stress-testing/find-all-stress-packages.ps1 +++ b/eng/common/scripts/stress-testing/find-all-stress-packages.ps1 @@ -36,6 +36,8 @@ function FindStressPackages( } foreach ($chartFile in $chartFiles) { $chart = ParseChart $chartFile + + VerifyAddonsVersion $chart if (matchesAnnotations $chart $filters) { $matrixFilePath = (Join-Path $chartFile.Directory.FullName $MatrixFileName) if (Test-Path $matrixFilePath) { @@ -73,6 +75,15 @@ function MatchesAnnotations([hashtable]$chart, [hashtable]$filters) { return $true } +function VerifyAddonsVersion([hashtable]$chart) { + foreach ($dependency in $chart.dependencies) { + if ($dependency.name -eq "stress-test-addons" -and + $dependency.version -lt "0.2.0") { + throw "The stress-test-addons version in use is $($dependency.version), please use versions >= 0.2.0" + } + } +} + function GetUsername() { # Check GITHUB_USER for users in codespaces environments, since the default user is `codespaces` and # we would like to avoid namespace overlaps for different codespaces users. From bb95a22e3f5fdf7987c757ba241e67934b0dccdc Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Fri, 28 Oct 2022 15:57:51 -0700 Subject: [PATCH 19/21] Added the ability to select OpenSSL 1.1.1n if desired. (#4045) * Added ability to switch to OpenSSL 1.1.1n * Fixed OpenSSL compilation challenges - the CRL stuff works now * Added instructions on using OpenSSL 1.1.1 to README * Added vcpkg args to handle openssl variants --- .vscode/cspell.json | 2 + CMakeSettings.json | 58 ++++ README.md | 35 +++ eng/pipelines/templates/jobs/ci.tests.yml | 4 + eng/pipelines/templates/jobs/live.tests.yml | 2 + .../templates/stages/platform-matrix.json | 4 + eng/pipelines/templates/steps/cmake-build.yml | 3 +- eng/scripts/Get-BinarySizes.ps1 | 3 + sdk/core/azure-core/CHANGELOG.md | 1 + sdk/core/azure-core/src/http/curl/curl.cpp | 128 +++++++- .../openssl/install-pc-files.cmake | 32 ++ vcpkg-custom-ports/openssl/openssl.pc.in | 6 + vcpkg-custom-ports/openssl/portfile.cmake | 28 ++ .../openssl/unix/CMakeLists.txt | 284 ++++++++++++++++++ .../openssl/unix/portfile.cmake | 38 +++ .../openssl/unix/remove-deps.cmake | 7 + vcpkg-custom-ports/openssl/usage | 4 + .../openssl/uwp/EnableUWPSupport.patch | 170 +++++++++++ .../openssl/uwp/make-openssl.bat | 16 + vcpkg-custom-ports/openssl/uwp/portfile.cmake | 163 ++++++++++ .../openssl/vcpkg-cmake-wrapper.cmake.in | 78 +++++ vcpkg-custom-ports/openssl/vcpkg.json | 18 ++ .../openssl/windows/portfile.cmake | 172 +++++++++++ 23 files changed, 1252 insertions(+), 4 deletions(-) create mode 100644 vcpkg-custom-ports/openssl/install-pc-files.cmake create mode 100644 vcpkg-custom-ports/openssl/openssl.pc.in create mode 100644 vcpkg-custom-ports/openssl/portfile.cmake create mode 100644 vcpkg-custom-ports/openssl/unix/CMakeLists.txt create mode 100644 vcpkg-custom-ports/openssl/unix/portfile.cmake create mode 100644 vcpkg-custom-ports/openssl/unix/remove-deps.cmake create mode 100644 vcpkg-custom-ports/openssl/usage create mode 100644 vcpkg-custom-ports/openssl/uwp/EnableUWPSupport.patch create mode 100644 vcpkg-custom-ports/openssl/uwp/make-openssl.bat create mode 100644 vcpkg-custom-ports/openssl/uwp/portfile.cmake create mode 100644 vcpkg-custom-ports/openssl/vcpkg-cmake-wrapper.cmake.in create mode 100644 vcpkg-custom-ports/openssl/vcpkg.json create mode 100644 vcpkg-custom-ports/openssl/windows/portfile.cmake diff --git a/.vscode/cspell.json b/.vscode/cspell.json index d0e48f281c..0aff3b5697 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -16,6 +16,7 @@ ".github/CODEOWNERS", ".gitignore", ".vscode/cspell.json", + "vcpkg-custom-ports", "ci.yml", "squid.conf*", "eng/common/**/*", @@ -54,6 +55,7 @@ "Deserializes", "DFETCH", "DMSVC", + "DVCPKG", "docfx", "DPAPI", "DRUN", diff --git a/CMakeSettings.json b/CMakeSettings.json index 12512877b0..b242dbc1ae 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -20,6 +20,64 @@ "name": "MSVC_USE_STATIC_CRT", "value": "True", "type": "BOOL" + }, + { + "name": "VCPKG_MANIFEST_MODE", + "value": "True", + "type": "BOOL" + } + ] + }, + { + "name": "x64-DebugWithTests-OpenSSL111", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "-v", + "ctestCommandArgs": "", + "variables": [ + { + "name": "VCPKG_TARGET_TRIPLET", + "value": "x64-windows-static", + "type": "STRING" + }, + { + "name": "MSVC_USE_STATIC_CRT", + "value": "True", + "type": "BOOL" + }, + { + "name": "VCPKG_MANIFEST_MODE", + "value": "True", + "type": "BOOL" + }, + { + "name": "VCPKG_OVERLAY_PORTS", + "value": "${projectDir}\\vcpkg-custom-ports", + "type": "STRING" + }, + { + "name": "INSTALL_GTEST", + "value": "False", + "type": "BOOL" + }, + { + "name": "BUILD_TESTING", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_TRANSPORT_CURL", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_SAMPLES", + "value": "True", + "type": "BOOL" } ] }, diff --git a/README.md b/README.md index d15cca613c..b1adda98b0 100644 --- a/README.md +++ b/README.md @@ -324,6 +324,41 @@ The following SDK library releases are available on [vcpkg](https://github.com/m > NOTE: In case of getting linker errors when consuming the SDK on Windows, make sure that [vcpkg triplet](https://vcpkg.readthedocs.io/en/latest/users/triplets/) being consumed matches the [CRT link flags](https://docs.microsoft.com/cpp/build/reference/md-mt-ld-use-run-time-library?view=msvc-160) being set for your app or library build. See also `MSVC_USE_STATIC_CRT` build flag. +## OpenSSL Version + +Several packages within the Azure SDK for C++ use the OpenSSL library. By default, the Azure SDK will use whatever the most recent version of OpenSSL is within the VCPKG repository. + +If you need to use a specific version of OpenSSL, you can use the vcpkg custom ports feature to specify the version of OpenSSL to use. +For example, if you want to use OpenSSL 1.1.1, you should create a folder named `vcpkg-custom-ports` next to to your vcpkg.json file. + +Navigate to your clone of the vcpkg vcpkg repo and execute "git checkout 3b3bd424827a1f7f4813216f6b32b6c61e386b2e" - this will reset your repo to the last version of OpenSSL 1.1.1 +in vcpkg. Then, copy the contents of the `ports/openssl` folder from the vcpkg repo to the `vcpkg-custom-ports` folder you created earlier: + +```sh +cd +git checkout 3b3bd424827a1f7f4813216f6b32b6c61e386b2e +cd ports +cp -r openssl +``` + +This will copy the port information for OpenSSL 1.1.1n to your vcpkg-custom-ports directory. + +Once that is done, you can install the custom port of OpenSSL 1.1.1n using the vcpkg tool: + +```sh +vcpkg install --overlay-ports= +``` + +If you are building using CMAKE, you can instruct CMAKE to apply the overlay ports using the following command line switches: + +```sh +vcpkg -DVCPKG_MANIFEST_MODE=ON -DVCPKG_OVERLAY_PORTS= -DVCPKG_MANIFEST_DIR= +``` + +In addition, if you need to consume OpenSSL from a dynamic linked library/shared object, you can set the VCPKG triplet to reflect that you want to build the library with dynamic +entries.Set the VCPKG_you can set the environment variable to `x64-windows-static` or `x64-windows-dynamic` depending on whether you want to use the static or dynamic version of OpenSSL. +Similarly you can use the x64-linux-dynamic and x64-linux-static triplet to specify consumption of libraries as a shared object or dynamic. + ## Need help - For reference documentation visit the [Azure SDK for C++ documentation](https://azure.github.io/azure-sdk-for-cpp). diff --git a/eng/pipelines/templates/jobs/ci.tests.yml b/eng/pipelines/templates/jobs/ci.tests.yml index 19d7dd6535..b5778797e0 100644 --- a/eng/pipelines/templates/jobs/ci.tests.yml +++ b/eng/pipelines/templates/jobs/ci.tests.yml @@ -76,6 +76,8 @@ jobs: value: "" - name: CmakeArgs value: "" + - name: VcpkgArgs + value: "" # Apply to all services running public pipeline - name: AZURE_TEST_MODE value: "PLAYBACK" @@ -142,6 +144,7 @@ jobs: ServiceDirectory: ${{ parameters.ServiceDirectory }} GenerateArgs: "$(CmakeArgs)" BuildArgs: "$(BuildArgs)" + VcpkgArgs: "$(VcpkgArgs)" Env: "$(CmakeEnvArg)" - ${{ parameters.PreTestSteps }} @@ -223,6 +226,7 @@ jobs: -OsVMImage '$(OSVmImage)' -CmakeEnvArg '$(CmakeEnvArg)' -BuildArgs '$(BuildArgs)' + -VcpkgArgs '$(VcpkgArgs)' -Job '$(Agent.JobName)' -BuildReason '$(Build.Reason)' -SourceBranch '$(Build.SourceBranch)' diff --git a/eng/pipelines/templates/jobs/live.tests.yml b/eng/pipelines/templates/jobs/live.tests.yml index d9783e7b89..ec366dfb52 100644 --- a/eng/pipelines/templates/jobs/live.tests.yml +++ b/eng/pipelines/templates/jobs/live.tests.yml @@ -62,6 +62,7 @@ jobs: CMOCKA_MESSAGE_OUTPUT: "xml" AZURE_ENABLE_STATIC_ANALYSIS: 1 BuildArgs: "" + VcpkgArgs: "" WindowsCtestConfig: "" CmakeEnvArg: "" CmakeArgs: "" @@ -119,6 +120,7 @@ jobs: parameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} GenerateArgs: $(CmakeArgs) + VcpkgArgs: "$(VcpkgArgs)" BuildArgs: "$(BuildArgs)" Env: "$(CmakeEnvArg)" diff --git a/eng/pipelines/templates/stages/platform-matrix.json b/eng/pipelines/templates/stages/platform-matrix.json index 76d1bd0368..8c6315f643 100644 --- a/eng/pipelines/templates/stages/platform-matrix.json +++ b/eng/pipelines/templates/stages/platform-matrix.json @@ -179,6 +179,10 @@ }, "included_release": { "CMAKE_BUILD_TYPE": "Release" + }, + "openssl_111n": { + "CMAKE_BUILD_TYPE": "Release", + "VcpkgArgs": " -DVCPKG_MANIFEST_MODE=ON -DVCPKG_OVERLAY_PORTS=$(Build.SourcesDirectory)/vcpkg-custom-ports -DVCPKG_MANIFEST_DIR=$(Build.SourcesDirectory)" } } } diff --git a/eng/pipelines/templates/steps/cmake-build.yml b/eng/pipelines/templates/steps/cmake-build.yml index 9918d7f511..9f0bed255c 100644 --- a/eng/pipelines/templates/steps/cmake-build.yml +++ b/eng/pipelines/templates/steps/cmake-build.yml @@ -3,6 +3,7 @@ parameters: GenerateArgs: '' Build: true BuildArgs: '' + VcpkgArgs: '' ServiceDirectory: '' @@ -15,7 +16,7 @@ steps: displayName: cmake --version - script: | - ${{ parameters.Env }} cmake ${{ parameters.GenerateArgs }} .. + ${{ parameters.Env }} cmake ${{ parameters.VcpkgArgs }} ${{ parameters.GenerateArgs }} .. workingDirectory: build displayName: cmake generate env: diff --git a/eng/scripts/Get-BinarySizes.ps1 b/eng/scripts/Get-BinarySizes.ps1 index bbe5be472f..563574074f 100644 --- a/eng/scripts/Get-BinarySizes.ps1 +++ b/eng/scripts/Get-BinarySizes.ps1 @@ -18,6 +18,9 @@ param( [Parameter()] [string] $BuildArgs, + [Parameter()] + [string] $VcpkgArgs, + [Parameter()] [string] $Job, diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index abc9f97fcc..db837a6f82 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -10,6 +10,7 @@ ### Other Changes +- Added the ability to consume version 1.1.1n of OpenSSL. - Added support for Identity token caching, and for configuring token refresh offset in `BearerTokenAuthenticationPolicy`. ## 1.8.0-beta.1 (2022-10-06) diff --git a/sdk/core/azure-core/src/http/curl/curl.cpp b/sdk/core/azure-core/src/http/curl/curl.cpp index fc70778a9d..e7d1ccd199 100644 --- a/sdk/core/azure-core/src/http/curl/curl.cpp +++ b/sdk/core/azure-core/src/http/curl/curl.cpp @@ -37,24 +37,39 @@ #include "curl_session_private.hpp" #if defined(AZ_PLATFORM_POSIX) +#include +#if OPENSSL_VERSION_NUMBER < 0x30000000L +#define USE_OPENSSL_1 +#else +#define USE_OPENSSL_3 +#endif // OPENSSL_VERSION_NUMBER < 0x30000000L + #include #include +// For OpenSSL > 3.0, we can use the new API to get the certificate's OCSP URL. +#if defined(USE_OPENSSL_3) #include +#endif +#if defined(USE_OPENSSL_1) +#include +#endif // defined(USE_OPENSSL_1) #include #include #include #include #include +#endif // AZ_PLATFORM_POSIX + +#if defined(AZ_PLATFORM_POSIX) #include // for poll() #include // for socket shutdown #elif defined(AZ_PLATFORM_WINDOWS) #include // for WSAPoll(); -#endif +#endif // AZ_PLATFORM_POSIX/AZ_PLATFORM_WINDOWS #include #include #include -#include #include #include #include @@ -1383,6 +1398,12 @@ namespace Azure { namespace Core { { using type = BasicUniqueHandle; }; +#if defined(USE_OPENSSL_1) + template <> struct UniqueHandleHelper + { + using type = BasicUniqueHandle; + }; +#endif // USE_OPENSSL_1 template <> struct UniqueHandleHelper { @@ -1445,8 +1466,105 @@ namespace Azure { namespace Core { Azure::Core::_internal::UniqueHandle LoadCrlFromUrl(std::string const& url) { Log::Write(Logger::Level::Informational, "Load CRL from Url: " + url); - auto crl = Azure::Core::_internal::MakeUniqueHandle( + Azure::Core::_internal::UniqueHandle crl; +#if defined(USE_OPENSSL_3) + crl = Azure::Core::_internal::MakeUniqueHandle( X509_CRL_load_http, url.c_str(), nullptr, nullptr, 5); +#else + std::string host, port, path; + int use_ssl; + { + char *host_ptr, *port_ptr, *path_ptr; + if (!OCSP_parse_url(url.c_str(), &host_ptr, &port_ptr, &path_ptr, &use_ssl)) + { + Log::Write(Logger::Level::Error, "Failure parsing URL"); + return nullptr; + } + host = host_ptr; + port = port_ptr; + path = path_ptr; + } + + if (use_ssl) + { + Log::Write(Logger::Level::Error, "CRL HTTPS not supported"); + return nullptr; + } + Azure::Core::_internal::UniqueHandle bio{ + Azure::Core::_internal::MakeUniqueHandle(BIO_new_connect, host.c_str())}; + if (!bio) + { + Log::Write( + Logger::Level::Error, + "BIO_new_connect failed" + _detail::GetOpenSSLError("Load CRL")); + return nullptr; + } + if (!BIO_set_conn_port(bio.get(), const_cast(port.c_str()))) + { + Log::Write( + Logger::Level::Error, + "BIO_set_conn_port failed" + _detail::GetOpenSSLError("Load CRL")); + return nullptr; + } + + auto requestContext + = Azure::Core::_internal::MakeUniqueHandle(OCSP_REQ_CTX_new, bio.get(), 1024 * 1024); + if (!requestContext) + { + Log::Write( + Logger::Level::Error, + "OCSP_REQ_CTX_new failed" + _detail::GetOpenSSLError("Load CRL")); + return nullptr; + } + + // By default the OCSP APIs limit the CRL length to 1M, that isn't sufficient + // for many web sites, so increase it to 10M. + OCSP_set_max_response_length(requestContext.get(), 10 * 1024 * 1024); + + if (!OCSP_REQ_CTX_http(requestContext.get(), "GET", url.c_str())) + { + Log::Write( + Logger::Level::Error, + "OCSP_REQ_CTX_http failed" + _detail::GetOpenSSLError("Load CRL")); + return nullptr; + } + + if (!OCSP_REQ_CTX_add1_header(requestContext.get(), "Host", host.c_str())) + { + Log::Write( + Logger::Level::Error, + "OCSP_REQ_add1_header failed" + _detail::GetOpenSSLError("Load CRL")); + return nullptr; + } + + { + X509_CRL* crl_ptr = nullptr; + int rv; + do + { + rv = X509_CRL_http_nbio(requestContext.get(), &crl_ptr); + } while (rv == -1); + + if (rv != 1) + { + if (ERR_peek_error() == 0) + { + Log::Write( + Logger::Level::Error, + "X509_CRL_http_nbio failed, possible because CRL is too long."); + } + else + { + Log::Write( + Logger::Level::Error, + "X509_CRL_http_nbio failed" + _detail::GetOpenSSLError("Load CRL")); + } + return nullptr; + } + crl.reset(crl_ptr); + } + +#endif if (!crl) { Log::Write(Logger::Level::Error, _detail::GetOpenSSLError("Load CRL")); @@ -1692,7 +1810,11 @@ namespace Azure { namespace Core { * @brief Retrieve the CRL associated with the provided store context, if available. * */ +#if defined(USE_OPENSSL_3) STACK_OF(X509_CRL) * CrlHttpCallback(const X509_STORE_CTX* context, const X509_NAME*) +#else + STACK_OF(X509_CRL) * CrlHttpCallback(X509_STORE_CTX* context, X509_NAME*) +#endif { Azure::Core::_internal::UniqueHandle crl; STACK_OF(DIST_POINT) * crlDistributionPoint; diff --git a/vcpkg-custom-ports/openssl/install-pc-files.cmake b/vcpkg-custom-ports/openssl/install-pc-files.cmake new file mode 100644 index 0000000000..eb8d2b8c28 --- /dev/null +++ b/vcpkg-custom-ports/openssl/install-pc-files.cmake @@ -0,0 +1,32 @@ +function(install_pc_file name pc_data) + if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release") + configure_file("${CMAKE_CURRENT_LIST_DIR}/openssl.pc.in" "${CURRENT_PACKAGES_DIR}/lib/pkgconfig/${name}.pc" @ONLY) + endif() + if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug") + configure_file("${CMAKE_CURRENT_LIST_DIR}/openssl.pc.in" "${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/${name}.pc" @ONLY) + endif() +endfunction() + +install_pc_file(openssl [[ +Name: OpenSSL +Description: Secure Sockets Layer and cryptography libraries and tools +Requires: libssl libcrypto +]]) + +install_pc_file(libssl [[ +Name: OpenSSL-libssl +Description: Secure Sockets Layer and cryptography libraries +Libs: -L"${libdir}" -llibssl +Requires: libcrypto +Cflags: -I"${includedir}" +]]) + +install_pc_file(libcrypto [[ +Name: OpenSSL-libcrypto +Description: OpenSSL cryptography library +Libs: -L"${libdir}" -llibcrypto +Libs.private: -lcrypt32 -lws2_32 +Cflags: -I"${includedir}" +]]) + +vcpkg_fixup_pkgconfig() diff --git a/vcpkg-custom-ports/openssl/openssl.pc.in b/vcpkg-custom-ports/openssl/openssl.pc.in new file mode 100644 index 0000000000..3033e1804d --- /dev/null +++ b/vcpkg-custom-ports/openssl/openssl.pc.in @@ -0,0 +1,6 @@ +prefix=${pcfiledir}/../.. +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include +Version: @OPENSSL_VERSION@ +@pc_data@ diff --git a/vcpkg-custom-ports/openssl/portfile.cmake b/vcpkg-custom-ports/openssl/portfile.cmake new file mode 100644 index 0000000000..e94e7a83f0 --- /dev/null +++ b/vcpkg-custom-ports/openssl/portfile.cmake @@ -0,0 +1,28 @@ +if(EXISTS "${CURRENT_INSTALLED_DIR}/include/openssl/ssl.h") + message(FATAL_ERROR "Can't build openssl if libressl/boringssl is installed. Please remove libressl/boringssl, and try install openssl again if you need it.") +endif() + +set(OPENSSL_VERSION 1.1.1n) +vcpkg_download_distfile( + ARCHIVE + URLS "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz" "https://www.openssl.org/source/old/1.1.1/openssl-${OPENSSL_VERSION}.tar.gz" + FILENAME "openssl-${OPENSSL_VERSION}.tar.gz" + SHA512 1937796736613dcf4105a54e42ecb61f95a1cea74677156f9459aea0f2c95159359e766089632bf364ee6b0d28d661eb9957bce8fecc9d2436378d8d79e8d0a4 +) + +vcpkg_find_acquire_program(PERL) +get_filename_component(PERL_EXE_PATH ${PERL} DIRECTORY) +vcpkg_add_to_path("${PERL_EXE_PATH}") + +if(VCPKG_TARGET_IS_UWP) + include("${CMAKE_CURRENT_LIST_DIR}/uwp/portfile.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/install-pc-files.cmake") +elseif(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW) + include("${CMAKE_CURRENT_LIST_DIR}/windows/portfile.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/install-pc-files.cmake") +else() + include("${CMAKE_CURRENT_LIST_DIR}/unix/portfile.cmake") +endif() + +configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake.in" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake" @ONLY) +file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") diff --git a/vcpkg-custom-ports/openssl/unix/CMakeLists.txt b/vcpkg-custom-ports/openssl/unix/CMakeLists.txt new file mode 100644 index 0000000000..52bfcfff3c --- /dev/null +++ b/vcpkg-custom-ports/openssl/unix/CMakeLists.txt @@ -0,0 +1,284 @@ +cmake_minimum_required(VERSION 3.9) +project(openssl C) + +if(NOT SOURCE_PATH) + message(FATAL_ERROR "Requires SOURCE_PATH") +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Android" OR CMAKE_SYSTEM_NAME STREQUAL "Linux") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(PLATFORM linux-x86_64) + else() + set(PLATFORM linux-generic32) + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") + if(VCPKG_TARGET_ARCHITECTURE MATCHES "arm64") + set(PLATFORM ios64-xcrun) + elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "arm") + set(PLATFORM ios-xcrun) + elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "x86" OR + VCPKG_TARGET_ARCHITECTURE MATCHES "x64") + set(PLATFORM iossimulator-xcrun) + else() + message(FATAL_ERROR "Unknown iOS target architecture: ${VCPKG_TARGET_ARCHITECTURE}") + endif() + # disable that makes linkage error (e.g. require stderr usage) + list(APPEND DISABLES no-stdio no-ui no-asm) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + if(VCPKG_TARGET_ARCHITECTURE MATCHES "arm64") + set(PLATFORM darwin64-arm64-cc) + else() + set(PLATFORM darwin64-x86_64-cc) + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + set(PLATFORM BSD-generic64) +elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + set(PLATFORM BSD-generic64) +elseif(MINGW) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(PLATFORM mingw64) + else() + set(PLATFORM mingw) + endif() +elseif(EMSCRIPTEN) + set(MAKE $ENV{EMSDK}/upstream/emscripten/emmake) + set(ENV{MAKE} $ENV{EMSDK}/upstream/emscripten/emmake) +else() + message(FATAL_ERROR "Unknown platform") +endif() + +get_filename_component(COMPILER_ROOT "${CMAKE_C_COMPILER}" DIRECTORY) + +message("CMAKE_C_COMPILER=${CMAKE_C_COMPILER}") +message("COMPILER_ROOT=${COMPILER_ROOT}") +message("CMAKE_SYSROOT=${CMAKE_SYSROOT}") +message("CMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT}") +message("CMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") +message("CMAKE_C_FLAGS=${CMAKE_C_FLAGS}") +message("CMAKE_C_FLAGS_RELEASE=${CMAKE_C_FLAGS_RELEASE}") +message("CMAKE_C_FLAGS_DEBUG=${CMAKE_C_FLAGS_DEBUG}") +message("CMAKE_INCLUDE_SYSTEM_FLAG_C=${CMAKE_INCLUDE_SYSTEM_FLAG_C}") +message("CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG=${CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG}") + +string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE) +set(CFLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${BUILD_TYPE}}") +if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + set(CFLAGS "${CFLAGS} -Wno-error=unused-command-line-argument") +endif() +if(CMAKE_C_COMPILER_TARGET AND CMAKE_C_COMPILE_OPTIONS_TARGET) + set(CFLAGS "${CFLAGS} ${CMAKE_C_COMPILE_OPTIONS_TARGET}${CMAKE_C_COMPILER_TARGET}") +endif() +if(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN AND CMAKE_C_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN) + set(CFLAGS "${CFLAGS} ${CMAKE_C_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN}${CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN}") +endif() +if(CMAKE_SYSROOT AND CMAKE_C_COMPILE_OPTIONS_SYSROOT) + set(CFLAGS "${CFLAGS} ${CMAKE_C_COMPILE_OPTIONS_SYSROOT}${CMAKE_SYSROOT}") +elseif(CMAKE_OSX_SYSROOT AND CMAKE_C_COMPILE_OPTIONS_SYSROOT) + set(CFLAGS "${CFLAGS} ${CMAKE_C_COMPILE_OPTIONS_SYSROOT}${CMAKE_OSX_SYSROOT}") +endif() +if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG) + set(CFLAGS "${CFLAGS} ${CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}") +elseif((CMAKE_SYSTEM_NAME STREQUAL "Darwin") AND (VCPKG_TARGET_ARCHITECTURE MATCHES "arm64")) + set(CFLAGS "${CFLAGS} -mmacosx-version-min=11.0") +endif() + +string(REGEX REPLACE "^ " "" CFLAGS "${CFLAGS}") + +if(CMAKE_HOST_WIN32) + file(TO_NATIVE_PATH ENV_PATH "${COMPILER_ROOT};$ENV{PATH}") +else() + file(TO_NATIVE_PATH ENV_PATH "${COMPILER_ROOT}:$ENV{PATH}") +endif() +set(ENV{ANDROID_DEV} "${CMAKE_SYSROOT}/usr") + +if(NOT IOS) + set(ENV{CC} "${CMAKE_C_COMPILER}") +endif() + +message("ENV{ANDROID_DEV}=$ENV{ANDROID_DEV}") + +get_filename_component(SOURCE_PATH_NAME "${SOURCE_PATH}" NAME) +set(BUILDDIR "${CMAKE_CURRENT_BINARY_DIR}/${SOURCE_PATH_NAME}") + +if(NOT EXISTS "${BUILDDIR}") + file(COPY ${SOURCE_PATH} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +endif() + +get_filename_component(MSYS_BIN_DIR "${MAKE}" DIRECTORY) + +if(BUILD_SHARED_LIBS) + set(SHARED shared) + file(STRINGS "${BUILDDIR}/include/openssl/opensslv.h" SHLIB_VERSION + REGEX "^#[\t ]*define[\t ]+SHLIB_VERSION_NUMBER[\t ]+\".*\".*") + string(REGEX REPLACE "^.*SHLIB_VERSION_NUMBER[\t ]+\"([^\"]*)\".*$" "\\1" + SHLIB_VERSION "${SHLIB_VERSION}") + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS") + set(LIB_EXT dylib) + set(LIB_EXTS ${SHLIB_VERSION}.${LIB_EXT}) + elseif(MINGW) + string(REPLACE "." "_" SHLIB_VERSION "${SHLIB_VERSION}") + set(BIN_EXT dll) + set(LIB_EXT dll.a) + else() + set(LIB_EXT so) + set(LIB_EXTS ${LIB_EXT}.${SHLIB_VERSION}) + endif() + list(APPEND BIN_EXTS ${BIN_EXT}) + list(APPEND LIB_EXTS ${LIB_EXT}) +else() + set(SHARED no-shared) + set(LIB_EXTS a) +endif() +set(INSTALL_PKG_CONFIGS "${BUILDDIR}/openssl.pc") +foreach(lib ssl crypto) + foreach(ext ${LIB_EXTS}) + list(APPEND INSTALL_LIBS "${BUILDDIR}/lib${lib}.${ext}") + list(APPEND INSTALL_PKG_CONFIGS "${BUILDDIR}/lib${lib}.pc") + endforeach() + foreach(ext ${BIN_EXTS}) + # This might be wrong for targets which don't follow this naming scheme, but I'm not aware of any + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + list(APPEND INSTALL_BINS "${BUILDDIR}/lib${lib}-${SHLIB_VERSION}-x64.${ext}") + else() + list(APPEND INSTALL_BINS "${BUILDDIR}/lib${lib}-${SHLIB_VERSION}.${ext}") + endif() + endforeach() +endforeach() + +if(CMAKE_HOST_WIN32) + set(ENV_COMMAND set) + set(PATH_VAR ";%PATH%") +else() + set(ENV_COMMAND export) + set(PATH_VAR ":$ENV{PATH}") +endif() + +add_custom_command( + OUTPUT "${BUILDDIR}/Makefile" + COMMAND ${ENV_COMMAND} "PATH=${MSYS_BIN_DIR}${PATH_VAR}" + VERBATIM + WORKING_DIRECTORY "${BUILDDIR}" +) + +if(NOT IOS) + add_custom_command( + OUTPUT "${BUILDDIR}/Makefile" + COMMAND ${ENV_COMMAND} CC=${CMAKE_C_COMPILER} + COMMAND ${ENV_COMMAND} AR=${CMAKE_AR} + COMMAND ${ENV_COMMAND} LD=${CMAKE_LINKER} + COMMAND ${ENV_COMMAND} RANLIB=${CMAKE_RANLIB} + COMMAND ${ENV_COMMAND} MAKE=${MAKE} + COMMAND ${ENV_COMMAND} MAKEDEPPROG=${CMAKE_C_COMPILER} + COMMAND ${ENV_COMMAND} WINDRES=${CMAKE_RC_COMPILER} + VERBATIM + APPEND + ) + if(EMSCRIPTEN) + list(APPEND DISABLES + threads + no-engine + no-dso + no-asm + no-shared + no-sse2 + no-srtp + ) + else() + list(APPEND DISABLES + enable-static-engine + no-zlib + no-ssl2 + no-idea + no-cast + no-seed + no-md2 + no-tests) + endif() +endif() + +if(EMSCRIPTEN) + add_custom_command( + OUTPUT "${BUILDDIR}/Makefile" + COMMAND "$ENV{EMSDK}/upstream/emscripten/emconfigure" ./config + ${SHARED} + ${DISABLES} + "--prefix=${CMAKE_INSTALL_PREFIX}" + "--openssldir=/etc/ssl" + "--cross-compile-prefix=\"/\"" + VERBATIM + APPEND + ) + + add_custom_target(build_libs ALL + COMMAND ${ENV_COMMAND} "PATH=${MSYS_BIN_DIR}${PATH_VAR}" + COMMAND "${CMAKE_COMMAND}" -E touch "${BUILDDIR}/krb5.h" + COMMAND "${MAKE}" make build_libs + VERBATIM + WORKING_DIRECTORY "${BUILDDIR}" + DEPENDS "${BUILDDIR}/Makefile" + BYPRODUCTS ${INSTALL_LIBS} + ) +else() + add_custom_command( + OUTPUT "${BUILDDIR}/Makefile" + COMMAND "${PERL}" Configure + ${SHARED} + ${DISABLES} + ${PLATFORM} + "--prefix=${CMAKE_INSTALL_PREFIX}" + "--openssldir=/etc/ssl" + ${CFLAGS} + VERBATIM + APPEND + ) + + add_custom_target(build_libs ALL + COMMAND ${ENV_COMMAND} "PATH=${MSYS_BIN_DIR}${PATH_VAR}" + COMMAND "${CMAKE_COMMAND}" -E touch "${BUILDDIR}/krb5.h" + COMMAND "${MAKE}" -j ${VCPKG_CONCURRENCY} build_libs + VERBATIM + WORKING_DIRECTORY "${BUILDDIR}" + DEPENDS "${BUILDDIR}/Makefile" + BYPRODUCTS ${INSTALL_LIBS} + ) +endif() + +add_custom_command( + OUTPUT "${BUILDDIR}/Makefile" + COMMAND "${CMAKE_COMMAND}" "-DDIR=${BUILDDIR}" -P "${CMAKE_CURRENT_LIST_DIR}/remove-deps.cmake" + VERBATIM + APPEND +) + +if((CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS") AND BUILD_SHARED_LIBS) + if(DEFINED CMAKE_INSTALL_NAME_DIR) + set(ID_PREFIX "${CMAKE_INSTALL_NAME_DIR}") + else() + set(ID_PREFIX "@rpath") + endif() + + add_custom_command( + TARGET build_libs + COMMAND /usr/bin/install_name_tool -id "${ID_PREFIX}/libssl.${SHLIB_VERSION}.dylib" + "${BUILDDIR}/libssl.${SHLIB_VERSION}.dylib" + COMMAND /usr/bin/install_name_tool -id "${ID_PREFIX}/libcrypto.${SHLIB_VERSION}.dylib" + "${BUILDDIR}/libcrypto.1.1.dylib" + COMMAND /usr/bin/install_name_tool -change "${CMAKE_INSTALL_PREFIX}/lib/libcrypto.${SHLIB_VERSION}.dylib" + "${ID_PREFIX}/libcrypto.${SHLIB_VERSION}.dylib" + "${BUILDDIR}/libssl.${SHLIB_VERSION}.dylib" + VERBATIM + ) +endif() + +install( + FILES ${INSTALL_LIBS} + DESTINATION lib +) +install( + FILES ${INSTALL_BINS} + DESTINATION bin +) +install( + FILES ${INSTALL_PKG_CONFIGS} + DESTINATION lib/pkgconfig +) diff --git a/vcpkg-custom-ports/openssl/unix/portfile.cmake b/vcpkg-custom-ports/openssl/unix/portfile.cmake new file mode 100644 index 0000000000..7a04ae7c9d --- /dev/null +++ b/vcpkg-custom-ports/openssl/unix/portfile.cmake @@ -0,0 +1,38 @@ +vcpkg_extract_source_archive_ex( + OUT_SOURCE_PATH MASTER_COPY_SOURCE_PATH + ARCHIVE "${ARCHIVE}" + REF ${OPENSSL_VERSION} +) + +if(CMAKE_HOST_WIN32) + vcpkg_acquire_msys(MSYS_ROOT PACKAGES make perl) + set(MAKE ${MSYS_ROOT}/usr/bin/make.exe) + set(PERL ${MSYS_ROOT}/usr/bin/perl.exe) +else() + find_program(MAKE make) + if(NOT MAKE) + message(FATAL_ERROR "Could not find make. Please install it through your package manager.") + endif() +endif() + +vcpkg_cmake_configure( + SOURCE_PATH ${CMAKE_CURRENT_LIST_DIR} + OPTIONS + -DSOURCE_PATH=${MASTER_COPY_SOURCE_PATH} + -DPERL=${PERL} + -DMAKE=${MAKE} + -DVCPKG_CONCURRENCY=${VCPKG_CONCURRENCY} +) + +vcpkg_cmake_install() +vcpkg_fixup_pkgconfig() + +file(GLOB HEADERS ${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/*/include/openssl/*.h) +set(RESOLVED_HEADERS) +foreach(HEADER ${HEADERS}) + get_filename_component(X "${HEADER}" REALPATH) + list(APPEND RESOLVED_HEADERS "${X}") +endforeach() + +file(INSTALL ${RESOLVED_HEADERS} DESTINATION ${CURRENT_PACKAGES_DIR}/include/openssl) +file(INSTALL ${MASTER_COPY_SOURCE_PATH}/LICENSE DESTINATION ${CURRENT_PACKAGES_DIR}/share/${PORT} RENAME copyright) diff --git a/vcpkg-custom-ports/openssl/unix/remove-deps.cmake b/vcpkg-custom-ports/openssl/unix/remove-deps.cmake new file mode 100644 index 0000000000..53ad6ef290 --- /dev/null +++ b/vcpkg-custom-ports/openssl/unix/remove-deps.cmake @@ -0,0 +1,7 @@ +file(GLOB_RECURSE MAKEFILES ${DIR}/*/Makefile) +foreach(MAKEFILE ${MAKEFILES}) + message("removing deps from ${MAKEFILE}") + file(READ "${MAKEFILE}" _contents) + string(REGEX REPLACE "\n# DO NOT DELETE THIS LINE.*" "" _contents "${_contents}") + file(WRITE "${MAKEFILE}" "${_contents}") +endforeach() diff --git a/vcpkg-custom-ports/openssl/usage b/vcpkg-custom-ports/openssl/usage new file mode 100644 index 0000000000..cf83f33916 --- /dev/null +++ b/vcpkg-custom-ports/openssl/usage @@ -0,0 +1,4 @@ +The package openssl is compatible with built-in CMake targets: + + find_package(OpenSSL REQUIRED) + target_link_libraries(main PRIVATE OpenSSL::SSL OpenSSL::Crypto) diff --git a/vcpkg-custom-ports/openssl/uwp/EnableUWPSupport.patch b/vcpkg-custom-ports/openssl/uwp/EnableUWPSupport.patch new file mode 100644 index 0000000000..fe78374459 --- /dev/null +++ b/vcpkg-custom-ports/openssl/uwp/EnableUWPSupport.patch @@ -0,0 +1,170 @@ +diff --git a/Configurations/10-main.conf b/Configurations/10-main.conf +index 3c4299d264..99fcb1f713 100644 +--- a/Configurations/10-main.conf ++++ b/Configurations/10-main.conf +@@ -1287,7 +1287,7 @@ my %targets = ( + }, + "VC-WIN64I" => { + inherit_from => [ "VC-WIN64-common", asm("ia64_asm"), +- sub { $disabled{shared} ? () : "ia64_uplink" } ], ++ sub { $disabled{uplink} ? () : "ia64_uplink" } ], + AS => "ias", + ASFLAGS => "-d debug", + asoutflag => "-o ", +@@ -1299,7 +1299,7 @@ my %targets = ( + }, + "VC-WIN64A" => { + inherit_from => [ "VC-WIN64-common", asm("x86_64_asm"), +- sub { $disabled{shared} ? () : "x86_64_uplink" } ], ++ sub { $disabled{uplink} ? () : "x86_64_uplink" } ], + AS => sub { vc_win64a_info()->{AS} }, + ASFLAGS => sub { vc_win64a_info()->{ASFLAGS} }, + asoutflag => sub { vc_win64a_info()->{asoutflag} }, +@@ -1312,7 +1312,7 @@ my %targets = ( + }, + "VC-WIN32" => { + inherit_from => [ "VC-noCE-common", asm("x86_asm"), +- sub { $disabled{shared} ? () : "uplink_common" } ], ++ sub { $disabled{uplink} ? () : "uplink_common" } ], + AS => sub { vc_win32_info()->{AS} }, + ASFLAGS => sub { vc_win32_info()->{ASFLAGS} }, + asoutflag => sub { vc_win32_info()->{asoutflag} }, +@@ -1374,7 +1374,7 @@ my %targets = ( + #### MinGW + "mingw" => { + inherit_from => [ "BASE_unix", asm("x86_asm"), +- sub { $disabled{shared} ? () : "x86_uplink" } ], ++ sub { $disabled{uplink} ? () : "x86_uplink" } ], + CC => "gcc", + CFLAGS => picker(default => "-Wall", + debug => "-g -O0", +diff --git a/Configurations/50-win-onecore.conf b/Configurations/50-win-onecore.conf +index d478f42b0f..e0fb70daca 100644 +--- a/Configurations/50-win-onecore.conf ++++ b/Configurations/50-win-onecore.conf +@@ -1,3 +1,4 @@ ++## -*- mode: perl; -*- + # Windows OneCore targets. + # + # OneCore is new API stability "contract" that transcends Desktop, IoT and +@@ -10,6 +11,25 @@ + # TODO: extend error handling to use ETW based eventing + # (Or rework whole error messaging) + ++my $UWP_info = {}; ++sub UWP_info { ++ unless (%$UWP_info) { ++ my $SDKver = `pwsh.exe -Command \"& {\$(Get-Item \\\"hklm:\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\\").GetValue(\\\"CurrentVersion\\\")}\"`; ++ $SDKver =~ s|\R$||; ++ my @SDKver_split = split(/\./, $SDKver); ++ # SDK version older than 10.0.17763 don't support our ASM builds ++ if ($SDKver_split[0] < 10 ++ || ($SDKver_split[0] == 10 ++ && $SDKver_split[1] == 0 ++ && $SDKver_split[2] < 17763)) { ++ $UWP_info->{disable} = [ 'asm' ]; ++ } else { ++ $UWP_info->{disable} = [ ]; ++ } ++ } ++ return $UWP_info; ++} ++ + my %targets = ( + "VC-WIN32-ONECORE" => { + inherit_from => [ "VC-WIN32" ], +@@ -61,4 +81,57 @@ my %targets = ( + ex_libs => "onecore.lib", + multilib => "-arm64", + }, ++ ++ # Universal Windows Platform (UWP) App Support ++ ++ # TODO ++ # ++ # The 'disable' attribute should have 'uplink'. ++ # however, these are checked in some 'inherit_from', which is processed ++ # very early, before the 'disable' attributes are seen. ++ # This is a problem that needs to be resolved in Configure first. ++ # ++ # But if you want to build library with Windows 10 Version 1809 SDK or ++ # earlier, the 'disable' attribute should also have 'asm'. ++ ++ "VC-WIN32-UWP" => { ++ inherit_from => [ "VC-WIN32-ONECORE" ], ++ lflags => add("/APPCONTAINER"), ++ defines => add("WINAPI_FAMILY=WINAPI_FAMILY_APP", ++ "_WIN32_WINNT=0x0A00"), ++ dso_scheme => "", ++ disable => sub { [ 'ui-console', 'stdio', 'async', 'uplink', ++ @{ UWP_info()->{disable} } ] }, ++ ex_libs => "WindowsApp.lib", ++ }, ++ "VC-WIN64A-UWP" => { ++ inherit_from => [ "VC-WIN64A-ONECORE" ], ++ lflags => add("/APPCONTAINER"), ++ defines => add("WINAPI_FAMILY=WINAPI_FAMILY_APP", ++ "_WIN32_WINNT=0x0A00"), ++ dso_scheme => "", ++ disable => sub { [ 'ui-console', 'stdio', 'async', 'uplink', ++ @{ UWP_info()->{disable} } ] }, ++ ex_libs => "WindowsApp.lib", ++ }, ++ "VC-WIN32-ARM-UWP" => { ++ inherit_from => [ "VC-WIN32-ARM" ], ++ lflags => add("/APPCONTAINER"), ++ defines => add("WINAPI_FAMILY=WINAPI_FAMILY_APP", ++ "_WIN32_WINNT=0x0A00"), ++ dso_scheme => "", ++ disable => sub { [ 'ui-console', 'stdio', 'async', 'uplink', ++ @{ UWP_info()->{disable} } ] }, ++ ex_libs => "WindowsApp.lib", ++ }, ++ "VC-WIN64-ARM-UWP" => { ++ inherit_from => [ "VC-WIN64-ARM" ], ++ lflags => add("/APPCONTAINER"), ++ defines => add("WINAPI_FAMILY=WINAPI_FAMILY_APP", ++ "_WIN32_WINNT=0x0A00"), ++ dso_scheme => "", ++ disable => sub { [ 'ui-console', 'stdio', 'async', 'uplink', ++ @{ UWP_info()->{disable} } ] }, ++ ex_libs => "WindowsApp.lib", ++ }, + ); +diff --git a/Configure b/Configure +index 5a699836f3..de45f1e299 100755 +--- a/Configure ++++ b/Configure +@@ -407,6 +408,7 @@ my @disablables = ( + "ubsan", + "ui-console", + "unit-test", ++ "uplink", + "whirlpool", + "weak-ssl-ciphers", + "zlib", +@@ -491,8 +493,8 @@ my @disable_cascades = ( + + # Without position independent code, there can be no shared libraries or DSOs + "pic" => [ "shared" ], +- "shared" => [ "dynamic-engine" ], ++ "shared" => [ "dynamic-engine", "uplink" ], + "dso" => [ "dynamic-engine" ], + "engine" => [ "afalgeng", "devcryptoeng" ], + + # no-autoalginit is only useful when building non-shared +diff --git a/INSTALL b/INSTALL +index 2119cbae9e..ee54e8c215 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -560,6 +560,10 @@ + likely to complement configuration command line with + suitable compiler-specific option. + ++ no-uplink ++ Don't build support for UPLINK interface. ++ ++ + no- + Don't build support for negotiating the specified SSL/TLS + protocol (one of ssl, ssl3, tls, tls1, tls1_1, tls1_2, diff --git a/vcpkg-custom-ports/openssl/uwp/make-openssl.bat b/vcpkg-custom-ports/openssl/uwp/make-openssl.bat new file mode 100644 index 0000000000..6f6166a24e --- /dev/null +++ b/vcpkg-custom-ports/openssl/uwp/make-openssl.bat @@ -0,0 +1,16 @@ +set build=%1 + +perl Configure no-asm no-hw no-dso VC-WINUNIVERSAL -FS -FIWindows.h + +for /D %%f in ("%WindowsSdkDir%References\%WindowsSDKLibVersion%Windows.Foundation.FoundationContract\*") do set LibPath=%LibPath%;%%f\ +for /D %%f in ("%WindowsSdkDir%References\%WindowsSDKLibVersion%Windows.Foundation.UniversalApiContract\*") do set LibPath=%LibPath%;%%f\ +for /D %%f in ("%WindowsSdkDir%References\Windows.Foundation.FoundationContract\*") do set LibPath=%LibPath%;%%f\ +for /D %%f in ("%WindowsSdkDir%References\Windows.Foundation.UniversalApiContract\*") do set LibPath=%LibPath%;%%f\ + +call ms\do_winuniversal.bat + +mkdir inc32\openssl + +jom -j %NUMBER_OF_PROCESSORS% -k -f ms\ntdll.mak +REM due to a race condition in the build, we need to have a second single-threaded pass. +nmake -f ms\ntdll.mak diff --git a/vcpkg-custom-ports/openssl/uwp/portfile.cmake b/vcpkg-custom-ports/openssl/uwp/portfile.cmake new file mode 100644 index 0000000000..9414634fe2 --- /dev/null +++ b/vcpkg-custom-ports/openssl/uwp/portfile.cmake @@ -0,0 +1,163 @@ +vcpkg_find_acquire_program(JOM) +get_filename_component(JOM_EXE_PATH ${JOM} DIRECTORY) +vcpkg_add_to_path("${PERL_EXE_PATH}") + +set(OPENSSL_SHARED no-shared) +if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") + set(OPENSSL_SHARED shared) +endif() + +vcpkg_extract_source_archive_ex( + OUT_SOURCE_PATH SOURCE_PATH + ARCHIVE ${ARCHIVE} + PATCHES + uwp/EnableUWPSupport.patch +) + +vcpkg_find_acquire_program(NASM) +get_filename_component(NASM_EXE_PATH ${NASM} DIRECTORY) +vcpkg_add_to_path(PREPEND "${NASM_EXE_PATH}") + +set(CONFIGURE_COMMAND ${PERL} Configure + enable-static-engine + enable-capieng + no-unit-test + no-ssl2 + no-asm + no-uplink + no-tests + -utf-8 + ${OPENSSL_SHARED} +) + +if(VCPKG_TARGET_ARCHITECTURE STREQUAL "x86") + set(OPENSSL_ARCH VC-WIN32-UWP) +elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") + set(OPENSSL_ARCH VC-WIN64A-UWP) +elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "arm") + set(OPENSSL_ARCH VC-WIN32-ARM-UWP) +elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "arm64") + set(OPENSSL_ARCH VC-WIN64-ARM-UWP) +else() + message(FATAL_ERROR "Unsupported target architecture: ${VCPKG_TARGET_ARCHITECTURE}") +endif() + +set(OPENSSL_MAKEFILE "makefile") + +file(REMOVE_RECURSE ${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel ${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg) + + +if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release") + + # Copy openssl sources. + message(STATUS "Copying openssl release source files...") + file(GLOB OPENSSL_SOURCE_FILES "${SOURCE_PATH}/*") + foreach(SOURCE_FILE ${OPENSSL_SOURCE_FILES}) + file(COPY ${SOURCE_FILE} DESTINATION "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel") + endforeach() + message(STATUS "Copying openssl release source files... done") + set(SOURCE_PATH_RELEASE "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel") + + set(OPENSSLDIR_RELEASE "${CURRENT_PACKAGES_DIR}") + + message(STATUS "Configure ${TARGET_TRIPLET}-rel") + vcpkg_execute_required_process( + COMMAND ${CONFIGURE_COMMAND} ${OPENSSL_ARCH} "--prefix=${OPENSSLDIR_RELEASE}" "--openssldir=${OPENSSLDIR_RELEASE}" -FS + WORKING_DIRECTORY "${SOURCE_PATH_RELEASE}" + LOGNAME configure-perl-${TARGET_TRIPLET}-${VCPKG_BUILD_TYPE}-rel + ) + message(STATUS "Configure ${TARGET_TRIPLET}-rel done") + + message(STATUS "Build ${TARGET_TRIPLET}-rel") + # Openssl's buildsystem has a race condition which will cause JOM to fail at some point. + # This is ok; we just do as much work as we can in parallel first, then follow up with a single-threaded build. + make_directory(${SOURCE_PATH_RELEASE}/inc32/openssl) + execute_process( + COMMAND "${JOM}" -k -j ${VCPKG_CONCURRENCY} -f "${OPENSSL_MAKEFILE}" build_libs + WORKING_DIRECTORY "${SOURCE_PATH_RELEASE}" + OUTPUT_FILE "${CURRENT_BUILDTREES_DIR}/build-${TARGET_TRIPLET}-rel-0-out.log" + ERROR_FILE "${CURRENT_BUILDTREES_DIR}/build-${TARGET_TRIPLET}-rel-0-err.log" + ) + vcpkg_execute_required_process( + COMMAND nmake -f "${OPENSSL_MAKEFILE}" install_dev + WORKING_DIRECTORY "${SOURCE_PATH_RELEASE}" + LOGNAME build-${TARGET_TRIPLET}-rel-1) + + message(STATUS "Build ${TARGET_TRIPLET}-rel done") +endif() + + +if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug") + # Copy openssl sources. + message(STATUS "Copying openssl debug source files...") + file(GLOB OPENSSL_SOURCE_FILES ${SOURCE_PATH}/*) + foreach(SOURCE_FILE ${OPENSSL_SOURCE_FILES}) + file(COPY "${SOURCE_FILE}" DESTINATION "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg") + endforeach() + message(STATUS "Copying openssl debug source files... done") + set(SOURCE_PATH_DEBUG "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg") + + set(OPENSSLDIR_DEBUG "${CURRENT_PACKAGES_DIR}/debug") + + message(STATUS "Configure ${TARGET_TRIPLET}-dbg") + vcpkg_execute_required_process( + COMMAND ${CONFIGURE_COMMAND} debug-${OPENSSL_ARCH} "--prefix=${OPENSSLDIR_DEBUG}" "--openssldir=${OPENSSLDIR_DEBUG}" -FS + WORKING_DIRECTORY "${SOURCE_PATH_DEBUG}" + LOGNAME configure-perl-${TARGET_TRIPLET}-${VCPKG_BUILD_TYPE}-dbg + ) + message(STATUS "Configure ${TARGET_TRIPLET}-dbg done") + + message(STATUS "Build ${TARGET_TRIPLET}-dbg") + make_directory("${SOURCE_PATH_DEBUG}/inc32/openssl") + execute_process( + COMMAND "${JOM}" -k -j ${VCPKG_CONCURRENCY} -f "${OPENSSL_MAKEFILE}" build_libs + WORKING_DIRECTORY "${SOURCE_PATH_DEBUG}" + OUTPUT_FILE "${CURRENT_BUILDTREES_DIR}/build-${TARGET_TRIPLET}-dbg-0-out.log" + ERROR_FILE "${CURRENT_BUILDTREES_DIR}/build-${TARGET_TRIPLET}-dbg-0-err.log" + ) + vcpkg_execute_required_process( + COMMAND nmake -f "${OPENSSL_MAKEFILE}" install_dev + WORKING_DIRECTORY "${SOURCE_PATH_DEBUG}" + LOGNAME build-${TARGET_TRIPLET}-dbg-1) + + message(STATUS "Build ${TARGET_TRIPLET}-dbg done") +endif() + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/certs") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/private") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/lib/engines-1_1") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/certs") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/lib/engines-1_1") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/private") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +file(REMOVE + "${CURRENT_PACKAGES_DIR}/bin/openssl.exe" + "${CURRENT_PACKAGES_DIR}/debug/bin/openssl.exe" + "${CURRENT_PACKAGES_DIR}/debug/openssl.cnf" + "${CURRENT_PACKAGES_DIR}/openssl.cnf" + "${CURRENT_PACKAGES_DIR}/ct_log_list.cnf" + "${CURRENT_PACKAGES_DIR}/ct_log_list.cnf.dist" + "${CURRENT_PACKAGES_DIR}/openssl.cnf.dist" + "${CURRENT_PACKAGES_DIR}/debug/ct_log_list.cnf" + "${CURRENT_PACKAGES_DIR}/debug/ct_log_list.cnf.dist" + "${CURRENT_PACKAGES_DIR}/debug/openssl.cnf.dist" +) + +if(VCPKG_LIBRARY_LINKAGE STREQUAL static) + # They should be empty, only the exes deleted above were in these directories + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/bin/") + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/bin/") +endif() + +file(READ "${CURRENT_PACKAGES_DIR}/include/openssl/dtls1.h" _contents) +string(REPLACE "" "" _contents "${_contents}") +file(WRITE "${CURRENT_PACKAGES_DIR}/include/openssl/dtls1.h" "${_contents}") + +file(READ "${CURRENT_PACKAGES_DIR}/include/openssl/rand.h" _contents) +string(REPLACE "# include " "#ifndef _WINSOCKAPI_\n#define _WINSOCKAPI_\n#endif\n# include " _contents "${_contents}") +file(WRITE "${CURRENT_PACKAGES_DIR}/include/openssl/rand.h" "${_contents}") + +vcpkg_copy_pdbs() + +file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/vcpkg-custom-ports/openssl/vcpkg-cmake-wrapper.cmake.in b/vcpkg-custom-ports/openssl/vcpkg-cmake-wrapper.cmake.in new file mode 100644 index 0000000000..4a5ee893a2 --- /dev/null +++ b/vcpkg-custom-ports/openssl/vcpkg-cmake-wrapper.cmake.in @@ -0,0 +1,78 @@ +cmake_policy(PUSH) +cmake_policy(SET CMP0012 NEW) +cmake_policy(SET CMP0054 NEW) +cmake_policy(SET CMP0057 NEW) + +if(OPENSSL_USE_STATIC_LIBS) + if("@VCPKG_LIBRARY_LINKAGE@" STREQUAL "dynamic") + message(WARNING "OPENSSL_USE_STATIC_LIBS is set, but vcpkg port openssl was built with dynamic linkage") + endif() + set(OPENSSL_USE_STATIC_LIBS_BAK "${OPENSSL_USE_STATIC_LIBS}") + set(OPENSSL_USE_STATIC_LIBS FALSE) +endif() + +if(DEFINED OPENSSL_ROOT_DIR) + set(OPENSSL_ROOT_DIR_BAK "${OPENSSL_ROOT_DIR}") +endif() +get_filename_component(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY) +get_filename_component(OPENSSL_ROOT_DIR "${OPENSSL_ROOT_DIR}" DIRECTORY) +find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h PATH "${OPENSSL_ROOT_DIR}/include" NO_DEFAULT_PATH) +if(MSVC) + find_library(LIB_EAY_DEBUG NAMES libcrypto PATHS "${OPENSSL_ROOT_DIR}/debug/lib" NO_DEFAULT_PATH) + find_library(LIB_EAY_RELEASE NAMES libcrypto PATHS "${OPENSSL_ROOT_DIR}/lib" NO_DEFAULT_PATH) + find_library(SSL_EAY_DEBUG NAMES libssl PATHS "${OPENSSL_ROOT_DIR}/debug/lib" NO_DEFAULT_PATH) + find_library(SSL_EAY_RELEASE NAMES libssl PATHS "${OPENSSL_ROOT_DIR}/lib" NO_DEFAULT_PATH) +elseif(WIN32) + find_library(LIB_EAY NAMES libcrypto crypto NAMES_PER_DIR) + find_library(SSL_EAY NAMES libssl ssl NAMES_PER_DIR) +else() + find_library(OPENSSL_CRYPTO_LIBRARY NAMES crypto) + find_library(OPENSSL_SSL_LIBRARY NAMES ssl) +endif() + +_find_package(${ARGS}) + +unset(OPENSSL_ROOT_DIR) +if(DEFINED OPENSSL_ROOT_DIR_BAK) + set(OPENSSL_ROOT_DIR "${OPENSSL_ROOT_DIR_BAK}") + unset(OPENSSL_ROOT_DIR_BAK) +endif() + +if(DEFINED OPENSSL_USE_STATIC_LIBS_BAK) + set(OPENSSL_USE_STATIC_LIBS "${OPENSSL_USE_STATIC_LIBS_BAK}") + unset(OPENSSL_USE_STATIC_LIBS_BAK) +endif() + +if(OPENSSL_FOUND AND "@VCPKG_LIBRARY_LINKAGE@" STREQUAL "static") + if(WIN32) + list(APPEND OPENSSL_LIBRARIES crypt32 ws2_32) + if(TARGET OpenSSL::Crypto) + set_property(TARGET OpenSSL::Crypto APPEND PROPERTY INTERFACE_LINK_LIBRARIES "crypt32;ws2_32") + endif() + if(TARGET OpenSSL::SSL) + set_property(TARGET OpenSSL::SSL APPEND PROPERTY INTERFACE_LINK_LIBRARIES "crypt32;ws2_32") + endif() + else() + find_library(OPENSSL_DL_LIBRARY NAMES dl) + if(OPENSSL_DL_LIBRARY) + list(APPEND OPENSSL_LIBRARIES "dl") + if(TARGET OpenSSL::Crypto) + set_property(TARGET OpenSSL::Crypto APPEND PROPERTY INTERFACE_LINK_LIBRARIES "dl") + endif() + endif() + + if("REQUIRED" IN_LIST ARGS) + find_package(Threads REQUIRED) + else() + find_package(Threads) + endif() + list(APPEND OPENSSL_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) + if(TARGET OpenSSL::Crypto) + set_property(TARGET OpenSSL::Crypto APPEND PROPERTY INTERFACE_LINK_LIBRARIES "Threads::Threads") + endif() + if(TARGET OpenSSL::SSL) + set_property(TARGET OpenSSL::SSL APPEND PROPERTY INTERFACE_LINK_LIBRARIES "Threads::Threads") + endif() + endif() +endif() +cmake_policy(POP) diff --git a/vcpkg-custom-ports/openssl/vcpkg.json b/vcpkg-custom-ports/openssl/vcpkg.json new file mode 100644 index 0000000000..beb5807743 --- /dev/null +++ b/vcpkg-custom-ports/openssl/vcpkg.json @@ -0,0 +1,18 @@ +{ + "name": "openssl", + "version-string": "1.1.1n", + "port-version": 1, + "description": "OpenSSL is an open source project that provides a robust, commercial-grade, and full-featured toolkit for the Transport Layer Security (TLS) and Secure Sockets Layer (SSL) protocols. It is also a general-purpose cryptography library.", + "homepage": "https://www.openssl.org", + "license": "OpenSSL", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +} diff --git a/vcpkg-custom-ports/openssl/windows/portfile.cmake b/vcpkg-custom-ports/openssl/windows/portfile.cmake new file mode 100644 index 0000000000..5a0dec0b73 --- /dev/null +++ b/vcpkg-custom-ports/openssl/windows/portfile.cmake @@ -0,0 +1,172 @@ +vcpkg_extract_source_archive_ex( + OUT_SOURCE_PATH SOURCE_PATH + ARCHIVE ${ARCHIVE} +) + +vcpkg_find_acquire_program(NASM) +get_filename_component(NASM_EXE_PATH "${NASM}" DIRECTORY) +vcpkg_add_to_path(PREPEND "${NASM_EXE_PATH}") + +vcpkg_find_acquire_program(JOM) + +set(OPENSSL_SHARED no-shared) +if(VCPKG_LIBRARY_LINKAGE STREQUAL dynamic) + set(OPENSSL_SHARED shared) +endif() + +set(CONFIGURE_OPTIONS + enable-static-engine + enable-capieng + no-ssl2 + no-tests + -utf-8 + ${OPENSSL_SHARED} +) + +if(DEFINED OPENSSL_USE_NOPINSHARED) + set(CONFIGURE_OPTIONS ${CONFIGURE_OPTIONS} no-pinshared) +endif() + +if(OPENSSL_NO_AUTOLOAD_CONFIG) + set(CONFIGURE_OPTIONS ${CONFIGURE_OPTIONS} no-autoload-config) +endif() + +set(CONFIGURE_COMMAND "${PERL}" Configure ${CONFIGURE_OPTIONS}) + +if(VCPKG_TARGET_ARCHITECTURE STREQUAL "x86") + set(OPENSSL_ARCH VC-WIN32) +elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") + set(OPENSSL_ARCH VC-WIN64A) +elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "arm") + set(OPENSSL_ARCH VC-WIN32-ARM) +elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "arm64") + set(OPENSSL_ARCH VC-WIN64-ARM) +else() + message(FATAL_ERROR "Unsupported target architecture: ${VCPKG_TARGET_ARCHITECTURE}") +endif() + +set(OPENSSL_MAKEFILE "makefile") + +file(REMOVE_RECURSE "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel" + "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg") + +if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release") + + # Copy openssl sources. + message(STATUS "Copying openssl release source files...") + file(GLOB OPENSSL_SOURCE_FILES ${SOURCE_PATH}/*) + foreach(SOURCE_FILE ${OPENSSL_SOURCE_FILES}) + file(COPY ${SOURCE_FILE} DESTINATION "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel") + endforeach() + message(STATUS "Copying openssl release source files... done") + set(SOURCE_PATH_RELEASE "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel") + + set(OPENSSLDIR_RELEASE ${CURRENT_PACKAGES_DIR}) + + message(STATUS "Configure ${TARGET_TRIPLET}-rel") + vcpkg_execute_required_process( + COMMAND ${CONFIGURE_COMMAND} ${OPENSSL_ARCH} "--prefix=${OPENSSLDIR_RELEASE}" "--openssldir=${OPENSSLDIR_RELEASE}" -FS + WORKING_DIRECTORY ${SOURCE_PATH_RELEASE} + LOGNAME configure-perl-${TARGET_TRIPLET}-rel + ) + message(STATUS "Configure ${TARGET_TRIPLET}-rel done") + + message(STATUS "Build ${TARGET_TRIPLET}-rel") + # Openssl's buildsystem has a race condition which will cause JOM to fail at some point. + # This is ok; we just do as much work as we can in parallel first, then follow up with a single-threaded build. + make_directory(${SOURCE_PATH_RELEASE}/inc32/openssl) + execute_process( + COMMAND "${JOM}" -k -j "${VCPKG_CONCURRENCY}" -f "${OPENSSL_MAKEFILE}" + WORKING_DIRECTORY ${SOURCE_PATH_RELEASE} + OUTPUT_FILE ${CURRENT_BUILDTREES_DIR}/build-${TARGET_TRIPLET}-rel-0-out.log + ERROR_FILE ${CURRENT_BUILDTREES_DIR}/build-${TARGET_TRIPLET}-rel-0-err.log + ) + vcpkg_execute_required_process( + COMMAND "${JOM}" -j 1 -f "${OPENSSL_MAKEFILE}" install_sw install_ssldirs + WORKING_DIRECTORY ${SOURCE_PATH_RELEASE} + LOGNAME build-${TARGET_TRIPLET}-rel-1) + + message(STATUS "Build ${TARGET_TRIPLET}-rel done") +endif() + + +if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug") + # Copy openssl sources. + message(STATUS "Copying openssl debug source files...") + file(GLOB OPENSSL_SOURCE_FILES ${SOURCE_PATH}/*) + foreach(SOURCE_FILE ${OPENSSL_SOURCE_FILES}) + file(COPY ${SOURCE_FILE} DESTINATION "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg") + endforeach() + message(STATUS "Copying openssl debug source files... done") + set(SOURCE_PATH_DEBUG "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg") + + set(OPENSSLDIR_DEBUG ${CURRENT_PACKAGES_DIR}/debug) + + message(STATUS "Configure ${TARGET_TRIPLET}-dbg") + vcpkg_execute_required_process( + COMMAND ${CONFIGURE_COMMAND} debug-${OPENSSL_ARCH} "--prefix=${OPENSSLDIR_DEBUG}" "--openssldir=${OPENSSLDIR_DEBUG}" -FS + WORKING_DIRECTORY ${SOURCE_PATH_DEBUG} + LOGNAME configure-perl-${TARGET_TRIPLET}-dbg + ) + message(STATUS "Configure ${TARGET_TRIPLET}-dbg done") + + message(STATUS "Build ${TARGET_TRIPLET}-dbg") + make_directory(${SOURCE_PATH_DEBUG}/inc32/openssl) + execute_process( + COMMAND "${JOM}" -k -j "${VCPKG_CONCURRENCY}" -f "${OPENSSL_MAKEFILE}" + WORKING_DIRECTORY ${SOURCE_PATH_DEBUG} + OUTPUT_FILE ${CURRENT_BUILDTREES_DIR}/build-${TARGET_TRIPLET}-dbg-0-out.log + ERROR_FILE ${CURRENT_BUILDTREES_DIR}/build-${TARGET_TRIPLET}-dbg-0-err.log + ) + vcpkg_execute_required_process( + COMMAND "${JOM}" -j 1 -f "${OPENSSL_MAKEFILE}" install_sw install_ssldirs + WORKING_DIRECTORY ${SOURCE_PATH_DEBUG} + LOGNAME build-${TARGET_TRIPLET}-dbg-1) + + message(STATUS "Build ${TARGET_TRIPLET}-dbg done") +endif() + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/certs") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/private") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/lib/engines-1_1") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/certs") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/lib/engines-1_1") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/private") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +file(REMOVE + "${CURRENT_PACKAGES_DIR}/ct_log_list.cnf" + "${CURRENT_PACKAGES_DIR}/ct_log_list.cnf.dist" + "${CURRENT_PACKAGES_DIR}/openssl.cnf.dist" + "${CURRENT_PACKAGES_DIR}/debug/bin/openssl.exe" + "${CURRENT_PACKAGES_DIR}/debug/ct_log_list.cnf" + "${CURRENT_PACKAGES_DIR}/debug/ct_log_list.cnf.dist" + "${CURRENT_PACKAGES_DIR}/debug/openssl.cnf" + "${CURRENT_PACKAGES_DIR}/debug/openssl.cnf.dist" +) + +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/tools/openssl/") +file(RENAME "${CURRENT_PACKAGES_DIR}/bin/openssl.exe" "${CURRENT_PACKAGES_DIR}/tools/openssl/openssl.exe") +file(RENAME "${CURRENT_PACKAGES_DIR}/openssl.cnf" "${CURRENT_PACKAGES_DIR}/tools/openssl/openssl.cnf") + +vcpkg_copy_tool_dependencies("${CURRENT_PACKAGES_DIR}/tools/openssl") + +if(VCPKG_LIBRARY_LINKAGE STREQUAL static) + # They should be empty, only the exes deleted above were in these directories + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/bin/") + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/bin/") +endif() + +vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/openssl/dtls1.h" + "" + "" +) + +vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/openssl/rand.h" + "# include " + "#ifndef _WINSOCKAPI_\n#define _WINSOCKAPI_\n#endif\n# include " +) + +vcpkg_copy_pdbs() + +file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) From 4c70c2fdc6af56fcf0cb04059b9cca50056069d9 Mon Sep 17 00:00:00 2001 From: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> Date: Mon, 31 Oct 2022 17:15:04 -0400 Subject: [PATCH 20/21] Dump out correlation id without verbose logging for resource deployment (#4069) Co-authored-by: Ben Broderick Phillips --- .../TestResources/New-TestResources.ps1 | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/eng/common/TestResources/New-TestResources.ps1 b/eng/common/TestResources/New-TestResources.ps1 index 25d8060cc1..8fdcaad7f7 100644 --- a/eng/common/TestResources/New-TestResources.ps1 +++ b/eng/common/TestResources/New-TestResources.ps1 @@ -723,29 +723,27 @@ try { Log $msg $deployment = Retry { - $lastDebugPreference = $DebugPreference - try { - if ($CI) { - $DebugPreference = 'Continue' - } - New-AzResourceGroupDeployment -Name $BaseName -ResourceGroupName $resourceGroup.ResourceGroupName -TemplateFile $templateFile.jsonFilePath -TemplateParameterObject $templateFileParameters -Force:$Force - } catch { - Write-Output @' + New-AzResourceGroupDeployment ` + -Name $BaseName ` + -ResourceGroupName $resourceGroup.ResourceGroupName ` + -TemplateFile $templateFile.jsonFilePath ` + -TemplateParameterObject $templateFileParameters ` + -Force:$Force + } + + if ($deployment.ProvisioningState -ne 'Succeeded') { + Write-Host "Deployment '$($deployment.DeploymentName)' has state '$($deployment.ProvisioningState)' with CorrelationId '$($deployment.CorrelationId)'. Exiting..." + Write-Host @' ##################################################### # For help debugging live test provisioning issues, # -# see http://aka.ms/azsdk/engsys/live-test-help, # +# see http://aka.ms/azsdk/engsys/live-test-help # ##################################################### '@ - throw - } finally { - $DebugPreference = $lastDebugPreference - } + exit 1 } - if ($deployment.ProvisioningState -eq 'Succeeded') { - # New-AzResourceGroupDeployment would've written an error and stopped the pipeline by default anyway. - Write-Verbose "Successfully deployed template '$($templateFile.jsonFilePath)' to resource group '$($resourceGroup.ResourceGroupName)'" - } + Write-Host "Deployment '$($deployment.DeploymentName)' has CorrelationId '$($deployment.CorrelationId)'" + Write-Host "Successfully deployed template '$($templateFile.jsonFilePath)' to resource group '$($resourceGroup.ResourceGroupName)'" $deploymentOutputs = SetDeploymentOutputs $serviceName $context $deployment $templateFile From e9a322d4b7aab5d5e3169c29e8f7f756ff45c0fe Mon Sep 17 00:00:00 2001 From: JinmingHu Date: Tue, 1 Nov 2022 09:42:09 +0800 Subject: [PATCH 21/21] fix typo in PerformanceTesting.md (#4076) --- doc/PerformanceTesting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/PerformanceTesting.md b/doc/PerformanceTesting.md index 625e121c43..bafb0dedff 100644 --- a/doc/PerformanceTesting.md +++ b/doc/PerformanceTesting.md @@ -155,7 +155,7 @@ in the above mentioned folder resided the test defintion file "tests.yml". ### The tests exists in other languages -If the test exists in other languages then making the CPP version visible to the framework requires adding an entry with the name **CPP** under **Service**/**Languages** followed by the pakages and versions available for the testing(this ties into the CMakeLists SetPerfDeps macro). +If the test exists in other languages then making the CPP version visible to the framework requires adding an entry with the name **CPP** under **Service**/**Languages** followed by the packages and versions available for the testing(this ties into the CMakeLists SetPerfDeps macro). Next under the **Tests**/**Test** node with the desired name add the CPP test name. In this section mind the aArguments list , this ies with the regex in the cpp sdk pipeline.yml definition.