diff --git a/.gitignore b/.gitignore index f426b11b3d..6c62b7275b 100644 --- a/.gitignore +++ b/.gitignore @@ -343,3 +343,6 @@ build/ # vscode .vscode/ .factorypath + +# Default Assets restore directory +.assets diff --git a/.vscode/cspell.json b/.vscode/cspell.json index fbd5d8dda6..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", @@ -73,7 +75,9 @@ "HKEY", "HRESULT", "IMDS", + "immutability", "Intel", + "issecret", "itfactor", "iusg", "jepio", diff --git a/CMakeSettings.json b/CMakeSettings.json index 093d2f651c..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" } ] }, @@ -290,7 +348,7 @@ "configurationType": "Debug", "buildRoot": "${projectDir}\\out\\build\\${name}", "installRoot": "${projectDir}\\out\\install\\${name}", - "cmakeCommandArgs": "-DINSTALL_GTEST=OFF -DBUILD_TESTING=ON -DBUILD_TRANSPORT_CURL=ON -DBUILD_SAMPLES=ON -DBUILD_PERFORMANCE_TESTS=ON", + "cmakeCommandArgs": "", "buildCommandArgs": "-v", "inheritEnvironments": [ "msvc_x64_x64" ], "variables": [ @@ -299,6 +357,88 @@ "value": "x64-windows-static", "type": "STRING" }, + { + "name": "INSTALL_GTEST", + "value": "False", + "type": "BOOL" + }, + { + "name": "BUILD_TESTING", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_SAMPLES", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_PERFORMANCE_TESTS", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_TRANSPORT_WINHTTP", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_TRANSPORT_CURL", + "value": "True", + "type": "BOOL" + }, + { + "name": "MSVC_USE_STATIC_CRT", + "value": "True", + "type": "BOOL" + } + ] + }, + { + "name": "x64-ReleaseWithPerfTest", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "-v", + "inheritEnvironments": [ "msvc_x64_x64" ], + "variables": [ + { + "name": "VCPKG_TARGET_TRIPLET", + "value": "x64-windows-static", + "type": "STRING" + }, + { + "name": "INSTALL_GTEST", + "value": "False", + "type": "BOOL" + }, + { + "name": "BUILD_TESTING", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_SAMPLES", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_PERFORMANCE_TESTS", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_TRANSPORT_WINHTTP", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_TRANSPORT_CURL", + "value": "True", + "type": "BOOL" + }, { "name": "MSVC_USE_STATIC_CRT", "value": "True", 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/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/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/cmake-modules/FolderList.cmake b/cmake-modules/FolderList.cmake index 5837920d7e..eae69f4c2b 100644 --- a/cmake-modules/FolderList.cmake +++ b/cmake-modules/FolderList.cmake @@ -18,9 +18,9 @@ macro(GetFolderList project) DownloadDepVersion(sdk/core azure-core 1.7.1) DownloadDepVersion(sdk/storage/azure-storage-common azure-storage-common 12.3.0) elseif(${project} STREQUAL STORAGE_FILES_DATALAKE) - DownloadDepVersion(sdk/core azure-core 1.3.1) - DownloadDepVersion(sdk/storage/azure-storage-common azure-storage-common 12.2.2) - DownloadDepVersion(sdk/storage/azure-storage-blobs azure-storage-blobs 12.3.0) + DownloadDepVersion(sdk/core azure-core 1.7.1) + DownloadDepVersion(sdk/storage/azure-storage-common azure-storage-common 12.3.0) + DownloadDepVersion(sdk/storage/azure-storage-blobs azure-storage-blobs 12.6.2) elseif(${project} STREQUAL STORAGE_FILES_SHARES) DownloadDepVersion(sdk/core azure-core 1.7.1) DownloadDepVersion(sdk/storage/azure-storage-common azure-storage-common 12.3.0) 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/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/doc/PerformanceTesting.md b/doc/PerformanceTesting.md new file mode 100644 index 0000000000..bafb0dedff --- /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 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. + +### 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). + 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/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) } diff --git a/eng/common/scripts/Verify-Links.ps1 b/eng/common/scripts/Verify-Links.ps1 index bdb4762a8e..4bfc212436 100644 --- a/eng/common/scripts/Verify-Links.ps1 +++ b/eng/common/scripts/Verify-Links.ps1 @@ -43,7 +43,7 @@ .PARAMETER outputCacheFile Path to a file that the script will output all the validated links after running all checks. - + .PARAMETER requestTimeoutSec The number of seconds before we timeout when sending an individual web request. Default is 15 seconds. @@ -332,7 +332,7 @@ function GetLinks([System.Uri]$pageUri) { if ($pageUri.Scheme.StartsWith("http")) { try { - $response = Invoke-WebRequest -Uri $pageUri -UserAgent $userAgent -TimeoutSec $requestTimeoutSec + $response = Invoke-WebRequest -Uri $pageUri -UserAgent $userAgent -TimeoutSec $requestTimeoutSec -MaximumRetryCount 3 $content = $response.Content if ($pageUri.ToString().EndsWith(".md")) { @@ -341,7 +341,7 @@ function GetLinks([System.Uri]$pageUri) } catch { $statusCode = $_.Exception.Response.StatusCode.value__ - Write-Error "Invalid page [$statusCode] $pageUri" + LogError "Invalid page [$statusCode] $pageUri" } } elseif ($pageUri.IsFile -and (Test-Path $pageUri.LocalPath)) { @@ -363,7 +363,7 @@ function GetLinks([System.Uri]$pageUri) } } else { - Write-Error "Don't know how to process uri $pageUri" + LogError "Don't know how to process uri $pageUri" } $links = ParseLinks $pageUri $content @@ -396,12 +396,12 @@ if ($inputCacheFile) $cacheContent = "" if ($inputCacheFile.StartsWith("http")) { try { - $response = Invoke-WebRequest -Uri $inputCacheFile -TimeoutSec $requestTimeoutSec + $response = Invoke-WebRequest -Uri $inputCacheFile -TimeoutSec $requestTimeoutSec -MaximumRetryCount 3 $cacheContent = $response.Content } catch { $statusCode = $_.Exception.Response.StatusCode.value__ - Write-Error "Failed to read cache file from page [$statusCode] $inputCacheFile" + LogError "Failed to read cache file from page [$statusCode] $inputCacheFile" } } elseif (Test-Path $inputCacheFile) { diff --git a/eng/common/scripts/get-codeowners.ps1 b/eng/common/scripts/get-codeowners.ps1 index 866569cc61..9606cd66ff 100644 --- a/eng/common/scripts/get-codeowners.ps1 +++ b/eng/common/scripts/get-codeowners.ps1 @@ -1,7 +1,7 @@ param ( [string]$TargetDirectory = "", # Code path to code owners. e.g sdk/core/azure-amqp [string]$CodeOwnerFileLocation = (Resolve-Path $PSScriptRoot/../../../.github/CODEOWNERS), # The absolute path of CODEOWNERS file. - [string]$ToolVersion = "1.0.0-dev.20220121.1", + [string]$ToolVersion = "1.0.0-dev.20221005.1", [string]$ToolPath = (Join-Path ([System.IO.Path]::GetTempPath()) "codeowners-tool-path"), # The place to check the tool existence. Put temp path as default [string]$DevOpsFeed = "https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json", # DevOp tool feeds. [string]$VsoVariable = "", # Option of write code owners into devop variable 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..673e64e73b 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,44 @@ 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 + + VerifyAddonsVersion $chart 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 ` @@ -51,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. @@ -80,8 +113,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..1ddb05cd0c --- /dev/null +++ b/eng/common/scripts/stress-testing/generate-scenario-matrix.ps1 @@ -0,0 +1,90 @@ +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 + } + + $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." + } + } + + $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..0365bbb30c 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). 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" } } diff --git a/eng/common/testproxy/target_version.txt b/eng/common/testproxy/target_version.txt index 5cc40cb14c..95166fc1a8 100644 --- a/eng/common/testproxy/target_version.txt +++ b/eng/common/testproxy/target_version.txt @@ -1 +1 @@ -1.0.0-dev.20220928.2 +1.0.0-dev.20221026.3 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 ffb3678cd9..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)" @@ -133,8 +135,6 @@ jobs: Location: ${{ coalesce(parameters.Location, parameters.CloudConfig.Location) }} SubscriptionConfiguration: $(SubscriptionConfiguration) - - ${{ parameters.PreTestSteps }} - - ${{ parameters.PreTestSteps }} # For non multi-config generator use the same build configuration to run tests diff --git a/eng/pipelines/templates/jobs/perf.yml b/eng/pipelines/templates/jobs/perf.yml index 4e1d328449..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,7 +41,4 @@ extends: Iterations: ${{ parameters.Iterations }} AdditionalArguments: ${{ parameters.AdditionalArguments }} EnvVars: ${{ parameters.EnvVars}} - InstallLanguageSteps: - - template: /eng/pipelines/templates/steps/vcpkg-clone.yml - parameters: - RepoOwner: Microsoft + InstallLanguageSteps: ${{ parameters.InstallLanguageSteps }} 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/attestation/azure-security-attestation/CHANGELOG.md b/sdk/attestation/azure-security-attestation/CHANGELOG.md index e4300cd817..1f47954d18 100644 --- a/sdk/attestation/azure-security-attestation/CHANGELOG.md +++ b/sdk/attestation/azure-security-attestation/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 1.1.0-beta.1 (Unreleased) +## 1.1.0-beta.2 (Unreleased) ### Features Added @@ -15,6 +15,15 @@ ### Other Changes +## 1.1.0-beta.1 (2022-10-11) + +### Breaking Changes + +- Changed `AttestationClient::AttestTpm` to match `AttestOpenEnclave` and `AttestSgxEnclave`: + - Added `std::vector` dataToAttest parameter to the `AttestTpm()` client method. + - Removed `Payload` in `TpmAttestationOptions`. + - Changed `TpmResult` in `TpmAttestationResult` to type `std::vector`. + ## 1.0.0 (2022-07-07) ### Breaking Changes diff --git a/sdk/attestation/azure-security-attestation/src/private/package_version.hpp b/sdk/attestation/azure-security-attestation/src/private/package_version.hpp index 574c556d0c..424964bd3e 100644 --- a/sdk/attestation/azure-security-attestation/src/private/package_version.hpp +++ b/sdk/attestation/azure-security-attestation/src/private/package_version.hpp @@ -11,7 +11,7 @@ #define AZURE_ATTESTATION_VERSION_MAJOR 1 #define AZURE_ATTESTATION_VERSION_MINOR 1 #define AZURE_ATTESTATION_VERSION_PATCH 0 -#define AZURE_ATTESTATION_VERSION_PRERELEASE "beta.1" +#define AZURE_ATTESTATION_VERSION_PRERELEASE "beta.2" #define AZURE_ATTESTATION_VERSION_ITOA_HELPER(i) #i #define AZURE_ATTESTATION_VERSION_ITOA(i) AZURE_ATTESTATION_VERSION_ITOA_HELPER(i) 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/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-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/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-tracing-opentelemetry/test/ut/service_support_test.cpp b/sdk/core/azure-core-tracing-opentelemetry/test/ut/service_support_test.cpp index 66d14624d7..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: { @@ -262,10 +243,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; } @@ -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 @@ -502,10 +483,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. @@ -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; +}; diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index e83939cde4..b763722178 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 1.8.0-beta.1 (Unreleased) +## 1.8.0-beta.2 (Unreleased) ### Features Added @@ -24,6 +24,28 @@ ### 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) + +### Features Added + +- Added support for HTTP proxy servers, both unauthenticated and with Plain authentication. +- Added universal support for several TLS options: + - Added the ability to set the expected TLS root certificate for TLS connection (useful if a proxy server uses a TLS certificate that is not chained to a known root). + - Added the ability to enable TLS certificate revocation list checks (off by default). + - For libcurl only: Allow TLS connection to succeed if CRL retrieval fails. + - *NOTE*: This change only applies if libcurl is built using the OpenSSL crypto backend. It does NOT apply if libcurl uses the schannel (Windows default) or SecureTransport (macOS/iOS default). + +### Breaking Changes + +- Updated retry policy timeouts to conform to Azure guidelines. + - The default delay between retries is changed from 4 seconds to 800ms. + - The maximum retry delay is changed from 2 minutes to 60 seconds (one minute). + + If the original behavior is desired, customers can adjust these timeouts by changing the `RetryDelay` and `MaxRetryDelay` fields in the `RetryOptions` structure. + ## 1.7.2 (2022-09-01) ### Bugs Fixed diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt index 94ff527cd4..3838d0a4bc 100644 --- a/sdk/core/azure-core/CMakeLists.txt +++ b/sdk/core/azure-core/CMakeLists.txt @@ -56,9 +56,10 @@ endif() if(BUILD_TRANSPORT_WINHTTP) SET(WIN_TRANSPORT_ADAPTER_SRC src/http/winhttp/win_http_transport.cpp + src/http/winhttp/win_http_request.hpp src/http/winhttp/win_http_websockets.cpp ) - SET(WIN_TRANSPORT_ADAPTER_INC + SET(WIN_TRANSPORT_ADAPTER_INC inc/azure/core/http/win_http_transport.hpp inc/azure/core/http/websockets/win_http_websockets_transport.hpp ) 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/inc/azure/core/http/websockets/curl_websockets_transport.hpp b/sdk/core/azure-core/inc/azure/core/http/websockets/curl_websockets_transport.hpp index d3b1ecb1ad..9099d669ad 100644 --- a/sdk/core/azure-core/inc/azure/core/http/websockets/curl_websockets_transport.hpp +++ b/sdk/core/azure-core/inc/azure/core/http/websockets/curl_websockets_transport.hpp @@ -35,6 +35,15 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { : CurlTransport(options) { } + /** + * @brief Construct a new CurlWebSocketTransport object. + * + * @param options Optional parameter to override the default options. + */ + CurlWebSocketTransport(Azure::Core::Http::Policies::TransportOptions const& options = {}) + : CurlTransport(options) + { + } /** * @brief Implements interface to send an HTTP Request and produce an HTTP RawResponse @@ -49,9 +58,9 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { /** * @brief Indicates if the transport natively supports websockets or not. * - * @details For the CURL websocket transport, the transport does NOT support native websockets - - * it is the responsibility of the client of the WebSocketTransport to format WebSocket protocol - * elements. + * @details For the CURL websocket transport, the transport does NOT support native + * websockets - it is the responsibility of the client of the WebSocketTransport to format + * WebSocket protocol elements. */ virtual bool HasBuiltInWebSocketSupport() override { return false; } @@ -65,7 +74,8 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { /** * @brief Gracefully closes the WebSocket, notifying the remote node of the close reason. * - * @details Not implemented for CURL websockets because CURL does not support native websockets. + * @details Not implemented for CURL websockets because CURL does not support native + * websockets. * * The first param is the close reason, the second is descriptive text. */ @@ -78,7 +88,8 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { /** * @brief Retrieve the status of the close socket operation. * - * @details Not implemented for CURL websockets because CURL does not support native websockets. + * @details Not implemented for CURL websockets because CURL does not support native + * websockets. * */ NativeWebSocketCloseInformation NativeGetCloseSocketInformation( @@ -90,7 +101,8 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { /** * @brief Send a frame of data to the remote node. * - * @details Not implemented for CURL websockets because CURL does not support native websockets. + * @details Not implemented for CURL websockets because CURL does not support native + * websockets. * */ virtual void NativeSendFrame( @@ -104,7 +116,8 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { /** * @brief Receive a frame of data from the remote node. * - * @details Not implemented for CURL websockets because CURL does not support native websockets. + * @details Not implemented for CURL websockets because CURL does not support native + * websockets. * */ virtual NativeWebSocketReceiveInformation NativeReceiveFrame( @@ -116,8 +129,8 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { // Non-Native WebSocket support. /** * @brief This function is used when working with streams to pull more data from the wire. - * Function will try to keep pulling data from socket until the buffer is all written or until - * there is no more data to get from the socket. + * Function will try to keep pulling data from socket until the buffer is all written or + * until there is no more data to get from the socket. * * @param buffer Buffer to fill with data. * @param bufferSize Size of buffer. @@ -151,5 +164,4 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { void OnUpgradedConnection( std::unique_ptr&& upgradedConnection) override; }; - }}}} // namespace Azure::Core::Http::WebSockets diff --git a/sdk/core/azure-core/inc/azure/core/http/websockets/win_http_websockets_transport.hpp b/sdk/core/azure-core/inc/azure/core/http/websockets/win_http_websockets_transport.hpp index 4d7fb045f3..c087536cfc 100644 --- a/sdk/core/azure-core/inc/azure/core/http/websockets/win_http_websockets_transport.hpp +++ b/sdk/core/azure-core/inc/azure/core/http/websockets/win_http_websockets_transport.hpp @@ -16,125 +16,135 @@ #include #include -namespace Azure { namespace Core { namespace Http { namespace WebSockets { +namespace Azure { namespace Core { namespace Http { + namespace _detail { + class WinHttpRequest; + class WinHttpAction; + } // namespace _detail - /** - * @brief Concrete implementation of a WebSocket Transport that uses WinHTTP. - */ - class WinHttpWebSocketTransport : public WebSocketTransport, public WinHttpTransport { - - Azure::Core::_internal::UniqueHandle m_socketHandle; - std::mutex m_sendMutex; - std::mutex m_receiveMutex; - - // Called by the - void OnUpgradedConnection( - Azure::Core::_internal::UniqueHandle const& requestHandle) override; - - public: - /** - * @brief Construct a new WinHTTP WebSocket Transport. - * - * @param options Optional parameter to override the default options. - */ - WinHttpWebSocketTransport(WinHttpTransportOptions const& options = WinHttpTransportOptions()) - : WinHttpTransport(options) - { - } - - /** - * @brief Implements interface to send an HTTP Request and produce an HTTP RawResponse - * - * @param request an HTTP Request to be send. - * @param context A context to control the request lifetime. - * - * @return unique ptr to an HTTP RawResponse. - */ - virtual std::unique_ptr Send(Request& request, Context const& context) override; + namespace WebSockets { /** - * @brief Indicates if the transports natively websockets or not. - * - * @details For the WinHTTP websocket transport, the WinHTTP API supports websockets. + * @brief Concrete implementation of a WebSocket Transport that uses WinHTTP. */ - virtual bool HasBuiltInWebSocketSupport() override { return true; } - - /** - * @brief Close the underlying WebSocket handle. - * - */ - virtual void Close() override; - - // Native WebSocket support methods. - /** - * @brief Gracefully closes the WebSocket, notifying the remote node of the close reason. - * - * @details Not implemented for CURL websockets because CURL does not support native websockets. - * - * @param status Status value to be sent to the remote node. Application defined. - * @param disconnectReason UTF-8 encoded reason for the disconnection. Optional. - * @param context Context for the operation. - * - */ - virtual void NativeCloseSocket(uint16_t, std::string const&, Azure::Core::Context const&) - override; - - /** - * @brief Retrieve the information associated with a WebSocket close response. - * - * Should only be called when a Receive operation returns WebSocketFrameType::CloseFrameType - * - * @param context Context for the operation. - * - * @returns a tuple containing the status code and string. - */ - virtual NativeWebSocketCloseInformation NativeGetCloseSocketInformation( - Azure::Core::Context const& context) override; - - /** - * @brief Send a frame of data to the remote node. - * - * @details Not implemented for CURL websockets because CURL does not support native - * websockets. - * - * @brief frameType Frame type sent to the server, Text or Binary. - * @brief frameData Frame data to be sent to the server. - */ - virtual void NativeSendFrame( - NativeWebSocketFrameType, - std::vector const&, - Azure::Core::Context const&) override; - - virtual NativeWebSocketReceiveInformation NativeReceiveFrame( - Azure::Core::Context const&) override; - - // Non-Native WebSocket support. - /** - * @brief This function is used when working with streams to pull more data from the wire. - * Function will try to keep pulling data from socket until the buffer is all written or - * until there is no more data to get from the socket. - * - * @details Not implemented for WinHTTP websockets because WinHTTP implements websockets - * natively. - */ - virtual size_t ReadFromSocket(uint8_t*, size_t, Context const&) override - { - throw std::runtime_error("Not implemented."); - } - - /** - * @brief This method will use sockets to write all the bytes from buffer. - * - * @details Not implemented for WinHTTP websockets because WinHTTP implements websockets - * natively. - * - */ - virtual int SendBuffer(uint8_t const*, size_t, Context const&) override - { - throw std::runtime_error("Not implemented."); - } - - bool HasWebSocketSupport() const override { return true; } - }; - -}}}} // namespace Azure::Core::Http::WebSockets + class WinHttpWebSocketTransport : public WebSocketTransport, public WinHttpTransport { + + Azure::Core::_internal::UniqueHandle m_socketHandle; + std::unique_ptr m_httpAction; + std::mutex m_sendMutex; + uint32_t m_sendMutexOwner{}; + std::mutex m_receiveMutex; + uint32_t m_receiveMutexOwner{}; + + // Called by the HttpTransport to complete the upgrade of a WebSocket connection. + void OnUpgradedConnection(std::unique_ptr const& + requestHandle) override; + + public: + /** + * @brief Construct a new WinHTTP WebSocket Transport. + * + * @param options Optional parameter to override the default options. + */ + WinHttpWebSocketTransport(Azure::Core::Http::Policies::TransportOptions const& options = {}); + + ~WinHttpWebSocketTransport(); + + /** + * @brief Implements interface to send an HTTP Request and produce an HTTP RawResponse + * + * @param request an HTTP Request to be send. + * @param context A context to control the request lifetime. + * + * @return unique ptr to an HTTP RawResponse. + */ + virtual std::unique_ptr Send(Request& request, Context const& context) override; + + /** + * @brief Indicates if the transports natively websockets or not. + * + * @details For the WinHTTP websocket transport, the WinHTTP API supports websockets. + */ + virtual bool HasBuiltInWebSocketSupport() override { return true; } + + /** + * @brief Close the underlying WebSocket handle. + * + */ + virtual void Close() override; + + // Native WebSocket support methods. + /** + * @brief Gracefully closes the WebSocket, notifying the remote node of the close reason. + * + * @details Not implemented for CURL websockets because CURL does not support native + * websockets. + * + * @param status Status value to be sent to the remote node. Application defined. + * @param disconnectReason UTF-8 encoded reason for the disconnection. Optional. + * @param context Context for the operation. + * + */ + virtual void NativeCloseSocket(uint16_t, std::string const&, Azure::Core::Context const&) + override; + + /** + * @brief Retrieve the information associated with a WebSocket close response. + * + * Should only be called when a Receive operation returns WebSocketFrameType::CloseFrameType + * + * @param context Context for the operation. + * + * @returns a tuple containing the status code and string. + */ + virtual NativeWebSocketCloseInformation NativeGetCloseSocketInformation( + Azure::Core::Context const& context) override; + + /** + * @brief Send a frame of data to the remote node. + * + * @details Not implemented for CURL websockets because CURL does not support native + * websockets. + * + * @brief frameType Frame type sent to the server, Text or Binary. + * @brief frameData Frame data to be sent to the server. + */ + virtual void NativeSendFrame( + NativeWebSocketFrameType, + std::vector const&, + Azure::Core::Context const&) override; + + virtual NativeWebSocketReceiveInformation NativeReceiveFrame( + Azure::Core::Context const&) override; + + // Non-Native WebSocket support. + /** + * @brief This function is used when working with streams to pull more data from the wire. + * Function will try to keep pulling data from socket until the buffer is all written or + * until there is no more data to get from the socket. + * + * @details Not implemented for WinHTTP websockets because WinHTTP implements websockets + * natively. + */ + virtual size_t ReadFromSocket(uint8_t*, size_t, Context const&) override + { + throw std::runtime_error("Not implemented."); + } + + /** + * @brief This method will use sockets to write all the bytes from buffer. + * + * @details Not implemented for WinHTTP websockets because WinHTTP implements websockets + * natively. + * + */ + virtual int SendBuffer(uint8_t const*, size_t, Context const&) override + { + throw std::runtime_error("Not implemented."); + } + + bool HasWebSocketSupport() const override { return true; } + }; + + } // namespace WebSockets +}}} // namespace Azure::Core::Http 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 74c7c5bcc0..e6315cacf1 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 @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT +// cspell:words HCERTIFICATECHAIN PCCERT CCERT HCERTCHAINENGINE HCERTSTORE + /** * @file * @brief #Azure::Core::Http::HttpTransport implementation via WinHTTP. - * cspell:words HCERTIFICATECHAIN PCCERT CCERT HCERTCHAINENGINE HCERTSTORE */ -// cspell:words HCERTIFICATECHAIN PCCERT CCERT HCERTCHAINENGINE HCERTSTORE #pragma once @@ -15,8 +15,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) @@ -59,53 +58,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 /** @@ -175,72 +129,23 @@ 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&){}; - protected: + protected: // Protected to allow WebSocketTransport to access this for error reporting. /** * @brief Throw an exception based on the Win32 Error code * @@ -270,8 +175,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. @@ -283,7 +188,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/inc/azure/core/internal/unique_handle.hpp b/sdk/core/azure-core/inc/azure/core/internal/unique_handle.hpp index 788eaf0bf6..10a69b7154 100644 --- a/sdk/core/azure-core/inc/azure/core/internal/unique_handle.hpp +++ b/sdk/core/azure-core/inc/azure/core/internal/unique_handle.hpp @@ -55,7 +55,7 @@ namespace Azure { namespace Core { namespace _internal { * * template <> struct UniqueHandleHelper * { - * using type = BasicUniqueHandle; + * using type = BasicUniqueHandle; * }; */ // *** Given just T, map it to the corresponding FreeFunc diff --git a/sdk/core/azure-core/src/environment_log_level_listener.cpp b/sdk/core/azure-core/src/environment_log_level_listener.cpp index 98ef17dcf3..9925da71fa 100644 --- a/sdk/core/azure-core/src/environment_log_level_listener.cpp +++ b/sdk/core/azure-core/src/environment_log_level_listener.cpp @@ -8,6 +8,7 @@ #include "azure/core/internal/strings.hpp" #include +#include #include #include @@ -111,12 +112,13 @@ EnvironmentLogLevelListener::GetLogListener() static std::function const consoleLogger = [](auto level, auto message) { - std::cerr << '[' - << Azure::DateTime(std::chrono::system_clock::now()) - .ToString( - DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits) - << " T: " << std::this_thread::get_id() << "] " << LogLevelToConsoleString(level) - << " : " << message << std::endl; + std::stringstream ss; + ss << '[' + << Azure::DateTime(std::chrono::system_clock::now()) + .ToString(DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits) + << " T: " << std::this_thread::get_id() << "] " << LogLevelToConsoleString(level) + << " : " << message << std::endl; + std::cerr << ss.str(); }; return consoleLogger; 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/core/azure-core/src/http/curl/curl.cpp b/sdk/core/azure-core/src/http/curl/curl.cpp index 3263b8cc5e..e7d1ccd199 100644 --- a/sdk/core/azure-core/src/http/curl/curl.cpp +++ b/sdk/core/azure-core/src/http/curl/curl.cpp @@ -37,22 +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 @@ -132,7 +149,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( @@ -1381,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 { @@ -1443,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")); @@ -1690,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/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/websockets/websockets_impl.cpp b/sdk/core/azure-core/src/http/websockets/websockets_impl.cpp index af84d45f98..7078c2ef8e 100644 --- a/sdk/core/azure-core/src/http/websockets/websockets_impl.cpp +++ b/sdk/core/azure-core/src/http/websockets/websockets_impl.cpp @@ -59,21 +59,29 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { names } m_state = SocketState::Opening; + // We create the pipeline using a copy of the specified client options which resets + // the TransportOptions, because we need to provide a custom transport to the pipeline, but + // the pipeline constructor is upset if the TransportOptions specify any special options. + // + // We handle all the special options in the constructor for the WebSocketTransport so they + // aren't needed by the pipeline constructor. + Azure::Core::_internal::ClientOptions clientOptions{m_options}; + clientOptions.Transport = Azure::Core::Http::Policies::TransportOptions{}; + #if defined(BUILD_TRANSPORT_WINHTTP_ADAPTER) - WinHttpTransportOptions transportOptions; auto winHttpTransport = std::make_shared( - transportOptions); + m_options.Transport); m_transport = std::static_pointer_cast(winHttpTransport); - m_options.Transport.Transport = std::static_pointer_cast(winHttpTransport); + clientOptions.Transport.Transport = std::static_pointer_cast(winHttpTransport); #elif defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER) - CurlWebSocketTransportOptions transportOptions; - transportOptions.HttpKeepAlive = false; - auto curlWebSockets - = std::make_shared(transportOptions); + // CurlWebSocketTransportOptions transportOptions; + // transportOptions.HttpKeepAlive = false; + auto curlWebSockets = std::make_shared( + m_options.Transport); m_transport = std::static_pointer_cast(curlWebSockets); - m_options.Transport.Transport = std::static_pointer_cast(curlWebSockets); + clientOptions.Transport.Transport = std::static_pointer_cast(curlWebSockets); #endif std::vector> perCallPolicies{}; @@ -87,7 +95,7 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { names m_options.ServiceName, m_options.ServiceVersion, m_options.Telemetry)); } Azure::Core::Http::_internal::HttpPipeline openPipeline( - m_options, std::move(perRetryPolicies), std::move(perCallPolicies)); + clientOptions, std::move(perRetryPolicies), std::move(perCallPolicies)); Azure::Core::Http::Request openSocketRequest( Azure::Core::Http::HttpMethod::Get, m_remoteUrl, false); @@ -107,7 +115,6 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { names } if (!m_options.Protocols.empty()) { - std::string protocols; for (auto const& protocol : m_options.Protocols) { @@ -134,7 +141,7 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { names // fail immediately. if (response->GetStatusCode() != Azure::Core::Http::HttpStatusCode::SwitchingProtocols) { - throw Azure::Core::Http::TransportException("Unexpected handshake response"); + throw Azure::Core::RequestFailedException(response); } // Prove that the server received this socket request. 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..c26db871af --- /dev/null +++ b/sdk/core/azure-core/src/http/winhttp/win_http_request.hpp @@ -0,0 +1,406 @@ +// 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 +#pragma warning(push) +#pragma warning(disable : 6553) +#include +#pragma warning(pop) +#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 { + + // An HttpOperation reflects an outstanding WinHTTP action. The WinHttpAction object allows for + // several classes of HttpOperation to be in progress at the same time. Those roughly are: + // + // 1) Receive Operations + // 2) Send Operations + // 3) Close Operations (used only for WebSocket handles). + // 4) Handle Closing operations + // There can be only one operation outstanding at a time for each category of operation. + class HttpOperation { + wil::unique_event m_operationCompleteEvent; + // Mutex protecting all mutable members of the class. + std::mutex m_operationStateMutex; + bool m_operationStarted{}; + DWORD m_stowedError{}; + DWORD_PTR m_stowedErrorInformation{}; + DWORD m_bytesAvailable{}; + WINHTTP_WEB_SOCKET_STATUS m_webSocketStatus{}; + DWORD m_operationMutexOwner{}; + + public: + HttpOperation() : m_operationCompleteEvent(CreateEvent(nullptr, TRUE, FALSE, nullptr)) + { + if (!m_operationCompleteEvent) + { + throw std::runtime_error("Error creating Action Complete Event."); + } + } + + /** + * @brief Start an HttpOperation. + * + * StartOperation is called before starting an HttpOperation. It resets the internal state of + * the HTTP Operation to a known state, and ensures that WaitForSingleObject will block (by + * resetting the operation complete event to the not-signalled state). + */ + void StartOperation() + { + // Reset the internal operation state. + std::unique_lock lock(m_operationStateMutex); + assert(!m_operationStarted); + m_stowedError = ERROR_SUCCESS; + m_stowedErrorInformation = static_cast(-1); + m_bytesAvailable = 0; + m_webSocketStatus.dwBytesTransferred = 0; + m_webSocketStatus.eBufferType = WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE; + m_operationStarted = true; + + // Reset the manual operation complete event so we will block until it's set to the + // signalled state. + m_operationCompleteEvent.ResetEvent(); + } + + /** + * @brief Mark an HttpOperation as complete. + */ + void CompleteOperation() + { + std::unique_lock lock(m_operationStateMutex); + // Note that we cannot assert that m_operationStarted is true here. + // That's because WinHTTP calls the status callback with an AsyncAction of 0 + // to reflect that all outstanding calls need to fail with an error. + if (m_operationStarted) + { + m_operationStarted = false; + m_operationCompleteEvent.SetEvent(); + } + } + DWORD WaitForSingleObject(DWORD waitTimeout) + { + return ::WaitForSingleObject(m_operationCompleteEvent.get(), waitTimeout); + } + void UpdateStowedError(DWORD_PTR stowedErrorInformation, DWORD stowedError) + { + std::unique_lock lock(m_operationStateMutex); + m_stowedError = stowedError; + m_stowedErrorInformation = stowedErrorInformation; + } + void UpdateBytesAvailable(DWORD bytesAvailable) + { + std::unique_lock lock(m_operationStateMutex); + m_bytesAvailable = bytesAvailable; + } + void UpdateWebSocketStatus(WINHTTP_WEB_SOCKET_STATUS* webSocketStatus) + { + std::unique_lock lock(m_operationStateMutex); + m_webSocketStatus = *webSocketStatus; + } + + DWORD GetStowedError() + { + std::unique_lock lock(m_operationStateMutex); + return m_stowedError; + } + DWORD_PTR GetStowedErrorInformation() + { + std::unique_lock lock(m_operationStateMutex); + return m_stowedErrorInformation; + } + DWORD GetBytesAvailable() + { + std::unique_lock lock(m_operationStateMutex); + return m_bytesAvailable; + } + WINHTTP_WEB_SOCKET_STATUS const* GetWebSocketStatus() + { + std::unique_lock lock(m_operationStateMutex); + return &m_webSocketStatus; + } + }; + + // Containing HTTP request, used during the status operation callback. + WinHttpRequest* const m_httpRequest{}; + // True if this action is for a websocket transport. + const bool m_isWebSocketAction{false}; + + HttpOperation m_sendOperation; + HttpOperation m_receiveOperation; + HttpOperation m_closeOperation; + HttpOperation m_handleClosingOperation; + + /* + * 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); + + HttpOperation& OperationFromActionStatus(DWORD callbackStatus); + HttpOperation& OperationFromAsyncResult(DWORD_PTR asyncResult); + + public: + /** + * @brief Create a new WinHttpAction object associated with a specific WinHttpRequest. + * + * @param request Http Request associated with the action. + * + * @remarks If the WinHttpRequest object is null, this is a hint that the WinHttpAction is + * associated with a WebSocket request, since WebSocket operations don't have an associated + * WinHttpRequest object. + */ + WinHttpAction(WinHttpRequest* request) + // Create a non-inheritable anonymous manual reset event intialized as unset. + : m_httpRequest(request), m_isWebSocketAction(request == nullptr) + { + } + + /** + * 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); + /** + * Unregisters the WinHTTP Status callback used by the action. + * + * @param internetHandle HINTERNET to register the callback. + * @returns The status of the operation. + */ + bool UnregisterWinHttpStatusCallback( + 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 a close action has completed successfully. + * + * @remarks Completes a wait operation initiated by WaitForAction, for a close operation. + * + * @note This function is only used for WebSocket transports. + * + */ + void CompleteCloseAction(DWORD actionToComplete); + /** + * @brief Notify a caller that the underlying HTTP request handle has been closed. + * + * @remarks Completes a wait operation initiated by WaitForAction, for a close operation. + */ + void CompleteHandleCloseAction(DWORD actionToComplete); + + /** + * @brief Notify a caller that the action has completed successfully. + * + * @remarks Completes a wait operation initiated by WaitForAction, for send operations. + */ + void CompleteSendAction(DWORD actionToComplete); + + /** + * @brief Notify a caller that the action has completed successfully. + * + * @remarks Completes a wait operation initiated by WaitForAction, for receive operations. + */ + void CompleteReceiveAction(DWORD actionToComplete); + + /** + * @brief Notify a caller that the action has completed successfully and reflect the bytes + * available + */ + void CompleteReceiveActionWithData(DWORD actionToComplete, DWORD bytesAvailable); + + /** + * @brief Notify a caller that the WebSocket action has completed successfully. + */ + void CompleteSendActionWithWebSocketStatus( + DWORD actionToComplete, + LPVOID statusInformation, + DWORD statusInformationLength); + /** + * @brief Notify a caller that the WebSocket action has completed successfully. + */ + void CompleteReceiveActionWithWebSocketStatus( + DWORD actionToComplete, + LPVOID statusInformation, + DWORD statusInformationLength); + + /** + * @brief Notify a caller that the action has completed with an error and save the error code + * and information. + * + * @param actionToComplete - event received. + * @param stowedErrorInformation - stowed error information from WinHTTP. + * @param stowedError - Win32 error code. + */ + void CompleteActionWithError(DWORD_PTR stowedErrorInformation, DWORD stowedError); + DWORD GetStowedError(DWORD actionToComplete); + DWORD_PTR GetStowedErrorInformation(DWORD actionToComplete); + DWORD GetBytesAvailable(DWORD actionToComplete); + WINHTTP_WEB_SOCKET_STATUS const* const GetWebSocketStatus(DWORD actionToComplete); + }; + + /** + * @brief A WinHttpRequest object encapsulates an HTTP operation. + */ + class WinHttpRequest final { + Azure::Core::_internal::UniqueHandle m_requestHandle; + std::unique_ptr m_httpAction; + std::vector m_expectedTlsRootCertificates; + // Thread used to asynchronously close a request handle if the expected root certificate does + // not match. + std::mutex m_handleClosedLock; + std::thread m_handleCloseThread; + bool m_requestHandleClosed{false}; + + /* + * 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); + HINTERNET const GetRequestHandle() { return m_requestHandle.get(); } + }; + + 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..6aea60d172 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 @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT -// cspell:words HCERTIFICATECHAIN PCCERT CCERT HCERTCHAINENGINE HCERTSTORE + +// cspell:words HCERTIFICATECHAIN PCCERT CCERT HCERTCHAINENGINE HCERTSTORE hlocal #include "azure/core/http/http.hpp" @@ -12,7 +13,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 +215,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 +239,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 +330,574 @@ 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); + + // Use a wil unique_hlocal_ansistring to manage the lifetime of errorMsg. Transfer the errorMsg to + // the unique + // pointer. + wil::unique_hlocal_ansistring errorString; + 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(errorString.addressof()), + 0, + nullptr) + != 0) { - WinHttpTransport* httpTransport = reinterpret_cast(dwContext); - httpTransport->OnHttpStatusOperation(hInternet, dwInternetStatus); + + size_t errorLength{strlen(errorString.get())}; + if (errorString.get()[errorLength - 1] == '\n' && errorString.get()[errorLength - 2] == '\r') + { + errorString.get()[errorLength - 2] = '\0'; + } + + errorMessage += ": "; + errorMessage += errorString.get(); } - catch (Azure::Core::RequestFailedException& rfe) + errorMessage += '.'; + return errorMessage; +} +} // namespace + +namespace Azure { namespace Core { namespace Http { namespace _detail { + + bool WinHttpAction::RegisterWinHttpStatusCallback( + Azure::Core::_internal::UniqueHandle const& internetHandle) { - // If an exception is thrown in the handler, log the error and terminate the connection. + // Reset the context handle for the newly registered status callback to the current + // WinHttpAction object. Log::Write( - Logger::Level::Error, - "Request Failed Exception Thrown: " + std::string(rfe.what()) + rfe.Message); - WinHttpCloseHandle(hInternet); + Logger::Level::Verbose, + "Register WinHttpStatusCallback on handle: " + + std::to_string(reinterpret_cast(internetHandle.get()))); + + return ( + WinHttpSetStatusCallback( + internetHandle.get(), + &WinHttpAction::StatusCallback, + WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, + 0) + != WINHTTP_INVALID_STATUS_CALLBACK); } - catch (std::exception& ex) + + bool WinHttpAction::UnregisterWinHttpStatusCallback( + Azure::Core::_internal::UniqueHandle const& internetHandle) { - // 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())); + // Reset the context handle for the newly registered status callback to the current + // WinHttpAction object. + Log::Write( + Logger::Level::Verbose, + "Unregister WinHttpStatusCallback on handle: " + + std::to_string(reinterpret_cast(internetHandle.get()))); + + return ( + WinHttpSetStatusCallback( + internetHandle.get(), nullptr, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0) + != WINHTTP_INVALID_STATUS_CALLBACK); } -} -/** - * @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) + // Returns the Operation associated with the specified action status. + // + // There are 3 events associated with each action: + // - The action's event, which is signaled when the action completes. + // - THe action's receive event which is signalled when data is received by the event. + // - The action's send event which is signalled when data sent by the action is completed. + WinHttpAction::HttpOperation& WinHttpAction::OperationFromActionStatus(DWORD callbackStatus) { - if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) + if (callbackStatus & (WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE)) { - Log::Write(Logger::Level::Error, "Security failure. :("); + return m_closeOperation; + } + else if ( + callbackStatus + & (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE)) + { + return m_sendOperation; + } + else if ( + callbackStatus + & (WINHTTP_CALLBACK_STATUS_READ_COMPLETE | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE)) + { + return m_receiveOperation; + } + else if (callbackStatus & WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) + { + return m_handleClosingOperation; + } + else + { + AZURE_ASSERT_MSG(false, "Unknown action status"); + } + AZURE_UNREACHABLE_CODE(); + } + + WinHttpAction::HttpOperation& WinHttpAction::OperationFromAsyncResult(DWORD_PTR asyncResult) + { + Log::Write( + Logger::Level::Informational, "OperationFromAsyncResult: " + std::to_string(asyncResult)); + switch (asyncResult) + { + case API_RECEIVE_RESPONSE: { + return m_receiveOperation; + } + case API_QUERY_DATA_AVAILABLE: { + return m_receiveOperation; + } + case API_READ_DATA: { + return m_receiveOperation; + } + case API_SEND_REQUEST: { + return m_sendOperation; + } + case API_WRITE_DATA: { + return m_sendOperation; + } + default: + AZURE_ASSERT_MSG(false, "OperationFromAsyncResult - unknown error information: "); + break; + } + AZURE_UNREACHABLE_CODE(); + } + + /** + * Wait for an action to complete. + */ + bool WinHttpAction::WaitForAction( + std::function initiateAction, + DWORD expectedCallbackStatus, + Azure::Core::Context const& context, + Azure::DateTime::duration const& pollInterval) + { + // Before doing any work, check to make sure that the context hasn't already been cancelled. + context.ThrowIfCancelled(); + + auto& operationToWait{OperationFromActionStatus(expectedCallbackStatus)}; + + Log::Write(Logger::Level::Verbose, "Start " + InternetStatusToString(expectedCallbackStatus)); + operationToWait.StartOperation(); + + // Call the provided callback to start the WinHTTP action. + initiateAction(); + + DWORD waitResult; + do + { + waitResult = operationToWait.WaitForSingleObject(static_cast( + std::chrono::duration_cast(pollInterval).count())); + if (waitResult == WAIT_TIMEOUT) + { + Log::Write(Logger::Level::Verbose, "Timeout, check for cancellation."); + // If the request was cancelled while we were waiting, throw an exception. + context.ThrowIfCancelled(); + } + else if (waitResult == WAIT_OBJECT_0) + { + } + else + { + return false; + } + } while (waitResult != WAIT_OBJECT_0); + if (operationToWait.GetStowedError() != NO_ERROR) + { + return false; } - // Silently ignore if there's any statuses we get that we can't handle - return; + return true; } - // We will only set the Status callback if a root certificate has been set. - AZURE_ASSERT(!m_options.ExpectedTlsRootCertificates.empty()); + void WinHttpAction::CompleteCloseAction(DWORD actionToComplete) + { + Log::Write(Logger::Level::Verbose, "CompleteCloseAction. "); + auto& operationToWait = OperationFromActionStatus(actionToComplete); + operationToWait.CompleteOperation(); + } + + void WinHttpAction::CompleteHandleCloseAction(DWORD actionToComplete) + { + Log::Write(Logger::Level::Verbose, "CompleteHandleClose: "); + auto& operationToWait = OperationFromActionStatus(actionToComplete); + operationToWait.CompleteOperation(); + } + + void WinHttpAction::CompleteSendAction(DWORD actionToComplete) + { + Log::Write(Logger::Level::Verbose, "CompleteSendAction. "); + auto& operationToWait = OperationFromActionStatus(actionToComplete); + operationToWait.CompleteOperation(); + } + void WinHttpAction::CompleteReceiveAction(DWORD actionToComplete) + { + Log::Write(Logger::Level::Verbose, "CompleteReceiveAction. "); + + auto& operationToWait = OperationFromActionStatus(actionToComplete); + operationToWait.CompleteOperation(); + } + + void WinHttpAction::CompleteReceiveActionWithData(DWORD actionToComplete, DWORD bytesAvailable) + { + Log::Write(Logger::Level::Verbose, "CompleteReceiveActionWithData: "); + // 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& operationToWait = OperationFromActionStatus(actionToComplete); + operationToWait.UpdateBytesAvailable(bytesAvailable); + operationToWait.CompleteOperation(); + } - // Ask WinHTTP for the server certificate - this won't be valid outside a status callback. - wil::unique_cert_context serverCertificate; + void WinHttpAction::CompleteActionWithError(DWORD_PTR stowedErrorInformation, DWORD stowedError) { - DWORD bufferLength = sizeof(PCCERT_CONTEXT); - if (!WinHttpQueryOption( - hInternet, - WINHTTP_OPTION_SERVER_CERT_CONTEXT, - reinterpret_cast(serverCertificate.addressof()), - &bufferLength)) + Log::Write( + Logger::Level::Error, + "CompleteActionWithError State: " + std::to_string(stowedErrorInformation) + + " Code: " + std::to_string(stowedError)); + // If the stowedErrorInformation is 0, it meaans that all operations are going to fail. + if (stowedErrorInformation == 0) + { + m_sendOperation.UpdateStowedError(stowedErrorInformation, stowedError); + m_sendOperation.CompleteOperation(); + m_receiveOperation.UpdateStowedError(stowedErrorInformation, stowedError); + m_receiveOperation.CompleteOperation(); + } + else { - GetErrorAndThrow("Could not retrieve TLS server certificate."); + auto& operationToWait = OperationFromAsyncResult(stowedErrorInformation); + operationToWait.UpdateStowedError(stowedErrorInformation, stowedError); + operationToWait.CompleteOperation(); } } - if (!VerifyCertificatesInChain(m_options.ExpectedTlsRootCertificates, serverCertificate.get())) + void WinHttpAction::CompleteReceiveActionWithWebSocketStatus( + DWORD actionToComplete, + LPVOID statusInformation, + DWORD statusInformationLength) { - Log::Write(Logger::Level::Error, "Server certificate is not trusted. Aborting HTTP request"); - // 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 (statusInformationLength != sizeof(WINHTTP_WEB_SOCKET_STATUS)) + { + Log::Write(Logger::Level::Verbose, "Unexpected length received from WebSocket Status"); + return; + } + auto& operationToWait = OperationFromActionStatus(actionToComplete); + WINHTTP_WEB_SOCKET_STATUS* webSocketStatus + = static_cast(statusInformation); + operationToWait.UpdateWebSocketStatus(webSocketStatus); + operationToWait.CompleteOperation(); + } + void WinHttpAction::CompleteSendActionWithWebSocketStatus( + DWORD actionToComplete, + LPVOID statusInformation, + DWORD statusInformationLength) + { + if (statusInformationLength != sizeof(WINHTTP_WEB_SOCKET_STATUS)) + { + Log::Write(Logger::Level::Verbose, "Unexpected length received from WebSocket Status"); + return; + } + auto& operationToWait = OperationFromActionStatus(actionToComplete); + WINHTTP_WEB_SOCKET_STATUS* webSocketStatus + = static_cast(statusInformation); + operationToWait.UpdateWebSocketStatus(webSocketStatus); + operationToWait.CompleteOperation(); + } - // To avoid a double free of this handle record that we've - // already closed the handle. - m_requestHandleClosed = true; + DWORD WinHttpAction::GetStowedError(DWORD actionToComplete) + { + auto& operation{OperationFromActionStatus(actionToComplete)}; + return operation.GetStowedError(); + } + DWORD_PTR WinHttpAction::GetStowedErrorInformation(DWORD actionToComplete) + { + auto& operation{OperationFromActionStatus(actionToComplete)}; + return operation.GetStowedErrorInformation(); } -} -void WinHttpTransport::GetErrorAndThrow(const std::string& exceptionMessage, DWORD error) -{ - std::string errorMessage = exceptionMessage + " Error Code: " + std::to_string(error); + DWORD WinHttpAction::GetBytesAvailable(DWORD actionToComplete) + { + auto& operation{OperationFromActionStatus(actionToComplete)}; + return operation.GetBytesAvailable(); + } - 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) + WINHTTP_WEB_SOCKET_STATUS const* const WinHttpAction::GetWebSocketStatus(DWORD actionToComplete) { - // Use a unique_ptr to manage the lifetime of errorMsg. - std::unique_ptr errorString(errorMsg, &LocalFree); - errorMsg = nullptr; + auto& operation{OperationFromActionStatus(actionToComplete)}; + return operation.GetWebSocketStatus(); + } - errorMessage += ": "; - errorMessage += errorString.get(); + /** + * 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::Verbose, + "Status Callback received with no context. Handle: " + + std::to_string(reinterpret_cast(hInternet)) + + ", Status: " + std::to_string(internetStatus) + "(" + + InternetStatusToString(internetStatus) + ")"); + return; + } + + 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())); + } } - errorMessage += '.'; + + /** + * @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) + { + Log::Write( + Logger::Level::Informational, + "Status operation: " + std::to_string(internetStatus) + "(" + + InternetStatusToString(internetStatus) + ")"); + if (internetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) + { + 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)); + // We want to complete writes, reads, and headers available calls on error events. + 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 + { + switch (internetStatus) + { + case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: + // A WinHttpSendRequest API call has completed, complete the current action. + CompleteSendAction(internetStatus); + break; + case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: + // A WinHttpWriteData call has completed, complete the current action. + if (m_isWebSocketAction) + { + CompleteSendActionWithWebSocketStatus( + internetStatus, statusInformation, statusInformationLength); + } + else + { + CompleteSendAction(internetStatus); + } + break; + case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: + // Headers for an HTTP response are available, complete the current action. + CompleteReceiveAction(internetStatus); + break; + case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: + // A WinHttpReadData call has completed. Complete the current action, including + // the amount of data read. + if (m_isWebSocketAction) + { + CompleteReceiveActionWithWebSocketStatus( + internetStatus, statusInformation, statusInformationLength); + } + else + { + CompleteReceiveActionWithData(internetStatus, 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."); + CompleteHandleCloseAction(internetStatus); + break; + case WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE: + // Complete closing the handle. + Log::Write( + Logger::Level::Verbose, + "Handle Close Complete; completing outstanding Close request"); + CompleteCloseAction(internetStatus); + break; + default: + Log::Write( + Logger::Level::Error, "Ignoring status " + InternetStatusToString(internetStatus)); + break; + } + } + } + + void WinHttpRequest::HandleExpectedTlsRootCertificates(HINTERNET hInternet) + { + 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."); + } + } + + if (!VerifyCertificatesInChain(m_expectedTlsRootCertificates, serverCertificate.get())) + { + Log::Write( + Logger::Level::Error, "Server certificate is not trusted. Aborting HTTP request"); + + // We need to block the primary thread until we receive the + // WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING event (otherwise we could receive notifications + // after we've destroyed the WinHttpRequest object, which would be ... bad. Unfortunately + // we're about to close the handle (to trigger the cancellation of any outstanding send + // requests). And we cannot wait for the handle to close on the current thread because we're + // inside a WinHTTP callback. + // + // To resolve this issue, we post the close handle to another thread and then on the main + // thread, in the destructor of the WinHttpRequest object, we wait for the newly created + // thread to exit. + // + // Note that we MUST call CompleteActionWithError in this function, because when we return + // WinHTTP will continue processing the request. + // + std::unique_lock closeLock(m_handleClosedLock); + m_requestHandleClosed = true; + + // Complete any outstanding actions with secure failure errors. Note that "0" is + // a sentinel which means "Complete all outstanding actions". + m_httpAction->CompleteActionWithError(0, ERROR_WINHTTP_SECURE_FAILURE); + + // Start a thread to synchronously close the handle and wait for the handle to close. + // If m_requestHandleClosed is set, we'll block waiting on this thread in the destructor + // of the WinHttpRequest. + m_handleCloseThread = std::thread([this, hInternet] { + // Complete any outstanding actions with secure failure errors. Note that "0" is + // a sentinel which means "Complete all outstanding actions". + m_httpAction->CompleteActionWithError(0, ERROR_WINHTTP_SECURE_FAILURE); + + m_httpAction->WaitForAction( + [hInternet]() { WinHttpCloseHandle(hInternet); }, + WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, + Azure::Core::Context{}); + }); + + // 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 + { + std::string errorMessage = exceptionMessage + GetErrorMessage(error); + + throw Azure::Core::Http::TransportException(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 +914,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 +951,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; } @@ -539,13 +980,13 @@ WinHttpTransportOptions WinHttpTransportOptionsFromTransportOptions( } if (transportOptions.EnableCertificateRevocationListCheck) { - httpOptions.EnableCertificateRevocationListCheck; + httpOptions.EnableCertificateRevocationListCheck = true; } // If you specify an expected TLS root certificate, you also need to enable ignoring unknown // CAs. if (!transportOptions.ExpectedTlsRootCertificate.empty()) { - httpOptions.IgnoreUnknownCertificateAuthority; + httpOptions.IgnoreUnknownCertificateAuthority = true; } return httpOptions; @@ -563,6 +1004,8 @@ WinHttpTransport::WinHttpTransport( { } +WinHttpTransport::~WinHttpTransport() = default; + Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateConnectionHandle( Azure::Core::Url const& url, Azure::Core::Context const& context) @@ -570,6 +1013,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 +1039,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 +1067,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 +1076,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 @@ -635,76 +1093,123 @@ Azure::Core::_internal::UniqueHandle WinHttpTransport::CreateRequestH // If the service requests TLS client certificates, we want to let the WinHTTP APIs know that // it's ok to initiate the request without a client certificate. // - // Note: If/When TLS client certificate support is added to the pipeline, this line may need to - // be revisited. + // 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() +{ + std::unique_lock closeLock(m_handleClosedLock); + if (m_requestHandleClosed) + { + Log::Write(Logger::Level::Verbose, "WinHttpRequest::~WinHttpRequest. Handle forced closed."); + if (m_handleCloseThread.joinable()) + { + Log::Write( + Logger::Level::Verbose, + "WinHttpRequest::~WinHttpRequest. Waiting for close handle to exit."); + m_handleCloseThread.join(); + } + Log::Write( + Logger::Level::Verbose, "WinHttpRequest::~WinHttpRequest. Handle close thread completed."); + } + else + { + Log::Write( + Logger::Level::Verbose, "WinHttpRequest::~WinHttpRequest. Closing handle synchronously."); + // Close the outstanding request handle. This is always a synchronous operation, but callers + // should block until WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING is received. + m_httpAction->WaitForAction( + [&]() { 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 +1234,28 @@ void WinHttpTransport::Upload( DWORD dwBytesWritten = 0; - context.ThrowIfCancelled(); - - // Write data to the server. - if (!WinHttpWriteData( - requestHandle.get(), - unique_buffer.get(), - static_cast(rawRequestLen), - &dwBytesWritten)) + 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)) { - GetErrorAndThrow("Error while uploading/sending data."); + GetErrorAndThrow( + "Error sending HTTP request asynchronously", + m_httpAction->GetStowedError(WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE)); } } } -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 +1275,113 @@ 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(WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE)); + } - // 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(WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE)); } } -int64_t WinHttpTransport::GetContentLength( - Azure::Core::_internal::UniqueHandle const& requestHandle, +int64_t _detail::WinHttpRequest::GetContentLength( HttpMethod requestMethod, HttpStatusCode responseStatusCode) { @@ -852,7 +1398,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 +1416,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 +1448,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 +1468,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 +1491,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 +1512,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 +1537,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 +1567,55 @@ 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(WINHTTP_CALLBACK_STATUS_READ_COMPLETE)); } - 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(WINHTTP_CALLBACK_STATUS_READ_COMPLETE); } - 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 +1626,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/src/http/winhttp/win_http_websockets.cpp b/sdk/core/azure-core/src/http/winhttp/win_http_websockets.cpp index ca1d42164e..188ed89979 100644 --- a/sdk/core/azure-core/src/http/winhttp/win_http_websockets.cpp +++ b/sdk/core/azure-core/src/http/winhttp/win_http_websockets.cpp @@ -8,6 +8,7 @@ #include "azure/core/internal/diagnostics/log.hpp" #include "azure/core/internal/unique_handle.hpp" #include "azure/core/platform.hpp" +#include "win_http_request.hpp" #if defined(AZ_PLATFORM_POSIX) #include // for poll() @@ -24,18 +25,35 @@ #endif #include +using namespace Azure::Core::Diagnostics::_internal; +using namespace Azure::Core::Diagnostics; + namespace Azure { namespace Core { namespace Http { namespace WebSockets { + WinHttpWebSocketTransport::WinHttpWebSocketTransport( + Azure::Core::Http::Policies::TransportOptions const& options) + : WinHttpTransport(options), m_httpAction(std::make_unique<_detail::WinHttpAction>(nullptr)) + { + } + + WinHttpWebSocketTransport::~WinHttpWebSocketTransport() { Close(); } + void WinHttpWebSocketTransport::OnUpgradedConnection( - Azure::Core::_internal::UniqueHandle const& requestHandle) + std::unique_ptr const& requestHandle) { // Convert the request handle into a WebSocket handle for us to use later. - m_socketHandle = Azure::Core::_internal::UniqueHandle( - WinHttpWebSocketCompleteUpgrade(requestHandle.get(), 0)); + m_socketHandle + = Azure::Core::_internal::UniqueHandle(WinHttpWebSocketCompleteUpgrade( + requestHandle->GetRequestHandle(), reinterpret_cast(m_httpAction.get()))); if (!m_socketHandle) { GetErrorAndThrow("Error Upgrading HttpRequest handle to WebSocket handle."); } + // Register the WebSocket action with WinHTTP. + if (!m_httpAction->RegisterWinHttpStatusCallback(m_socketHandle)) + { + GetErrorAndThrow("Error registering for notifications on the websocket handle."); + } } std::unique_ptr WinHttpWebSocketTransport::Send( @@ -48,7 +66,23 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { /** * @brief Close the WebSocket cleanly. */ - void WinHttpWebSocketTransport::Close() { m_socketHandle.reset(); } + void WinHttpWebSocketTransport::Close() + { + if (m_socketHandle) + { + Log::Write( + Logger::Level::Verbose, + "WinHttpWebSocketTransport::Close. Closing handle synchronously."); + // m_httpAction->UnregisterWinHttpStatusCallback(m_socketHandle); + // Close the outstanding request handle. While WinHttpCloseHandle is synchronous, + // the WinHttpCloseHandle documentation strongly recommends waiting until the handle closed + // callback is received before allowing the CLose to proceed. + m_httpAction->WaitForAction( + [&]() { m_socketHandle.reset(); }, + WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, + Azure::Core::Context{}); + } + } // Native WebSocket support methods. /** @@ -66,22 +100,35 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { std::string const& disconnectReason, Azure::Core::Context const& context) { - context.ThrowIfCancelled(); - - auto err = WinHttpWebSocketClose( - m_socketHandle.get(), - status, - disconnectReason.empty() - ? nullptr - : reinterpret_cast(const_cast(disconnectReason.c_str())), - static_cast(disconnectReason.size())); - if (err != 0) + if (!m_httpAction->WaitForAction( + [&]() { + auto err = WinHttpWebSocketClose( + m_socketHandle.get(), + status, + disconnectReason.empty() + ? nullptr + : reinterpret_cast(const_cast(disconnectReason.c_str())), + static_cast(disconnectReason.size())); + if (err != 0) + { + GetErrorAndThrow("WinHttpWebSocketClose() failed", err); + } + }, + WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, + context)) { - GetErrorAndThrow("WinHttpWebSocketClose() failed", err); + // Close calls can trigger operation cancelled errors, so ignore them since they're expected + // from close calls. + if ((m_httpAction->GetStowedError(WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE) != 0) + && (m_httpAction->GetStowedError(WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE) + != ERROR_WINHTTP_OPERATION_CANCELLED)) + { + GetErrorAndThrow( + "Error Closing WebSocket handle synchronously", + m_httpAction->GetStowedError(WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE)); + } } - context.ThrowIfCancelled(); - // Make sure that the server responds gracefully to the close request. auto closeInformation = NativeGetCloseSocketInformation(context); @@ -118,7 +165,7 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { &closeReasonLength); if (err != 0) { - GetErrorAndThrow("WinHttpGetCloseStatus() failed", err); + GetErrorAndThrow("WinHttpWebSocketQueryCloseStatus() failed", err); } return NativeWebSocketCloseInformation{closeStatus, std::string(closeReason)}; } @@ -137,7 +184,6 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { std::vector const& frameData, Azure::Core::Context const& context) { - context.ThrowIfCancelled(); WINHTTP_WEB_SOCKET_BUFFER_TYPE bufferType; switch (frameType) { @@ -158,43 +204,67 @@ namespace Azure { namespace Core { namespace Http { namespace WebSockets { "Unknown frame type: " + std::to_string(static_cast(frameType))); break; } + // Lock the socket to prevent concurrent writes. WinHTTP gets annoyed if // there are multiple WinHttpWebSocketSend requests outstanding. std::lock_guard lock(m_sendMutex); - auto err = WinHttpWebSocketSend( - m_socketHandle.get(), - bufferType, - reinterpret_cast(const_cast(frameData.data())), - static_cast(frameData.size())); - if (err != 0) + m_sendMutexOwner = GetCurrentThreadId(); + if (!m_httpAction->WaitForAction( + [&]() { + auto err = WinHttpWebSocketSend( + m_socketHandle.get(), + bufferType, + reinterpret_cast(const_cast(frameData.data())), + static_cast(frameData.size())); + if (err != 0) + { + GetErrorAndThrow("WinHttpWebSocketSend() failed", err); + } + }, + WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, + context)) { - GetErrorAndThrow("WinHttpWebSocketSend() failed", err); + GetErrorAndThrow( + "Error Sending WebSocket synchronously", + m_httpAction->GetStowedError(WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE)); } } WinHttpWebSocketTransport::NativeWebSocketReceiveInformation WinHttpWebSocketTransport::NativeReceiveFrame(Azure::Core::Context const& context) { - WINHTTP_WEB_SOCKET_BUFFER_TYPE bufferType; + WINHTTP_WEB_SOCKET_BUFFER_TYPE bufferType{}; NativeWebSocketFrameType frameTypeReceived; - DWORD bufferBytesRead; + DWORD bufferBytesRead{}; std::vector buffer(128); - context.ThrowIfCancelled(); - std::lock_guard lock(m_receiveMutex); - auto err = WinHttpWebSocketReceive( - m_socketHandle.get(), - reinterpret_cast(buffer.data()), - static_cast(buffer.size()), - &bufferBytesRead, - &bufferType); - if (err != 0 && err != ERROR_INSUFFICIENT_BUFFER) + std::lock_guard lock(m_receiveMutex); + m_receiveMutexOwner = GetCurrentThreadId(); + if (!m_httpAction->WaitForAction( + [&]() { + auto err = WinHttpWebSocketReceive( + m_socketHandle.get(), + reinterpret_cast(buffer.data()), + static_cast(buffer.size()), + &bufferBytesRead, + &bufferType); + if (err != 0 && err != ERROR_INSUFFICIENT_BUFFER) + { + GetErrorAndThrow("WinHttpWebSocketReceive() failed", err); + } + }, + WINHTTP_CALLBACK_STATUS_READ_COMPLETE, + context)) { - GetErrorAndThrow("WinHttpWebSocketReceive() failed", err); + GetErrorAndThrow( + "Error Receiving WebSocket frame synchronously", + m_httpAction->GetStowedError(WINHTTP_CALLBACK_STATUS_READ_COMPLETE)); } - buffer.resize(bufferBytesRead); - switch (bufferType) + buffer.resize(m_httpAction->GetWebSocketStatus(WINHTTP_CALLBACK_STATUS_READ_COMPLETE) + ->dwBytesTransferred); + + switch (m_httpAction->GetWebSocketStatus(WINHTTP_CALLBACK_STATUS_READ_COMPLETE)->eBufferType) { case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE: frameTypeReceived = NativeWebSocketFrameType::Text; diff --git a/sdk/core/azure-core/src/private/package_version.hpp b/sdk/core/azure-core/src/private/package_version.hpp index 5c06d2895c..8b58e77937 100644 --- a/sdk/core/azure-core/src/private/package_version.hpp +++ b/sdk/core/azure-core/src/private/package_version.hpp @@ -13,7 +13,7 @@ #define AZURE_CORE_VERSION_MAJOR 1 #define AZURE_CORE_VERSION_MINOR 8 #define AZURE_CORE_VERSION_PATCH 0 -#define AZURE_CORE_VERSION_PRERELEASE "beta.1" +#define AZURE_CORE_VERSION_PRERELEASE "beta.2" #define AZURE_CORE_VERSION_ITOA_HELPER(i) #i #define AZURE_CORE_VERSION_ITOA(i) AZURE_CORE_VERSION_ITOA_HELPER(i) @@ -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/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..33d387ca52 100644 --- a/sdk/core/azure-core/test/ut/transport_policy_options.cpp +++ b/sdk/core/azure-core/test/ut/transport_policy_options.cpp @@ -149,15 +149,15 @@ namespace Azure { namespace Core { namespace Test { } } { -#if defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER) +#if defined(BUILD_TRANSPORT_WINHTTP_ADAPTER) + Azure::Core::Http::WinHttpTransportOptions winHttpOptions; + winHttpOptions.IgnoreUnknownCertificateAuthority = true; + options.Transport = std::make_shared(winHttpOptions); +#elif defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER) Azure::Core::Http::CurlTransportOptions curlOptions; curlOptions.SslVerifyPeer = false; curlOptions.EnableCurlTracing = true; options.Transport = std::make_shared(curlOptions); -#elif defined(BUILD_TRANSPORT_WINHTTP_ADAPTER) - Azure::Core::Http::WinHttpTransportOptions winHttpOptions; - winHttpOptions.IgnoreUnknownCertificateAuthority = true; - options.Transport = std::make_shared(winHttpOptions); #endif auto pipeline = CreateHttpPipeline(options); auto request = Azure::Core::Http::Request( @@ -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/azure-core/test/ut/websocket_test.cpp b/sdk/core/azure-core/test/ut/websocket_test.cpp index 0227f7ce6d..55de3f7893 100644 --- a/sdk/core/azure-core/test/ut/websocket_test.cpp +++ b/sdk/core/azure-core/test/ut/websocket_test.cpp @@ -3,7 +3,9 @@ #include "../../src/http/websockets/websockets_impl.hpp" #include "azure/core/http/websockets/websockets.hpp" +#include "azure/core/internal/environment.hpp" #include "azure/core/internal/json/json.hpp" +#include "azure/core/platform.hpp" #include #include #include @@ -22,8 +24,26 @@ using namespace std::chrono_literals; constexpr uint16_t UndefinedButLegalCloseReason = 4500; class WebSocketTests : public testing::Test { -private: protected: + std::string HttpProxyServer() + { + std::string proxyUrl{Azure::Core::_internal::Environment::GetVariable("SQUID_PROXY_URL")}; + if (proxyUrl.empty()) + { + proxyUrl = "http://127.0.0.1:3128"; + } + return proxyUrl; + } + std::string HttpProxyServerWithPassword() + { + std::string proxyUrl{Azure::Core::_internal::Environment::GetVariable("SQUID_AUTH_PROXY_URL")}; + if (proxyUrl.empty()) + { + proxyUrl = "http://127.0.0.1:3129"; + } + return proxyUrl; + } + // Create static void SetUpTestSuite() {} static void TearDownTestSuite() {} @@ -55,7 +75,7 @@ TEST_F(WebSocketTests, OpenSimpleSocket) { WebSocketOptions options; - WebSocket defaultSocket(Azure::Core::Url("http://www.microsoft.com/"), options); + WebSocket defaultSocket(Azure::Core::Url("https://www.microsoft.com/"), options); defaultSocket.AddHeader("newHeader", "headerValue"); // When running this test locally, the call times out, so drop in a 5 second timeout on @@ -286,7 +306,7 @@ TEST_F(WebSocketTests, CloseDuringEcho) } }); - std::this_thread::sleep_for(100ms); + std::this_thread::sleep_for(1s); // Close the socket gracefully. GTEST_LOG_(INFO) << "Closing Socket."; @@ -711,20 +731,22 @@ TEST_F(WebSocketTests, MultiThreadedTestOnMultipleSockets) // Does not work because curl rejects the wss: scheme. class LibWebSocketIncrementProtocol { WebSocketOptions m_options{{"dumb-increment-protocol"}}; - WebSocket m_socket; + std::unique_ptr m_socket; public: - LibWebSocketIncrementProtocol() : m_socket{Azure::Core::Url("wss://libwebsockets.org"), m_options} + LibWebSocketIncrementProtocol(std::string proxyUrl = {}) { + m_options.Transport.HttpProxy = proxyUrl; + m_socket = std::make_unique(Azure::Core::Url("wss://libwebsockets.org"), m_options); } - void Open() { m_socket.Open(); } + void Open() { m_socket->Open(); } int GetNextNumber() { // Time out in 5 seconds if no activity. Azure::Core::Context contextWithTimeout = Azure::Core::Context().WithDeadline(std::chrono::system_clock::now() + 10s); - auto work = m_socket.ReceiveFrame(contextWithTimeout); + auto work = m_socket->ReceiveFrame(contextWithTimeout); if (work->FrameType == WebSocketFrameType::TextFrameReceived) { auto frame = work->AsTextFrame(); @@ -746,18 +768,18 @@ class LibWebSocketIncrementProtocol { } } - void Reset() { m_socket.SendFrame("reset\n", true); } - void RequestClose() { m_socket.SendFrame("closeme\n", true); } - void Close() { m_socket.Close(); } + void Reset() { m_socket->SendFrame("reset\n", true); } + void RequestClose() { m_socket->SendFrame("closeme\n", true); } + void Close() { m_socket->Close(); } void Close(uint16_t closeCode, std::string const& reasonText = {}) { - m_socket.Close(closeCode, reasonText); + m_socket->Close(closeCode, reasonText); } void ConsumeUntilClosed() { - while (m_socket.IsOpen()) + while (m_socket->IsOpen()) { - auto work = m_socket.ReceiveFrame(); + auto work = m_socket->ReceiveFrame(); if (work->FrameType == WebSocketFrameType::PeerClosedReceived) { auto peerClose = work->AsPeerCloseFrame(); @@ -842,6 +864,7 @@ TEST_F(WebSocketTests, LibWebSocketOrgLwsStatus) EXPECT_TRUE(foundOurConnection); } } + TEST_F(WebSocketTests, LibWebSocketOrgIncrement) { { @@ -864,6 +887,32 @@ TEST_F(WebSocketTests, LibWebSocketOrgIncrement) incrementProtocol.ConsumeUntilClosed(); } } + +#if !defined(DISABLE_PROXY_TESTS) +TEST_F(WebSocketTests, ProxyTestLibWebSocketOrgIncrement) +{ + { + LibWebSocketIncrementProtocol incrementProtocol{HttpProxyServer()}; + incrementProtocol.Open(); + + // Note that we cannot practically validate the numbers received from the service because + // they may be in flight at the time the "Reset" call is made. + for (auto i = 0; i < 100; i += 1) + { + if (i % 5 == 0) + { + GTEST_LOG_(INFO) << "Reset" << std::endl; + incrementProtocol.Reset(); + } + int number = incrementProtocol.GetNextNumber(); + GTEST_LOG_(INFO) << "Got next number " << number << std::endl; + } + incrementProtocol.RequestClose(); + incrementProtocol.ConsumeUntilClosed(); + } +} +#endif // DISABLE_PROXY_TESTS + #if defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER) TEST_F(WebSocketTests, CurlTransportCoverage) { diff --git a/sdk/core/ci.yml b/sdk/core/ci.yml index 7edefdcf61..93742b2ace 100644 --- a/sdk/core/ci.yml +++ b/sdk/core/ci.yml @@ -99,6 +99,7 @@ stages: runProxy: true targetVersion: 1.0.0-dev.20220810.2 condition: and(succeeded(), contains(variables.CmakeArgs, 'BUILD_TESTING=ON')) + PostTestSteps: # Shut down the test server. This uses curl to send a request to the "terminateserver" websocket endpoint. # When the test server receives a request on terminateserver, it shuts down gracefully. @@ -121,11 +122,6 @@ stages: } displayName: Shutdown Squid Proxy. condition: and(variables.RunProxyTests, contains(variables.CmakeArgs, 'BUILD_TESTING=ON'), contains(variables['OSVmImage'], 'linux')) - - template: /eng/common/pipelines/templates/steps/publish-artifact.yml - parameters: - ArtifactPath: '$(Build.SourcesDirectory)/WebSocketServer.log' - ArtifactName: 'WebSocketLogs-$(Agent.JobName)_attempt_$(System.JobAttempt)' - CustomCondition: contains(variables.CmakeArgs, 'BUILD_TESTING=ON') Artifacts: - Name: azure-core diff --git a/sdk/core/perf.yml b/sdk/core/perf.yml index a8494272b1..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 @@ -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/README.md b/sdk/core/perf/README.md index 7e9f3a2d12..76978c4255 100644 --- a/sdk/core/perf/README.md +++ b/sdk/core/perf/README.md @@ -46,6 +46,7 @@ usage: azure-perf-test testName [options] >Note: You can use the option `-h` to print out the available options for a test name. The next options can be used for any test: + | Option | Activators | Description | Default | Example | | ---------- | --- | ---| ---| --- | | Duration | -d, --duration | Duration of the test in seconds | 10 | -d 5 diff --git a/sdk/core/perf/inc/azure/perf/argagg.hpp b/sdk/core/perf/inc/azure/perf/argagg.hpp index 0ece3a9488..11bdaeb697 100644 --- a/sdk/core/perf/inc/azure/perf/argagg.hpp +++ b/sdk/core/perf/inc/azure/perf/argagg.hpp @@ -1436,7 +1436,7 @@ inline fmt_ostream::~fmt_ostream() { output << fmt_string(this->str()); } inline std::string lstrip(const std::string& text) { - auto result = text; + std::string result = text; result.erase(result.begin(), std::find_if(result.begin(), result.end(), [](int ch) { return !std::isspace(ch); @@ -1447,7 +1447,7 @@ inline std::string lstrip(const std::string& text) inline std::string rstrip(const std::string& text) { - auto result = text; + std::string result = text; result.erase( std::find_if(result.rbegin(), result.rend(), [](int ch) { return !std::isspace(ch); }).base(), diff --git a/sdk/core/perf/src/arg_parser.cpp b/sdk/core/perf/src/arg_parser.cpp index 5080128fb0..6350ebe7e6 100644 --- a/sdk/core/perf/src/arg_parser.cpp +++ b/sdk/core/perf/src/arg_parser.cpp @@ -18,12 +18,12 @@ argagg::parser_results Azure::Perf::Program::ArgParser::Parse( // Option Name, Activate options, display message and number of expected args. argagg::parser argParser; auto optionsMetadata = Azure::Perf::GlobalTestOptions::GetOptionMetadata(); - for (auto option : testOptions) + for (auto const& option : testOptions) { argParser.definitions.push_back( {option.Name, option.Activators, option.DisplayMessage, option.ExpectedArgs}); } - for (auto option : optionsMetadata) + for (auto const& option : optionsMetadata) { argParser.definitions.push_back( {option.Name, option.Activators, option.DisplayMessage, option.ExpectedArgs}); diff --git a/sdk/core/perf/src/base_test.cpp b/sdk/core/perf/src/base_test.cpp index a073326b6d..2060b1cc5b 100644 --- a/sdk/core/perf/src/base_test.cpp +++ b/sdk/core/perf/src/base_test.cpp @@ -32,7 +32,7 @@ class ProxyPolicy final : public HttpPolicy { ProxyPolicy(ProxyPolicy const& other) : ProxyPolicy{other.m_testContext} {} // move - ProxyPolicy(ProxyPolicy&& other) : m_testContext{other.m_testContext} {} + ProxyPolicy(ProxyPolicy&& other) noexcept : m_testContext{other.m_testContext} {} std::unique_ptr Send( Request& request, 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/core/perf/src/program.cpp b/sdk/core/perf/src/program.cpp index e56af90276..c788388c72 100644 --- a/sdk/core/perf/src/program.cpp +++ b/sdk/core/perf/src/program.cpp @@ -4,25 +4,26 @@ #include "azure/perf/program.hpp" #include "azure/perf/argagg.hpp" +#include #include #include +#include #include +#include #include #include namespace { -inline std::unique_ptr PrintAvailableTests( - std::vector const& tests) +inline void PrintAvailableTests(std::vector const& tests) { std::cout << "No test name found in the input. Available tests to run:" << std::endl; std::cout << std::endl << "Name\t\tDescription" << std::endl << "---\t\t---" << std::endl; - for (auto test : tests) + for (auto const& test : tests) { std::cout << test.Name << "\t\t" << test.Description << std::endl; } - return nullptr; } inline Azure::Perf::TestMetadata const* GetTestMetadata( @@ -37,14 +38,17 @@ inline Azure::Perf::TestMetadata const* GetTestMetadata( argagg::parser argParser; auto args = argParser.parse(argc, argv, true); - auto testName = std::string(args.pos[0]); - - for (auto& test : tests) + if (!args.pos.empty()) { - if (Azure::Core::_internal::StringExtensions::LocaleInvariantCaseInsensitiveEqual( - test.Name, testName)) + auto testName = std::string(args.pos[0]); + + for (auto& test : tests) { - return &test; + if (Azure::Core::_internal::StringExtensions::LocaleInvariantCaseInsensitiveEqual( + test.Name, testName)) + { + return &test; + } } } return nullptr; @@ -79,12 +83,13 @@ inline void PrintOptions( { std::cout << std::endl << "=== Test Options ===" << std::endl; Azure::Core::Json::_internal::json optionsAsJson; - for (auto option : testOptions) + for (auto const& option : testOptions) { try { - optionsAsJson[option.Name] - = option.SensitiveData ? "***" : parsedArgs[option.Name].as(); + auto optionName{option.Name}; + optionsAsJson[optionName] + = option.SensitiveData ? "***" : parsedArgs[optionName].as(); } catch (std::out_of_range const&) { @@ -199,14 +204,14 @@ inline void RunTests( std::vector lastCompletionTimes(parallelTestsCount); /********************* Progress Reporter ******************************/ - Azure::Core::Context progresToken; + Azure::Core::Context progressToken; uint64_t lastCompleted = 0; auto progressThread = std::thread( - [&title, &completedOperations, &lastCompletionTimes, &lastCompleted, &progresToken]() { + [&title, &completedOperations, &lastCompletionTimes, &lastCompleted, &progressToken]() { std::cout << std::endl << "=== " << title << " ===" << std::endl << "Current\t\tTotal\t\tAverage" << std::endl; - while (!progresToken.IsCancelled()) + while (!progressToken.IsCancelled()) { using namespace std::chrono_literals; std::this_thread::sleep_for(1000ms); @@ -228,7 +233,6 @@ inline void RunTests( bool isCancelled = false; // Azure::Context is not good performer for checking cancellation inside the test loop auto manualCancellation = std::thread([&deadLineSeconds, &isCancelled] { - using namespace std::chrono_literals; std::this_thread::sleep_for(deadLineSeconds); isCancelled = true; }); @@ -251,7 +255,7 @@ inline void RunTests( } // Stop progress - progresToken.Cancel(); + progressToken.Cancel(); progressThread.join(); std::cout << std::endl << "=== Results ==="; @@ -278,6 +282,17 @@ void Azure::Perf::Program::Run( int argc, char** argv) { + // 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 + + // 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, Azure::Core::Diagnostics::_internal::GlobalExceptionHandler::HandleSigAbort); +#endif // AZ_PLATFORM_WINDOWS + // Parse args only to get the test name first auto testMetadata = GetTestMetadata(tests, argc, argv); auto const& testGenerator = testMetadata->Factory; @@ -285,8 +300,10 @@ void Azure::Perf::Program::Run( { // Wrong input. Print what are the options. PrintAvailableTests(tests); + return; } + // Initial test to get it's options, we can use a dummy parser results argagg::parser_results argResults; auto test = testGenerator(Azure::Perf::TestOptions(argResults)); @@ -351,7 +368,7 @@ void Azure::Perf::Program::Run( { if (!options.TestProxies.empty()) { - std::cout << " - Creating test recordgins for each test using test-proxies..." << std::endl; + std::cout << " - Creating test recordings for each test using test-proxies..." << std::endl; std::cout << " - Enabling test-proxy playback" << std::endl; } @@ -375,20 +392,13 @@ void Azure::Perf::Program::Run( /******************** Tests ******************************/ std::string iterationInfo; - try + for (int iteration = 0; iteration < options.Iterations; iteration++) { - for (int iteration = 0; iteration < options.Iterations; iteration++) + if (iteration > 0) { - if (iteration > 0) - { - iterationInfo.append(FormatNumber(iteration)); - } - RunTests(context, parallelTest, options, "Test" + iterationInfo); + iterationInfo.append(FormatNumber(iteration)); } - } - catch (std::exception const& error) - { - std::cout << "Error: " << error.what(); + RunTests(context, parallelTest, options, "Test" + iterationInfo); } std::cout << std::endl << "=== Pre-Cleanup ===" << std::endl; diff --git a/sdk/core/perf/test/CMakeLists.txt b/sdk/core/perf/test/CMakeLists.txt index 2e75b63adf..b06bbb3133 100644 --- a/sdk/core/perf/test/CMakeLists.txt +++ b/sdk/core/perf/test/CMakeLists.txt @@ -38,8 +38,16 @@ target_include_directories( $ ) +if(DEFINED ENV{VCPKG-AZURE-CORE-CPP}) + find_package(azure-core-cpp $ENV{VCPKG-AZURE-CORE-CPP} EXACT) + add_compile_definitions(VCPKG_CORE_VERSION="$ENV{VCPKG-AZURE-CORE-CPP}") +else() + add_compile_definitions(VCPKG_CORE_VERSION="source") +endif() + + # link the `azure-perf` lib together with any other library which will be used for the tests. -target_link_libraries(azure-perf-test PRIVATE azure-core azure-perf) +target_link_libraries(azure-perf-test PRIVATE Azure::azure-core azure-perf) # Make sure the project will appear in the test folder for Visual Studio CMake view set_target_properties(azure-perf-test PROPERTIES FOLDER "Tests/Core") diff --git a/sdk/core/perf/test/inc/azure/perf/test/curl_http_client_get_test.hpp b/sdk/core/perf/test/inc/azure/perf/test/curl_http_client_get_test.hpp index 155198fe99..6483cff56a 100644 --- a/sdk/core/perf/test/inc/azure/perf/test/curl_http_client_get_test.hpp +++ b/sdk/core/perf/test/inc/azure/perf/test/curl_http_client_get_test.hpp @@ -36,7 +36,7 @@ namespace Azure { namespace Perf { namespace Test { */ void GlobalSetup() override { - _detail::HttpClient = std::make_unique(); + m_httpClient = std::make_unique(); } /** diff --git a/sdk/core/perf/test/inc/azure/perf/test/delay_test.hpp b/sdk/core/perf/test/inc/azure/perf/test/delay_test.hpp index 4d779f1106..9a21179cd8 100644 --- a/sdk/core/perf/test/inc/azure/perf/test/delay_test.hpp +++ b/sdk/core/perf/test/inc/azure/perf/test/delay_test.hpp @@ -56,7 +56,7 @@ namespace Azure { namespace Perf { namespace Test { { // Increment the counter and fetch the value, then remove 1 to get the previous-increment // value - auto instanceCount = _detail::DelayTestInstanceCount.fetch_add(1) - 1; + auto instanceCount = _detail::DelayTestInstanceCount.fetch_add(0); // default value if option is not parsed is 1000 auto initialDelay = m_options.GetOptionOrDefault("InitialDelayMs", 1000); auto instanceGrowFactor = m_options.GetOptionOrDefault("InstanceGrowthFactor", 1); @@ -77,17 +77,14 @@ namespace Azure { namespace Perf { namespace Test { std::vector GetTestOptions() override { return { - {"InitialDelayMs", - {"--delay"}, - "Initial delay (in milliseconds). Default to 1000 (1sec)", - 1}, + {"InitialDelayMs", {"-m"}, "Initial delay (in milliseconds). Default to 1000 (1sec)", 1}, {"InstanceGrowthFactor", - {"--infactor"}, + {"-n"}, "Instance growth factor. The delay of instance N will be (InitialDelayMS * " "(InstanceGrowthFactor ^ InstanceCount)). Default to 1", 1}, {"IterationGrowthFactor", - {"--itfactor"}, + {"-t"}, "Initial delay (in milliseconds). The delay of iteration N will be (InitialDelayMS * " "(IterationGrowthFactor ^ IterationCount)). Default to 1", 1}}; diff --git a/sdk/core/perf/test/inc/azure/perf/test/http_client_get_test.hpp b/sdk/core/perf/test/inc/azure/perf/test/http_client_get_test.hpp index 6bfd2f2f3d..7e206e8de9 100644 --- a/sdk/core/perf/test/inc/azure/perf/test/http_client_get_test.hpp +++ b/sdk/core/perf/test/inc/azure/perf/test/http_client_get_test.hpp @@ -20,10 +20,6 @@ namespace Azure { namespace Perf { namespace Test { - namespace _detail { - static std::unique_ptr HttpClient; - } // namespace _detail - /** * @brief A performance test that defines a test option. * @@ -31,6 +27,7 @@ namespace Azure { namespace Perf { namespace Test { class HttpClientGetTest : public Azure::Perf::PerfTest { protected: Azure::Core::Url m_url; + static std::unique_ptr m_httpClient; public: /** @@ -57,7 +54,7 @@ namespace Azure { namespace Perf { namespace Test { void Run(Azure::Core::Context const& ctx) override { Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, m_url); - auto response = _detail::HttpClient->Send(request, ctx); + auto response = m_httpClient->Send(request, ctx); // Read the body from network auto bodyStream = response->ExtractBodyStream(); response->SetBody(bodyStream->ReadToEnd(ctx)); @@ -74,4 +71,6 @@ namespace Azure { namespace Perf { namespace Test { } }; + std::unique_ptr HttpClientGetTest::m_httpClient; + }}} // namespace Azure::Perf::Test diff --git a/sdk/core/perf/test/inc/azure/perf/test/http_pipeline_get_test.hpp b/sdk/core/perf/test/inc/azure/perf/test/http_pipeline_get_test.hpp new file mode 100644 index 0000000000..6fe16f62b0 --- /dev/null +++ b/sdk/core/perf/test/inc/azure/perf/test/http_pipeline_get_test.hpp @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/** + * @file + * @brief Performance test measuring the use of an HTTP pipeline (and optionally test proxy). + * + */ + +#pragma once + +#include + +#include +#include +#include +#include + +#include +#include + +namespace Azure { namespace Perf { namespace Test { + + /** + * @brief A performance test that defines a test option. + * + */ + class HttpPipelineGetTest : public Azure::Perf::PerfTest { + Azure::Core::Url m_url; + + public: + /** + * @brief Construct a new Extended Options Test object. + * + * @param options The command-line parsed options. + */ + HttpPipelineGetTest(Azure::Perf::TestOptions options) : PerfTest(options) {} + + /** + * @brief Get and set the URL option + * + */ + void Setup() override + { + m_url = Azure::Core::Url(m_options.GetMandatoryOption("url")); + } + + /** + * @brief Set up the HTTP client + * + */ + void GlobalSetup() override {} + + /** + * @brief Get the static Test Metadata for the test. + * + * @return Azure::Perf::TestMetadata describing the test. + */ + static Azure::Perf::TestMetadata GetTestMetadata() + { + return { + "httpPipelineGet", + "Send an HTTP GET request to a configurable URL using Azure Pipelines.", + [](Azure::Perf::TestOptions options) { + return std::make_unique(options); + }}; + } + /** + * @brief Define the test options for the test. + * + * @return The list of test options. + */ + std::vector GetTestOptions() override + { + return {{"url", {"--url"}, "Url to send the HTTP request. *Required parameter.", 1, true}}; + } + + /** + * @brief The test definition + * + * @param ctx The cancellation token. + */ + void Run(Azure::Core::Context const& ctx) override + { + Azure::Core::_internal::ClientOptions clientOptions; + + ConfigureClientOptions(clientOptions); + std::vector> perRequest; + std::vector> perRetry; + Azure::Core::Http::_internal::HttpPipeline pipeline( + clientOptions, "PipelineTest", "na", std::move(perRequest), std::move(perRetry)); + + Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, m_url); + auto response = pipeline.Send(request, ctx); + response->GetBody(); + } + }; + +}}} // namespace Azure::Perf::Test diff --git a/sdk/core/perf/test/inc/azure/perf/test/no_op_test.hpp b/sdk/core/perf/test/inc/azure/perf/test/no_op_test.hpp index 1910ec3cf2..f3875cda41 100644 --- a/sdk/core/perf/test/inc/azure/perf/test/no_op_test.hpp +++ b/sdk/core/perf/test/inc/azure/perf/test/no_op_test.hpp @@ -32,7 +32,21 @@ namespace Azure { namespace Perf { namespace Test { * @brief Define an empty test. * */ - void Run(Azure::Core::Context const&) override {} + void Run(Azure::Core::Context const&) override + { // Get the option or a default value of 0 + auto myTestOption = m_options.GetOptionOrDefault("extraOption", 0); + (void)myTestOption; + } + + /** + * @brief Define the test options for the test. + * + * @return The list of test options. + */ + std::vector GetTestOptions() override + { + return {{"extraOption", {"-e"}, "Example for extended option for test.", 1}}; + } /** * @brief Get the static Test Metadata for the test. diff --git a/sdk/core/perf/test/inc/azure/perf/test/win_http_client_get_test.hpp b/sdk/core/perf/test/inc/azure/perf/test/win_http_client_get_test.hpp index 413be3245c..6363305e52 100644 --- a/sdk/core/perf/test/inc/azure/perf/test/win_http_client_get_test.hpp +++ b/sdk/core/perf/test/inc/azure/perf/test/win_http_client_get_test.hpp @@ -34,7 +34,7 @@ namespace Azure { namespace Perf { namespace Test { */ void GlobalSetup() override { - _detail::HttpClient = std::make_unique(); + m_httpClient = std::make_unique(); } /** diff --git a/sdk/core/perf/test/src/perf_test.cpp b/sdk/core/perf/test/src/perf_test.cpp index 9f827fcbc0..bbe9cd2d46 100644 --- a/sdk/core/perf/test/src/perf_test.cpp +++ b/sdk/core/perf/test/src/perf_test.cpp @@ -5,6 +5,7 @@ #include "azure/perf/test/delay_test.hpp" #include "azure/perf/test/extended_options_test.hpp" +#include "azure/perf/test/http_pipeline_get_test.hpp" #if defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER) #include "azure/perf/test/curl_http_client_get_test.hpp" #endif @@ -18,13 +19,15 @@ int main(int argc, char** argv) { - + std::cout << "AZURE-CORE-CPP VERSION " << VCPKG_CORE_VERSION << std::endl; // Create the test list std::vector tests{ Azure::Perf::Test::NoOp::GetTestMetadata(), Azure::Perf::Test::ExtendedOptionsTest::GetTestMetadata(), Azure::Perf::Test::DelayTest::GetTestMetadata(), - Azure::Perf::Test::ExceptionTest::GetTestMetadata()}; + Azure::Perf::Test::ExceptionTest::GetTestMetadata(), + Azure::Perf::Test::HttpPipelineGetTest::GetTestMetadata(), + }; #if defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER) tests.emplace_back(Azure::Perf::Test::CurlHttpClientGetTest::GetTestMetadata()); 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/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/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); diff --git a/sdk/keyvault/azure-security-keyvault-certificates/CHANGELOG.md b/sdk/keyvault/azure-security-keyvault-certificates/CHANGELOG.md index 63171c8ca4..db741d2998 100644 --- a/sdk/keyvault/azure-security-keyvault-certificates/CHANGELOG.md +++ b/sdk/keyvault/azure-security-keyvault-certificates/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 4.1.0-beta.2 (Unreleased) +## 4.2.0-beta.1 (Unreleased) ### Features Added @@ -10,6 +10,12 @@ ### Other Changes +## 4.1.0 (2022-10-11) + +### Features Added + +- Keyvault 7.3 support added for Certificates. + ## 4.1.0-beta.1 (2022-07-07) ### Features Added 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 55e836f964..526efc55d9 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 @@ -11,7 +11,7 @@ #include #define AZURE_SECURITY_KEYVAULT_CERTIFICATES_VERSION_MAJOR 4 -#define AZURE_SECURITY_KEYVAULT_CERTIFICATES_VERSION_MINOR 1 +#define AZURE_SECURITY_KEYVAULT_CERTIFICATES_VERSION_MINOR 2 #define AZURE_SECURITY_KEYVAULT_CERTIFICATES_VERSION_PATCH 0 #define AZURE_SECURITY_KEYVAULT_CERTIFICATES_VERSION_PRERELEASE "beta.2" @@ -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/CHANGELOG.md b/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md index 5bc04107a4..e5fb3a3b23 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md +++ b/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 4.3.0-beta.2 (Unreleased) +## 4.4.0-beta.1 (Unreleased) ### Features Added @@ -10,6 +10,12 @@ ### Other Changes +## 4.3.0 (2022-10-11) + +### Features Added + +- Keyvault 7.3 support added for Keys. + ## 4.3.0-beta.1 (2022-07-07) ### Features Added 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 a79e5bbb04..34d8a03dac 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 @@ -11,7 +11,7 @@ #include #define AZURE_SECURITY_KEYVAULT_KEYS_VERSION_MAJOR 4 -#define AZURE_SECURITY_KEYVAULT_KEYS_VERSION_MINOR 3 +#define AZURE_SECURITY_KEYVAULT_KEYS_VERSION_MINOR 4 #define AZURE_SECURITY_KEYVAULT_KEYS_VERSION_PATCH 0 #define AZURE_SECURITY_KEYVAULT_KEYS_VERSION_PRERELEASE "beta.2" @@ -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/CHANGELOG.md b/sdk/keyvault/azure-security-keyvault-secrets/CHANGELOG.md index a8d5bab494..67cabd93a6 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/CHANGELOG.md +++ b/sdk/keyvault/azure-security-keyvault-secrets/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 4.1.0-beta.2 (Unreleased) +## 4.2.0-beta.1 (Unreleased) ### Features Added @@ -10,6 +10,12 @@ ### Other Changes +## 4.1.0 (2022-10-11) + +### Features Added + +- Keyvault 7.3 support added for Secrets. + ## 4.1.0-beta.1 (2022-07-07) ### Features Added 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 23e0cc9253..a5f33e7ebf 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 @@ -11,7 +11,7 @@ #include #define AZURE_SECURITY_KEYVAULT_SECRETS_VERSION_MAJOR 4 -#define AZURE_SECURITY_KEYVAULT_SECRETS_VERSION_MINOR 1 +#define AZURE_SECURITY_KEYVAULT_SECRETS_VERSION_MINOR 2 #define AZURE_SECURITY_KEYVAULT_SECRETS_VERSION_PATCH 0 #define AZURE_SECURITY_KEYVAULT_SECRETS_VERSION_PRERELEASE "beta.2" @@ -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/CHANGELOG.md b/sdk/storage/azure-storage-blobs/CHANGELOG.md index bbc3e87f8a..60f3b6909d 100644 --- a/sdk/storage/azure-storage-blobs/CHANGELOG.md +++ b/sdk/storage/azure-storage-blobs/CHANGELOG.md @@ -10,6 +10,12 @@ ### Other Changes +## 12.6.2 (2022-10-11) + +### Other Changes + +- No public changes in this release. + ## 12.6.1 (2022-09-16) ### Other changes 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/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-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/sdk/storage/azure-storage-blobs/vcpkg.json b/sdk/storage/azure-storage-blobs/vcpkg.json index ae37d635b5..78b0f74cdf 100644 --- a/sdk/storage/azure-storage-blobs/vcpkg.json +++ b/sdk/storage/azure-storage-blobs/vcpkg.json @@ -1,6 +1,6 @@ { "name": "azure-storage-blobs-cpp", - "version-semver": "12.6.1", + "version-semver": "12.6.2", "description": [ "Microsoft Azure Storage Blobs SDK for C++", "This library provides Azure Storage Blobs SDK." 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 2c728abf54..4d2573c9fa 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/CHANGELOG.md b/sdk/storage/azure-storage-files-datalake/CHANGELOG.md index befcee05ce..c1c789a85a 100644 --- a/sdk/storage/azure-storage-files-datalake/CHANGELOG.md +++ b/sdk/storage/azure-storage-files-datalake/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 12.4.0-beta.1 (Unreleased) +## 12.4.0-beta.2 (Unreleased) ### Features Added @@ -8,11 +8,28 @@ ### Bugs Fixed +### Other Changes + +## 12.4.0-beta.1 (2022-10-11) + +### Features Added + +- Added support for encryption scope in SAS builder. +- Added support for customer-provided key. +- Added support for flushing when appending data to a file. +- Added some new fields in `CreatePathOptions`. +- New APIs: + - DataLakeServiceClient::SetProperties + - DataLakeServiceClient::GetProperties + - DataLakeFileSystemClient::ListDeletedPaths + - DataLakeFileSystemClient::UndeletePath + - DataLakeFileClient::Query + +### Bugs Fixed + - Fixed a bug where file/directory renaming cannot be authenticated with SAS. - Empty file or existing file won't be created/overwritten if the file to be downloaded doesn't exist. -### Other Changes - ## 12.3.1 (2022-03-09) ### Other Changes diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/rest_client.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/rest_client.hpp index a2d73be699..cce269de95 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/rest_client.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/rest_client.hpp @@ -162,7 +162,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { * The value of this header is set to true if the contents of the request are successfully * encrypted using the specified algorithm, and false otherwise. */ - Nullable IsServerEncrypted; + bool IsServerEncrypted = bool(); /** * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only * returned when the blob was encrypted with a customer-provided key. @@ -298,7 +298,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { * The value of this header is set to true if the contents of the request are successfully * encrypted using the specified algorithm, and false otherwise. */ - Nullable IsServerEncrypted; + bool IsServerEncrypted = bool(); /** * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only * returned when the blob was encrypted with a customer-provided key. @@ -319,7 +319,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { * The value of this header is set to true if the contents of the request are successfully * encrypted using the specified algorithm, and false otherwise. */ - Nullable IsServerEncrypted; + bool IsServerEncrypted = bool(); /** * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only * returned when the blob was encrypted with a customer-provided key. 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 ce25e4508a..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 @@ -11,7 +11,7 @@ #define AZURE_STORAGE_FILES_DATALAKE_VERSION_MAJOR 12 #define AZURE_STORAGE_FILES_DATALAKE_VERSION_MINOR 4 #define AZURE_STORAGE_FILES_DATALAKE_VERSION_PATCH 0 -#define AZURE_STORAGE_FILES_DATALAKE_VERSION_PRERELEASE "beta.1" +#define AZURE_STORAGE_FILES_DATALAKE_VERSION_PRERELEASE "beta.2" #define AZURE_STORAGE_FILES_DATALAKE_VERSION_ITOA_HELPER(i) #i #define AZURE_STORAGE_FILES_DATALAKE_VERSION_ITOA(i) \ @@ -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-datalake/src/rest_client.cpp b/sdk/storage/azure-storage-files-datalake/src/rest_client.cpp index c105e1428a..a88801e2db 100644 --- a/sdk/storage/azure-storage-files-datalake/src/rest_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/rest_client.cpp @@ -691,11 +691,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { response.LastModified = DateTime::Parse( pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); response.FileSize = std::stoll(pRawResponse->GetHeaders().at("Content-Length")); - if (pRawResponse->GetHeaders().count("x-ms-request-server-encrypted") != 0) - { - response.IsServerEncrypted - = pRawResponse->GetHeaders().at("x-ms-request-server-encrypted") == std::string("true"); - } + response.IsServerEncrypted + = pRawResponse->GetHeaders().at("x-ms-request-server-encrypted") == std::string("true"); if (pRawResponse->GetHeaders().count("x-ms-encryption-key-sha256") != 0) { response.EncryptionKeySha256 = Core::Convert::Base64Decode( @@ -775,11 +772,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { = Core::Convert::Base64Decode(pRawResponse->GetHeaders().at("x-ms-content-crc64")); response.TransactionalContentHash.Value().Algorithm = HashAlgorithm::Crc64; } - if (pRawResponse->GetHeaders().count("x-ms-request-server-encrypted") != 0) - { - response.IsServerEncrypted - = pRawResponse->GetHeaders().at("x-ms-request-server-encrypted") == std::string("true"); - } + response.IsServerEncrypted + = pRawResponse->GetHeaders().at("x-ms-request-server-encrypted") == std::string("true"); if (pRawResponse->GetHeaders().count("x-ms-encryption-key-sha256") != 0) { response.EncryptionKeySha256 = Core::Convert::Base64Decode( diff --git a/sdk/storage/azure-storage-files-datalake/swagger/README.md b/sdk/storage/azure-storage-files-datalake/swagger/README.md index b7c915b212..1ff26382ab 100644 --- a/sdk/storage/azure-storage-files-datalake/swagger/README.md +++ b/sdk/storage/azure-storage-files-datalake/swagger/README.md @@ -259,6 +259,7 @@ directive: $["201"].headers["Content-Length"]["x-ms-client-name"] = "FileSize"; $["201"].headers["Content-Length"]["x-nullable"] = true; $["201"].headers["x-ms-request-server-encrypted"]["x-nullable"] = true; + $["201"].headers["x-ms-request-server-encrypted"]["x-ms-client-default"] = "bool()"; $["201"].headers["x-ms-encryption-key-sha256"]["x-nullable"] = true; delete $["201"].headers["x-ms-continuation"]; $["201"].schema = { @@ -436,7 +437,6 @@ directive: $["Content-MD5"]["x-nullable"] = true; $["x-ms-content-crc64"]["x-ms-client-name"] = "TransactionalContentHash"; $["x-ms-content-crc64"]["x-nullable"] = true; - $["x-ms-request-server-encrypted"]["x-nullable"] = true; $["x-ms-encryption-key-sha256"]["x-nullable"] = true; delete $["ETag"]; ``` @@ -449,6 +449,5 @@ directive: where: $["x-ms-paths"]["/{filesystem}/{path}?action=flush"].patch.responses["200"].headers transform: > $["Content-Length"]["x-ms-client-name"] = "FileSize"; - $["x-ms-request-server-encrypted"]["x-nullable"] = true; $["x-ms-encryption-key-sha256"]["x-nullable"] = true; ``` \ No newline at end of file diff --git a/sdk/storage/azure-storage-files-datalake/test/ut/datalake_file_system_client_test.cpp b/sdk/storage/azure-storage-files-datalake/test/ut/datalake_file_system_client_test.cpp index 5278d72e59..d1dfc4a3d1 100644 --- a/sdk/storage/azure-storage-files-datalake/test/ut/datalake_file_system_client_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/ut/datalake_file_system_client_test.cpp @@ -844,7 +844,7 @@ namespace Azure { namespace Storage { namespace Test { m_fileSystemClient->GetDirectoryClient(destinationDirectoryName).GetProperties()); } - TEST_F(DataLakeFileSystemClientTest, DISABLED_ListDeletedPaths) + TEST_F(DataLakeFileSystemClientTest, ListDeletedPaths) { const std::string deletedFilename = GetTestNameLowerCase() + "_file_deleted"; const std::string nonDeletedFilename = GetTestNameLowerCase() + "_file"; @@ -912,7 +912,7 @@ namespace Azure { namespace Storage { namespace Test { } } - TEST_F(DataLakeFileSystemClientTest, DISABLED_Undelete) + TEST_F(DataLakeFileSystemClientTest, Undelete) { const std::string directoryName = GetTestNameLowerCase() + "_dir"; const std::string subFileName = "sub_file"; diff --git a/sdk/storage/azure-storage-files-datalake/test/ut/recordings/DataLakeFileSystemClientTest.ListDeletedPaths.json b/sdk/storage/azure-storage-files-datalake/test/ut/recordings/DataLakeFileSystemClientTest.ListDeletedPaths.json index b0764dbbd4..46c74e008c 100644 --- a/sdk/storage/azure-storage-files-datalake/test/ut/recordings/DataLakeFileSystemClientTest.ListDeletedPaths.json +++ b/sdk/storage/azure-storage-files-datalake/test/ut/recordings/DataLakeFileSystemClientTest.ListDeletedPaths.json @@ -2,8 +2,8 @@ "networkCallRecords": [ { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "4852b7d9-3925-4652-42b3-dae71445ca10", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "ae1c179c-f60d-4cfa-7ee6-4211cb5b14fb", "x-ms-version": "2021-04-10" }, "Method": "PUT", @@ -12,20 +12,20 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:07 GMT", - "etag": "\"0x8DAA0348687215F\"", - "last-modified": "Tue, 27 Sep 2022 03:01:08 GMT", + "date": "Fri, 30 Sep 2022 04:06:46 GMT", + "etag": "\"0x8DAA29930EBE686\"", + "last-modified": "Fri, 30 Sep 2022 04:06:46 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "4852b7d9-3925-4652-42b3-dae71445ca10", - "x-ms-request-id": "3803bf63-901e-0084-381d-d2a0ae000000", + "x-ms-client-request-id": "ae1c179c-f60d-4cfa-7ee6-4211cb5b14fb", + "x-ms-request-id": "e1a25879-c01e-006b-6882-d4ca54000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestlistdeletedpaths?restype=container" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "9597f3b2-8051-4fae-7a42-af04abd14058", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "5abbe163-4ec2-4284-4af6-0e3986060637", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -34,12 +34,12 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:09 GMT", - "etag": "\"0x8DAA03487668E60\"", - "last-modified": "Tue, 27 Sep 2022 03:01:09 GMT", + "date": "Fri, 30 Sep 2022 04:06:46 GMT", + "etag": "\"0x8DAA299319ADFD0\"", + "last-modified": "Fri, 30 Sep 2022 04:06:47 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "9597f3b2-8051-4fae-7a42-af04abd14058", - "x-ms-request-id": "4c4b6f94-201f-0028-7d1d-d2b307000000", + "x-ms-client-request-id": "5abbe163-4ec2-4284-4af6-0e3986060637", + "x-ms-request-id": "ccc23cb1-c01f-0044-6982-d4c79f000000", "x-ms-request-server-encrypted": "true", "x-ms-version": "2021-06-08" }, @@ -47,8 +47,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "283a24d9-c672-4a35-469d-38c6ddff5a3a", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "5e5dcadb-a8c2-4a8b-71c4-00aff8353e70", "x-ms-version": "2021-06-08" }, "Method": "DELETE", @@ -57,20 +57,20 @@ "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:10 GMT", + "date": "Fri, 30 Sep 2022 04:06:47 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "283a24d9-c672-4a35-469d-38c6ddff5a3a", + "x-ms-client-request-id": "5e5dcadb-a8c2-4a8b-71c4-00aff8353e70", "x-ms-delete-type-permanent": "false", - "x-ms-deletion-id": "133087212699969504", - "x-ms-request-id": "4c4b6faf-201f-0028-181d-d2b307000000", + "x-ms-deletion-id": "133089844075641417", + "x-ms-request-id": "ccc23cb2-c01f-0044-6a82-d4c79f000000", "x-ms-version": "2021-06-08" }, "Url": "https://REDACTED.dfs.core.windows.net/datalakefilesystemclienttestlistdeletedpaths/listdeletedpaths_file_deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "fd92820d-a84c-4005-553c-236f35238574", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "78174ae7-0e3f-49da-7b05-f7fe55bed0be", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -79,12 +79,12 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:10 GMT", - "etag": "\"0x8DAA03487DB1A28\"", - "last-modified": "Tue, 27 Sep 2022 03:01:10 GMT", + "date": "Fri, 30 Sep 2022 04:06:47 GMT", + "etag": "\"0x8DAA299322B164B\"", + "last-modified": "Fri, 30 Sep 2022 04:06:48 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "fd92820d-a84c-4005-553c-236f35238574", - "x-ms-request-id": "4c4b6fd9-201f-0028-421d-d2b307000000", + "x-ms-client-request-id": "78174ae7-0e3f-49da-7b05-f7fe55bed0be", + "x-ms-request-id": "ccc23cb3-c01f-0044-6b82-d4c79f000000", "x-ms-request-server-encrypted": "true", "x-ms-version": "2021-06-08" }, @@ -92,8 +92,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "98d837bb-2268-465e-5f0d-dd46d60a6ee6", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "5e435d6e-2eac-4f5a-6774-0fe95e5cacbe", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -102,12 +102,12 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:10 GMT", - "etag": "\"0x8DAA0348811B4A5\"", - "last-modified": "Tue, 27 Sep 2022 03:01:10 GMT", + "date": "Fri, 30 Sep 2022 04:06:47 GMT", + "etag": "\"0x8DAA29932567B73\"", + "last-modified": "Fri, 30 Sep 2022 04:06:48 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "98d837bb-2268-465e-5f0d-dd46d60a6ee6", - "x-ms-request-id": "4c4b6ffb-201f-0028-631d-d2b307000000", + "x-ms-client-request-id": "5e435d6e-2eac-4f5a-6774-0fe95e5cacbe", + "x-ms-request-id": "ccc23cb5-c01f-0044-6c82-d4c79f000000", "x-ms-request-server-encrypted": "true", "x-ms-version": "2021-06-08" }, @@ -115,8 +115,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "3b879536-f06b-4e70-4d1f-fa955c686651", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "3d37954b-d3c8-4ba9-7309-c1865d827811", "x-ms-version": "2021-06-08" }, "Method": "DELETE", @@ -125,20 +125,20 @@ "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:11 GMT", + "date": "Fri, 30 Sep 2022 04:06:48 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "3b879536-f06b-4e70-4d1f-fa955c686651", + "x-ms-client-request-id": "3d37954b-d3c8-4ba9-7309-c1865d827811", "x-ms-delete-type-permanent": "false", - "x-ms-deletion-id": "133087212712013186", - "x-ms-request-id": "4c4b7029-201f-0028-111d-d2b307000000", + "x-ms-deletion-id": "133089844087422656", + "x-ms-request-id": "ccc23cb6-c01f-0044-6d82-d4c79f000000", "x-ms-version": "2021-06-08" }, "Url": "https://REDACTED.dfs.core.windows.net/datalakefilesystemclienttestlistdeletedpaths/listdeletedpaths_dir_deleted?recursive=false" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "b1485ff3-9018-4e1d-7612-d7c6361391a2", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "3ed2d8f1-e3df-4b37-6a70-806d6e454181", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -147,12 +147,12 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:11 GMT", - "etag": "\"0x8DAA03488877376\"", - "last-modified": "Tue, 27 Sep 2022 03:01:11 GMT", + "date": "Fri, 30 Sep 2022 04:06:48 GMT", + "etag": "\"0x8DAA29932B39091\"", + "last-modified": "Fri, 30 Sep 2022 04:06:49 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "b1485ff3-9018-4e1d-7612-d7c6361391a2", - "x-ms-request-id": "4c4b704a-201f-0028-321d-d2b307000000", + "x-ms-client-request-id": "3ed2d8f1-e3df-4b37-6a70-806d6e454181", + "x-ms-request-id": "ccc23cb7-c01f-0044-6e82-d4c79f000000", "x-ms-request-server-encrypted": "true", "x-ms-version": "2021-06-08" }, @@ -160,71 +160,71 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "01922a3c-dfe2-444c-4ebe-35b4180305dd", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "0939ea9d-f230-4025-4b28-18ee2e9cf910", "x-ms-version": "2021-04-10" }, "Method": "GET", "Response": { - "BODY": "listdeletedpaths_dir_deleted133087212712013186trueTue, 27 Sep 2022 03:01:10 GMTTue, 27 Sep 2022 03:01:10 GMTTue, 04 Oct 2022 03:01:11 GMT0x8DAA0348811B4A5directory0application/octet-streamAAAAAAAAAAA=BlockBlobHottruetrueTue, 27 Sep 2022 03:01:11 GMT6listdeletedpaths_file_deleted133087212699969504trueTue, 27 Sep 2022 03:01:09 GMTTue, 27 Sep 2022 03:01:09 GMTTue, 04 Oct 2022 03:01:09 GMT0x8DAA03487668E60file0application/octet-streamAAAAAAAAAAA=BlockBlobHottruetrueTue, 27 Sep 2022 03:01:09 GMT6", + "BODY": "listdeletedpaths_dir_deleted133089844087422656trueFri, 30 Sep 2022 04:06:48 GMTFri, 30 Sep 2022 04:06:48 GMTFri, 07 Oct 2022 04:06:48 GMT0x8DAA29932567B73directory0application/octet-streamAAAAAAAAAAA=Fri, 30 Sep 2022 04:06:48 GMTBlockBlobHottruetrueFri, 30 Sep 2022 04:06:48 GMT6listdeletedpaths_file_deleted133089844075641417trueFri, 30 Sep 2022 04:06:47 GMTFri, 30 Sep 2022 04:06:47 GMTFri, 07 Oct 2022 04:06:47 GMT0x8DAA299319ADFD0file0application/octet-streamAAAAAAAAAAA=Fri, 30 Sep 2022 04:06:47 GMTBlockBlobHottruetrueFri, 30 Sep 2022 04:06:47 GMT6", "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-type": "application/xml", - "date": "Tue, 27 Sep 2022 03:01:11 GMT", + "date": "Fri, 30 Sep 2022 04:06:49 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "01922a3c-dfe2-444c-4ebe-35b4180305dd", - "x-ms-request-id": "3803c98a-901e-0084-781d-d2a0ae000000", + "x-ms-client-request-id": "0939ea9d-f230-4025-4b28-18ee2e9cf910", + "x-ms-request-id": "e1a25962-c01e-006b-1a82-d4ca54000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestlistdeletedpaths?comp=list&restype=container&showonly=deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "a4a99895-6c61-4928-6900-ab38c0040236", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "718731ad-6b6e-43a9-449d-cb937a0e611c", "x-ms-version": "2021-04-10" }, "Method": "GET", "Response": { - "BODY": "1listdeletedpaths_dir_deleted133087212712013186trueTue, 27 Sep 2022 03:01:10 GMTTue, 27 Sep 2022 03:01:10 GMTTue, 04 Oct 2022 03:01:11 GMT0x8DAA0348811B4A5directory0application/octet-streamAAAAAAAAAAA=BlockBlobHottruetrueTue, 27 Sep 2022 03:01:11 GMT62!384!MDAwMjQ0IVZCYjYrSnordTlTSjVQd0JHS2NCR0tFQkwzcGphR0Z1WjJSaGRHRnNZV3RsQVRBeFJEaENNRGd6TlVGR016VkdOak12SkhSeVlYTm9MMlJoZEdGc1lXdGxabWxzWlhONWMzUmxiV05zYVdWdWRIUmxjM1JzYVhOMFpHVnNaWFJsWkhCaGRHaHpBVEF4UkRoRU1qRkVOalF4TUVKQ1F6VUNMMnhwYzNSa1pXeGxkR1ZrY0dGMGFITmZabWxzWlY5a1pXeGxkR1ZrQVRJd01qSXRNRGt0TWpkVU1ETTZNREU2TURrdU9UazJPVFV3TkZvV0FBQUEhMDAwMDI4ITIwMjItMDktMjdUMDM6MDE6MTIuMTU4MDU1Mloh", + "BODY": "1listdeletedpaths_dir_deleted133089844087422656trueFri, 30 Sep 2022 04:06:48 GMTFri, 30 Sep 2022 04:06:48 GMTFri, 07 Oct 2022 04:06:48 GMT0x8DAA29932567B73directory0application/octet-streamAAAAAAAAAAA=Fri, 30 Sep 2022 04:06:48 GMTBlockBlobHottruetrueFri, 30 Sep 2022 04:06:48 GMT62!380!MDAwMjQwIVZCYXl2Y2ZwL0l2S3VIWVlwUUVZbndFdlpHRjBZV3hoYTJWbGRXRndBVEF4UkRZNFFUVTRRakJCUWtSQk9VSXZKSFJ5WVhOb0wyUmhkR0ZzWVd0bFptbHNaWE41YzNSbGJXTnNhV1Z1ZEhSbGMzUnNhWE4wWkdWc1pYUmxaSEJoZEdoekFUQXhSRGhFTkRneU1FVTNOVFUyUWtZQ0wyeHBjM1JrWld4bGRHVmtjR0YwYUhOZlptbHNaVjlrWld4bGRHVmtBVEl3TWpJdE1Ea3RNekJVTURRNk1EWTZORGN1TlRZME1UUXhOMW9XQUFBQSEwMDAwMjghMjAyMi0wOS0zMFQwNDowNjo0OS45OTQ2NTMxWiE-", "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-type": "application/xml", - "date": "Tue, 27 Sep 2022 03:01:11 GMT", + "date": "Fri, 30 Sep 2022 04:06:49 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "a4a99895-6c61-4928-6900-ab38c0040236", - "x-ms-request-id": "3803c9fc-901e-0084-5c1d-d2a0ae000000", + "x-ms-client-request-id": "718731ad-6b6e-43a9-449d-cb937a0e611c", + "x-ms-request-id": "e1a25995-c01e-006b-4882-d4ca54000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestlistdeletedpaths?comp=list&maxresults=1&restype=container&showonly=deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "ee16b368-7738-415c-436f-f0c892a836d7", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "eca1b38a-1317-4637-5332-75911481b034", "x-ms-version": "2021-04-10" }, "Method": "GET", "Response": { - "BODY": "2!384!MDAwMjQ0IVZCYjYrSnordTlTSjVQd0JHS2NCR0tFQkwzcGphR0Z1WjJSaGRHRnNZV3RsQVRBeFJEaENNRGd6TlVGR016VkdOak12SkhSeVlYTm9MMlJoZEdGc1lXdGxabWxzWlhONWMzUmxiV05zYVdWdWRIUmxjM1JzYVhOMFpHVnNaWFJsWkhCaGRHaHpBVEF4UkRoRU1qRkVOalF4TUVKQ1F6VUNMMnhwYzNSa1pXeGxkR1ZrY0dGMGFITmZabWxzWlY5a1pXeGxkR1ZrQVRJd01qSXRNRGt0TWpkVU1ETTZNREU2TURrdU9UazJPVFV3TkZvV0FBQUEhMDAwMDI4ITIwMjItMDktMjdUMDM6MDE6MTIuMTU4MDU1Mloh1listdeletedpaths_file_deleted133087212699969504trueTue, 27 Sep 2022 03:01:09 GMTTue, 27 Sep 2022 03:01:09 GMTTue, 04 Oct 2022 03:01:09 GMT0x8DAA03487668E60file0application/octet-streamAAAAAAAAAAA=BlockBlobHottruetrueTue, 27 Sep 2022 03:01:09 GMT6", + "BODY": "2!380!MDAwMjQwIVZCYXl2Y2ZwL0l2S3VIWVlwUUVZbndFdlpHRjBZV3hoYTJWbGRXRndBVEF4UkRZNFFUVTRRakJCUWtSQk9VSXZKSFJ5WVhOb0wyUmhkR0ZzWVd0bFptbHNaWE41YzNSbGJXTnNhV1Z1ZEhSbGMzUnNhWE4wWkdWc1pYUmxaSEJoZEdoekFUQXhSRGhFTkRneU1FVTNOVFUyUWtZQ0wyeHBjM1JrWld4bGRHVmtjR0YwYUhOZlptbHNaVjlrWld4bGRHVmtBVEl3TWpJdE1Ea3RNekJVTURRNk1EWTZORGN1TlRZME1UUXhOMW9XQUFBQSEwMDAwMjghMjAyMi0wOS0zMFQwNDowNjo0OS45OTQ2NTMxWiE-1listdeletedpaths_file_deleted133089844075641417trueFri, 30 Sep 2022 04:06:47 GMTFri, 30 Sep 2022 04:06:47 GMTFri, 07 Oct 2022 04:06:47 GMT0x8DAA299319ADFD0file0application/octet-streamAAAAAAAAAAA=Fri, 30 Sep 2022 04:06:47 GMTBlockBlobHottruetrueFri, 30 Sep 2022 04:06:47 GMT6", "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-type": "application/xml", - "date": "Tue, 27 Sep 2022 03:01:11 GMT", + "date": "Fri, 30 Sep 2022 04:06:50 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "ee16b368-7738-415c-436f-f0c892a836d7", - "x-ms-request-id": "3803ca64-901e-0084-391d-d2a0ae000000", + "x-ms-client-request-id": "eca1b38a-1317-4637-5332-75911481b034", + "x-ms-request-id": "e1a259b9-c01e-006b-6682-d4ca54000000", "x-ms-version": "2021-04-10" }, - "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestlistdeletedpaths?comp=list&marker=2!384!MDAwMjQ0IVZCYjYrSnordTlTSjVQd0JHS2NCR0tFQkwzcGphR0Z1WjJSaGRHRnNZV3RsQVRBeFJEaENNRGd6TlVGR016VkdOak12SkhSeVlYTm9MMlJoZEdGc1lXdGxabWxzWlhONWMzUmxiV05zYVdWdWRIUmxjM1JzYVhOMFpHVnNaWFJsWkhCaGRHaHpBVEF4UkRoRU1qRkVOalF4TUVKQ1F6VUNMMnhwYzNSa1pXeGxkR1ZrY0dGMGFITmZabWxzWlY5a1pXeGxkR1ZrQVRJd01qSXRNRGt0TWpkVU1ETTZNREU2TURrdU9UazJPVFV3TkZvV0FBQUEhMDAwMDI4ITIwMjItMDktMjdUMDM6MDE6MTIuMTU4MDU1Mloh&maxresults=1&restype=container&showonly=deleted" + "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestlistdeletedpaths?comp=list&marker=2!380!MDAwMjQwIVZCYXl2Y2ZwL0l2S3VIWVlwUUVZbndFdlpHRjBZV3hoYTJWbGRXRndBVEF4UkRZNFFUVTRRakJCUWtSQk9VSXZKSFJ5WVhOb0wyUmhkR0ZzWVd0bFptbHNaWE41YzNSbGJXTnNhV1Z1ZEhSbGMzUnNhWE4wWkdWc1pYUmxaSEJoZEdoekFUQXhSRGhFTkRneU1FVTNOVFUyUWtZQ0wyeHBjM1JrWld4bGRHVmtjR0YwYUhOZlptbHNaVjlrWld4bGRHVmtBVEl3TWpJdE1Ea3RNekJVTURRNk1EWTZORGN1TlRZME1UUXhOMW9XQUFBQSEwMDAwMjghMjAyMi0wOS0zMFQwNDowNjo0OS45OTQ2NTMxWiE-&maxresults=1&restype=container&showonly=deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "b4b269ee-68df-4159-6b2f-dee9c01573ab", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "b7f549de-e036-4348-76e9-509a29857acd", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -233,12 +233,12 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:12 GMT", - "etag": "\"0x8DAA034893E6CF7\"", - "last-modified": "Tue, 27 Sep 2022 03:01:12 GMT", + "date": "Fri, 30 Sep 2022 04:06:49 GMT", + "etag": "\"0x8DAA2993398805E\"", + "last-modified": "Fri, 30 Sep 2022 04:06:50 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "b4b269ee-68df-4159-6b2f-dee9c01573ab", - "x-ms-request-id": "4c4b7097-201f-0028-7f1d-d2b307000000", + "x-ms-client-request-id": "b7f549de-e036-4348-76e9-509a29857acd", + "x-ms-request-id": "ccc23cb8-c01f-0044-6f82-d4c79f000000", "x-ms-request-server-encrypted": "true", "x-ms-version": "2021-06-08" }, @@ -246,8 +246,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "6a1ff000-459b-4d1d-7692-e02752422968", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "623949fc-dabb-4256-6f23-9e5277306532", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -256,12 +256,12 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:13 GMT", - "etag": "\"0x8DAA034896F65DB\"", - "last-modified": "Tue, 27 Sep 2022 03:01:13 GMT", + "date": "Fri, 30 Sep 2022 04:06:50 GMT", + "etag": "\"0x8DAA29933CAB1F3\"", + "last-modified": "Fri, 30 Sep 2022 04:06:50 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "6a1ff000-459b-4d1d-7692-e02752422968", - "x-ms-request-id": "4c4b70b7-201f-0028-1f1d-d2b307000000", + "x-ms-client-request-id": "623949fc-dabb-4256-6f23-9e5277306532", + "x-ms-request-id": "ccc23cb9-c01f-0044-7082-d4c79f000000", "x-ms-request-server-encrypted": "true", "x-ms-version": "2021-06-08" }, @@ -269,8 +269,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "46f874e5-552f-4866-564e-ad35c1f89ffb", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "971829e4-083f-44b3-42a4-1b0b2fbc7e21", "x-ms-version": "2021-06-08" }, "Method": "DELETE", @@ -279,41 +279,41 @@ "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:13 GMT", + "date": "Fri, 30 Sep 2022 04:06:50 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "46f874e5-552f-4866-564e-ad35c1f89ffb", + "x-ms-client-request-id": "971829e4-083f-44b3-42a4-1b0b2fbc7e21", "x-ms-delete-type-permanent": "false", - "x-ms-deletion-id": "133087212735027045", - "x-ms-request-id": "4c4b70d2-201f-0028-3a1d-d2b307000000", + "x-ms-deletion-id": "133089844112053054", + "x-ms-request-id": "ccc23cbb-c01f-0044-7182-d4c79f000000", "x-ms-version": "2021-06-08" }, "Url": "https://REDACTED.dfs.core.windows.net/datalakefilesystemclienttestlistdeletedpaths/listdeletedpaths_prefix/file" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "fe187a16-e3e7-4992-5fd9-57cde493b940", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "0dd3fb50-fc9b-40f6-4b86-3631adf3f744", "x-ms-version": "2021-04-10" }, "Method": "GET", "Response": { - "BODY": "listdeletedpaths_prefixlistdeletedpaths_prefix/file133087212735027045trueTue, 27 Sep 2022 03:01:13 GMTTue, 27 Sep 2022 03:01:13 GMTTue, 04 Oct 2022 03:01:13 GMT0x8DAA034896F65DBfile0application/octet-streamAAAAAAAAAAA=BlockBlobHottruetrueTue, 27 Sep 2022 03:01:13 GMT6", + "BODY": "listdeletedpaths_prefixlistdeletedpaths_prefix/file133089844112053054trueFri, 30 Sep 2022 04:06:50 GMTFri, 30 Sep 2022 04:06:50 GMTFri, 07 Oct 2022 04:06:51 GMT0x8DAA29933CAB1F3file0application/octet-streamAAAAAAAAAAA=Fri, 30 Sep 2022 04:06:50 GMTBlockBlobHottruetrueFri, 30 Sep 2022 04:06:51 GMT6", "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-type": "application/xml", - "date": "Tue, 27 Sep 2022 03:01:13 GMT", + "date": "Fri, 30 Sep 2022 04:06:51 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "fe187a16-e3e7-4992-5fd9-57cde493b940", - "x-ms-request-id": "3803cce8-901e-0084-031d-d2a0ae000000", + "x-ms-client-request-id": "0dd3fb50-fc9b-40f6-4b86-3631adf3f744", + "x-ms-request-id": "e1a25a25-c01e-006b-4482-d4ca54000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestlistdeletedpaths?comp=list&prefix=listdeletedpaths_prefix&restype=container&showonly=deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "449930df-a9cb-44a9-5ad9-59eb4cca1288", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "d30ed1e8-0161-4e94-4723-319f31a8f400", "x-ms-version": "2021-04-10" }, "Method": "DELETE", @@ -322,10 +322,10 @@ "REASON_PHRASE": "Accepted", "STATUS_CODE": "202", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:13 GMT", + "date": "Fri, 30 Sep 2022 04:06:51 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "449930df-a9cb-44a9-5ad9-59eb4cca1288", - "x-ms-request-id": "3803cd63-901e-0084-721d-d2a0ae000000", + "x-ms-client-request-id": "d30ed1e8-0161-4e94-4723-319f31a8f400", + "x-ms-request-id": "e1a25a35-c01e-006b-5382-d4ca54000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestlistdeletedpaths?restype=container" diff --git a/sdk/storage/azure-storage-files-datalake/test/ut/recordings/DataLakeFileSystemClientTest.Undelete.json b/sdk/storage/azure-storage-files-datalake/test/ut/recordings/DataLakeFileSystemClientTest.Undelete.json index bdb126a06b..749d89d0fb 100644 --- a/sdk/storage/azure-storage-files-datalake/test/ut/recordings/DataLakeFileSystemClientTest.Undelete.json +++ b/sdk/storage/azure-storage-files-datalake/test/ut/recordings/DataLakeFileSystemClientTest.Undelete.json @@ -2,8 +2,8 @@ "networkCallRecords": [ { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "f268529f-3a61-4d97-7a8b-87c1bf7722d6", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "28517d6b-4d66-42ea-5d98-cacc97633cc0", "x-ms-version": "2021-04-10" }, "Method": "PUT", @@ -12,20 +12,20 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:13 GMT", - "etag": "\"0x8DAA0348A4720C7\"", - "last-modified": "Tue, 27 Sep 2022 03:01:14 GMT", + "date": "Fri, 30 Sep 2022 04:07:24 GMT", + "etag": "\"0x8DAA299483F4F81\"", + "last-modified": "Fri, 30 Sep 2022 04:07:25 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "f268529f-3a61-4d97-7a8b-87c1bf7722d6", - "x-ms-request-id": "3803ce00-901e-0084-7b1d-d2a0ae000000", + "x-ms-client-request-id": "28517d6b-4d66-42ea-5d98-cacc97633cc0", + "x-ms-request-id": "df2f7075-001e-0006-7982-d47e1f000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestundelete?restype=container" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "3ca3565f-4f12-453a-449e-d412b76ecc28", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "75f82534-40f4-4397-4547-50b9fa8e9370", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -34,12 +34,12 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:14 GMT", - "etag": "\"0x8DAA0348A7A8ACF\"", - "last-modified": "Tue, 27 Sep 2022 03:01:14 GMT", + "date": "Fri, 30 Sep 2022 04:07:26 GMT", + "etag": "\"0x8DAA29948C7AECF\"", + "last-modified": "Fri, 30 Sep 2022 04:07:26 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "3ca3565f-4f12-453a-449e-d412b76ecc28", - "x-ms-request-id": "4c4b714d-201f-0028-331d-d2b307000000", + "x-ms-client-request-id": "75f82534-40f4-4397-4547-50b9fa8e9370", + "x-ms-request-id": "ae8e04e6-201f-0063-1282-d4d05b000000", "x-ms-request-server-encrypted": "true", "x-ms-version": "2021-06-08" }, @@ -47,8 +47,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "80d7247b-af1e-4b67-5ae6-24dcbe1afdb8", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "0642893b-538d-474a-6390-32cbd406da53", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -57,12 +57,12 @@ "REASON_PHRASE": "Created", "STATUS_CODE": "201", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:15 GMT", - "etag": "\"0x8DAA0348AAE3164\"", - "last-modified": "Tue, 27 Sep 2022 03:01:15 GMT", + "date": "Fri, 30 Sep 2022 04:07:26 GMT", + "etag": "\"0x8DAA29948F66653\"", + "last-modified": "Fri, 30 Sep 2022 04:07:26 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "80d7247b-af1e-4b67-5ae6-24dcbe1afdb8", - "x-ms-request-id": "4c4b7165-201f-0028-4b1d-d2b307000000", + "x-ms-client-request-id": "0642893b-538d-474a-6390-32cbd406da53", + "x-ms-request-id": "ae8e04e7-201f-0063-1382-d4d05b000000", "x-ms-request-server-encrypted": "true", "x-ms-version": "2021-06-08" }, @@ -70,8 +70,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "6e0c849e-d03a-4470-7e93-230e9967aeb6", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "a39f6970-fd75-4b6b-7498-62d743c7a65e", "x-ms-version": "2021-04-10" }, "Method": "HEAD", @@ -82,22 +82,23 @@ "accept-ranges": "bytes", "content-length": "0", "content-type": "application/octet-stream", - "date": "Tue, 27 Sep 2022 03:01:14 GMT", - "etag": "\"0x8DAA0348A7A8ACF\"", - "last-modified": "Tue, 27 Sep 2022 03:01:14 GMT", + "date": "Fri, 30 Sep 2022 04:07:26 GMT", + "etag": "\"0x8DAA29948C7AECF\"", + "last-modified": "Fri, 30 Sep 2022 04:07:26 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "x-ms-access-tier": "Hot", "x-ms-access-tier-inferred": "true", "x-ms-blob-type": "BlockBlob", - "x-ms-client-request-id": "6e0c849e-d03a-4470-7e93-230e9967aeb6", - "x-ms-creation-time": "Tue, 27 Sep 2022 03:01:14 GMT", + "x-ms-client-request-id": "a39f6970-fd75-4b6b-7498-62d743c7a65e", + "x-ms-creation-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-group": "$superuser", + "x-ms-last-access-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-lease-state": "available", "x-ms-lease-status": "unlocked", "x-ms-meta-hdi_isfolder": "true", "x-ms-owner": "$superuser", "x-ms-permissions": "rwxr-x---", - "x-ms-request-id": "3803cf55-901e-0084-1c1d-d2a0ae000000", + "x-ms-request-id": "df2f713e-001e-0006-3082-d47e1f000000", "x-ms-resource-type": "directory", "x-ms-server-encrypted": "true", "x-ms-version": "2021-04-10" @@ -106,8 +107,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "c6d3db69-4932-4fbc-654b-d93773ce37ce", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "7206476c-561c-4d11-70ce-37dc32d4533c", "x-ms-version": "2021-04-10" }, "Method": "HEAD", @@ -118,21 +119,22 @@ "accept-ranges": "bytes", "content-length": "0", "content-type": "application/octet-stream", - "date": "Tue, 27 Sep 2022 03:01:14 GMT", - "etag": "\"0x8DAA0348AAE3164\"", - "last-modified": "Tue, 27 Sep 2022 03:01:15 GMT", + "date": "Fri, 30 Sep 2022 04:07:26 GMT", + "etag": "\"0x8DAA29948F66653\"", + "last-modified": "Fri, 30 Sep 2022 04:07:26 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "x-ms-access-tier": "Hot", "x-ms-access-tier-inferred": "true", "x-ms-blob-type": "BlockBlob", - "x-ms-client-request-id": "c6d3db69-4932-4fbc-654b-d93773ce37ce", - "x-ms-creation-time": "Tue, 27 Sep 2022 03:01:15 GMT", + "x-ms-client-request-id": "7206476c-561c-4d11-70ce-37dc32d4533c", + "x-ms-creation-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-group": "$superuser", + "x-ms-last-access-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-lease-state": "available", "x-ms-lease-status": "unlocked", "x-ms-owner": "$superuser", "x-ms-permissions": "rw-r-----", - "x-ms-request-id": "3803cfc8-901e-0084-051d-d2a0ae000000", + "x-ms-request-id": "df2f7169-001e-0006-5482-d47e1f000000", "x-ms-resource-type": "file", "x-ms-server-encrypted": "true", "x-ms-version": "2021-04-10" @@ -141,8 +143,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "9cf7aead-77ab-44ce-5b4f-64f8425e8e07", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "02097db5-4328-469c-5450-a4757a38b3e9", "x-ms-version": "2021-06-08" }, "Method": "DELETE", @@ -151,41 +153,41 @@ "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:16 GMT", + "date": "Fri, 30 Sep 2022 04:07:27 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "9cf7aead-77ab-44ce-5b4f-64f8425e8e07", + "x-ms-client-request-id": "02097db5-4328-469c-5450-a4757a38b3e9", "x-ms-delete-type-permanent": "false", - "x-ms-deletion-id": "133087212760750222", - "x-ms-request-id": "4c4b71b3-201f-0028-171d-d2b307000000", + "x-ms-deletion-id": "133089844473114648", + "x-ms-request-id": "ae8e04e9-201f-0063-1582-d4d05b000000", "x-ms-version": "2021-06-08" }, "Url": "https://REDACTED.dfs.core.windows.net/datalakefilesystemclienttestundelete/undelete_dir?recursive=true" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "d96f0fc6-feb6-49b1-4a05-077bc9370ee0", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "38f18c0c-0d71-44f5-42aa-b2c4eb9d773a", "x-ms-version": "2021-04-10" }, "Method": "GET", "Response": { - "BODY": "undelete_dir133087212760750222trueTue, 27 Sep 2022 03:01:14 GMTTue, 27 Sep 2022 03:01:14 GMTTue, 04 Oct 2022 03:01:16 GMT0x8DAA0348A7A8ACFdirectory0application/octet-streamAAAAAAAAAAA=BlockBlobHottruetrueTue, 27 Sep 2022 03:01:16 GMT6", + "BODY": "undelete_dir133089844473114648trueFri, 30 Sep 2022 04:07:26 GMTFri, 30 Sep 2022 04:07:26 GMTFri, 07 Oct 2022 04:07:27 GMT0x8DAA29948C7AECFdirectory0application/octet-streamAAAAAAAAAAA=Fri, 30 Sep 2022 04:07:26 GMTBlockBlobHottruetrueFri, 30 Sep 2022 04:07:27 GMT6", "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-type": "application/xml", - "date": "Tue, 27 Sep 2022 03:01:15 GMT", + "date": "Fri, 30 Sep 2022 04:07:27 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "d96f0fc6-feb6-49b1-4a05-077bc9370ee0", - "x-ms-request-id": "3803d1e4-901e-0084-591d-d2a0ae000000", + "x-ms-client-request-id": "38f18c0c-0d71-44f5-42aa-b2c4eb9d773a", + "x-ms-request-id": "df2f71b7-001e-0006-1c82-d47e1f000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestundelete?comp=list&restype=container&showonly=deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "f31e94c6-3605-4f8b-70c9-fb23b35f071a", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "34ad3dc4-a3eb-485c-4f10-32f672fbd4c1", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -194,11 +196,11 @@ "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:16 GMT", + "date": "Fri, 30 Sep 2022 04:07:28 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "f31e94c6-3605-4f8b-70c9-fb23b35f071a", - "x-ms-creation-time": "Tue, 27 Sep 2022 03:01:14 GMT", - "x-ms-request-id": "3803d270-901e-0084-581d-d2a0ae000000", + "x-ms-client-request-id": "34ad3dc4-a3eb-485c-4f10-32f672fbd4c1", + "x-ms-creation-time": "Fri, 30 Sep 2022 04:07:26 GMT", + "x-ms-request-id": "df2f71d0-001e-0006-3482-d47e1f000000", "x-ms-resource-type": "directory", "x-ms-version": "2021-06-08" }, @@ -206,29 +208,29 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "a5210b6f-e947-4216-7312-c8c1e02da4ec", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "e707d84a-0106-4d72-44de-f59dd8ac4281", "x-ms-version": "2021-04-10" }, "Method": "GET", "Response": { - "BODY": "", + "BODY": "", "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-type": "application/xml", - "date": "Tue, 27 Sep 2022 03:01:16 GMT", + "date": "Fri, 30 Sep 2022 04:07:28 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "a5210b6f-e947-4216-7312-c8c1e02da4ec", - "x-ms-request-id": "3803d370-901e-0084-3b1d-d2a0ae000000", + "x-ms-client-request-id": "e707d84a-0106-4d72-44de-f59dd8ac4281", + "x-ms-request-id": "df2f7223-001e-0006-7d82-d47e1f000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestundelete?comp=list&restype=container&showonly=deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "7a2a53d1-5a47-44af-65d8-1f5c9ceb07b8", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "47cb0282-6200-4a8d-4be0-8f6021a2919d", "x-ms-version": "2021-04-10" }, "Method": "HEAD", @@ -239,22 +241,23 @@ "accept-ranges": "bytes", "content-length": "0", "content-type": "application/octet-stream", - "date": "Tue, 27 Sep 2022 03:01:16 GMT", - "etag": "\"0x8DAA0348A7A8ACF\"", - "last-modified": "Tue, 27 Sep 2022 03:01:14 GMT", + "date": "Fri, 30 Sep 2022 04:07:28 GMT", + "etag": "\"0x8DAA29948C7AECF\"", + "last-modified": "Fri, 30 Sep 2022 04:07:26 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "x-ms-access-tier": "Hot", "x-ms-access-tier-inferred": "true", "x-ms-blob-type": "BlockBlob", - "x-ms-client-request-id": "7a2a53d1-5a47-44af-65d8-1f5c9ceb07b8", - "x-ms-creation-time": "Tue, 27 Sep 2022 03:01:14 GMT", + "x-ms-client-request-id": "47cb0282-6200-4a8d-4be0-8f6021a2919d", + "x-ms-creation-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-group": "$superuser", + "x-ms-last-access-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-lease-state": "available", "x-ms-lease-status": "unlocked", "x-ms-meta-hdi_isfolder": "true", "x-ms-owner": "$superuser", "x-ms-permissions": "rwxr-x---", - "x-ms-request-id": "3803d427-901e-0084-6b1d-d2a0ae000000", + "x-ms-request-id": "df2f727f-001e-0006-5682-d47e1f000000", "x-ms-resource-type": "directory", "x-ms-server-encrypted": "true", "x-ms-version": "2021-04-10" @@ -263,8 +266,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "6db9b566-c773-4f1c-623d-658776e8072e", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "11456486-fb15-4e31-566e-e42aa9eb40b5", "x-ms-version": "2021-04-10" }, "Method": "HEAD", @@ -275,21 +278,22 @@ "accept-ranges": "bytes", "content-length": "0", "content-type": "application/octet-stream", - "date": "Tue, 27 Sep 2022 03:01:17 GMT", - "etag": "\"0x8DAA0348AAE3164\"", - "last-modified": "Tue, 27 Sep 2022 03:01:15 GMT", + "date": "Fri, 30 Sep 2022 04:07:28 GMT", + "etag": "\"0x8DAA29948F66653\"", + "last-modified": "Fri, 30 Sep 2022 04:07:26 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "x-ms-access-tier": "Hot", "x-ms-access-tier-inferred": "true", "x-ms-blob-type": "BlockBlob", - "x-ms-client-request-id": "6db9b566-c773-4f1c-623d-658776e8072e", - "x-ms-creation-time": "Tue, 27 Sep 2022 03:01:15 GMT", + "x-ms-client-request-id": "11456486-fb15-4e31-566e-e42aa9eb40b5", + "x-ms-creation-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-group": "$superuser", + "x-ms-last-access-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-lease-state": "available", "x-ms-lease-status": "unlocked", "x-ms-owner": "$superuser", "x-ms-permissions": "rw-r-----", - "x-ms-request-id": "3803d4c8-901e-0084-7d1d-d2a0ae000000", + "x-ms-request-id": "df2f72a6-001e-0006-7282-d47e1f000000", "x-ms-resource-type": "file", "x-ms-server-encrypted": "true", "x-ms-version": "2021-04-10" @@ -298,8 +302,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "21dc66de-ddfe-448b-47ed-b27f94e8c077", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "deaa8a95-8237-4948-6b92-b81107c67d6f", "x-ms-version": "2021-06-08" }, "Method": "DELETE", @@ -308,20 +312,20 @@ "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:18 GMT", + "date": "Fri, 30 Sep 2022 04:07:29 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "21dc66de-ddfe-448b-47ed-b27f94e8c077", + "x-ms-client-request-id": "deaa8a95-8237-4948-6b92-b81107c67d6f", "x-ms-delete-type-permanent": "false", - "x-ms-deletion-id": "133087212781678638", - "x-ms-request-id": "4c4b727f-201f-0028-5e1d-d2b307000000", + "x-ms-deletion-id": "133089844495909870", + "x-ms-request-id": "ae8e04ea-201f-0063-1682-d4d05b000000", "x-ms-version": "2021-06-08" }, "Url": "https://REDACTED.dfs.core.windows.net/datalakefilesystemclienttestundelete/undelete_dir/sub_file" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "37df0b10-09dd-4cd4-5a36-b96ba299910a", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "7fa80279-fe0d-4d66-6e0e-efd656a9902f", "x-ms-version": "2021-06-08" }, "Method": "DELETE", @@ -330,41 +334,41 @@ "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:18 GMT", + "date": "Fri, 30 Sep 2022 04:07:29 GMT", "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "37df0b10-09dd-4cd4-5a36-b96ba299910a", + "x-ms-client-request-id": "7fa80279-fe0d-4d66-6e0e-efd656a9902f", "x-ms-delete-type-permanent": "false", - "x-ms-deletion-id": "133087212785510990", - "x-ms-request-id": "4c4b72b1-201f-0028-101d-d2b307000000", + "x-ms-deletion-id": "133089844499423591", + "x-ms-request-id": "ae8e04eb-201f-0063-1782-d4d05b000000", "x-ms-version": "2021-06-08" }, "Url": "https://REDACTED.dfs.core.windows.net/datalakefilesystemclienttestundelete/undelete_dir?recursive=false" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "2a834864-f79e-4b1a-6f9d-6e0d97aa73d2", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "2789eba2-7994-4c07-45bd-da572c152aa9", "x-ms-version": "2021-04-10" }, "Method": "GET", "Response": { - "BODY": "undelete_dir133087212785510990trueTue, 27 Sep 2022 03:01:14 GMTTue, 27 Sep 2022 03:01:14 GMTTue, 04 Oct 2022 03:01:18 GMT0x8DAA0348A7A8ACFdirectory0application/octet-streamAAAAAAAAAAA=BlockBlobHottruetrueTue, 27 Sep 2022 03:01:18 GMT6undelete_dir/sub_file133087212781678638trueTue, 27 Sep 2022 03:01:15 GMTTue, 27 Sep 2022 03:01:15 GMTTue, 04 Oct 2022 03:01:18 GMT0x8DAA0348AAE3164file0application/octet-streamAAAAAAAAAAA=BlockBlobHottruetrueTue, 27 Sep 2022 03:01:18 GMT6", + "BODY": "undelete_dir133089844499423591trueFri, 30 Sep 2022 04:07:26 GMTFri, 30 Sep 2022 04:07:26 GMTFri, 07 Oct 2022 04:07:29 GMT0x8DAA29948C7AECFdirectory0application/octet-streamAAAAAAAAAAA=Fri, 30 Sep 2022 04:07:26 GMTBlockBlobHottruetrueFri, 30 Sep 2022 04:07:29 GMT6undelete_dir/sub_file133089844495909870trueFri, 30 Sep 2022 04:07:26 GMTFri, 30 Sep 2022 04:07:26 GMTFri, 07 Oct 2022 04:07:29 GMT0x8DAA29948F66653file0application/octet-streamAAAAAAAAAAA=Fri, 30 Sep 2022 04:07:26 GMTBlockBlobHottruetrueFri, 30 Sep 2022 04:07:29 GMT6", "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-type": "application/xml", - "date": "Tue, 27 Sep 2022 03:01:18 GMT", + "date": "Fri, 30 Sep 2022 04:07:29 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "2a834864-f79e-4b1a-6f9d-6e0d97aa73d2", - "x-ms-request-id": "3803d788-901e-0084-101d-d2a0ae000000", + "x-ms-client-request-id": "2789eba2-7994-4c07-45bd-da572c152aa9", + "x-ms-request-id": "df2f7318-001e-0006-5582-d47e1f000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestundelete?comp=list&restype=container&showonly=deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "e4026214-e9d2-4954-7e54-e044c02c50f4", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "e6c75bc1-e754-434b-6ab9-91867e185fe5", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -373,11 +377,11 @@ "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:18 GMT", + "date": "Fri, 30 Sep 2022 04:07:30 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "e4026214-e9d2-4954-7e54-e044c02c50f4", - "x-ms-creation-time": "Tue, 27 Sep 2022 03:01:14 GMT", - "x-ms-request-id": "3803d86d-901e-0084-671d-d2a0ae000000", + "x-ms-client-request-id": "e6c75bc1-e754-434b-6ab9-91867e185fe5", + "x-ms-creation-time": "Fri, 30 Sep 2022 04:07:26 GMT", + "x-ms-request-id": "df2f734c-001e-0006-0382-d47e1f000000", "x-ms-resource-type": "directory", "x-ms-version": "2021-06-08" }, @@ -385,29 +389,29 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "1e70a5c5-5183-432f-7e26-4f833541d032", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "a3980582-cc36-490c-48b5-2a827cf032ff", "x-ms-version": "2021-04-10" }, "Method": "GET", "Response": { - "BODY": "undelete_dir/sub_file133087212781678638trueTue, 27 Sep 2022 03:01:15 GMTTue, 27 Sep 2022 03:01:15 GMTTue, 04 Oct 2022 03:01:18 GMT0x8DAA0348AAE3164file0application/octet-streamAAAAAAAAAAA=BlockBlobHottruetrueTue, 27 Sep 2022 03:01:18 GMT6", + "BODY": "undelete_dir/sub_file133089844495909870trueFri, 30 Sep 2022 04:07:26 GMTFri, 30 Sep 2022 04:07:26 GMTFri, 07 Oct 2022 04:07:29 GMT0x8DAA29948F66653file0application/octet-streamAAAAAAAAAAA=Fri, 30 Sep 2022 04:07:26 GMTBlockBlobHottruetrueFri, 30 Sep 2022 04:07:29 GMT6", "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-type": "application/xml", - "date": "Tue, 27 Sep 2022 03:01:18 GMT", + "date": "Fri, 30 Sep 2022 04:07:30 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "1e70a5c5-5183-432f-7e26-4f833541d032", - "x-ms-request-id": "3803d921-901e-0084-0d1d-d2a0ae000000", + "x-ms-client-request-id": "a3980582-cc36-490c-48b5-2a827cf032ff", + "x-ms-request-id": "df2f736e-001e-0006-2182-d47e1f000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestundelete?comp=list&restype=container&showonly=deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "012ef39d-9e4b-418e-7d34-0a6ec5334788", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "c4382b3f-7902-4843-61cf-ae263c5efa27", "x-ms-version": "2021-04-10" }, "Method": "HEAD", @@ -418,22 +422,23 @@ "accept-ranges": "bytes", "content-length": "0", "content-type": "application/octet-stream", - "date": "Tue, 27 Sep 2022 03:01:19 GMT", - "etag": "\"0x8DAA0348A7A8ACF\"", - "last-modified": "Tue, 27 Sep 2022 03:01:14 GMT", + "date": "Fri, 30 Sep 2022 04:07:31 GMT", + "etag": "\"0x8DAA29948C7AECF\"", + "last-modified": "Fri, 30 Sep 2022 04:07:26 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "x-ms-access-tier": "Hot", "x-ms-access-tier-inferred": "true", "x-ms-blob-type": "BlockBlob", - "x-ms-client-request-id": "012ef39d-9e4b-418e-7d34-0a6ec5334788", - "x-ms-creation-time": "Tue, 27 Sep 2022 03:01:14 GMT", + "x-ms-client-request-id": "c4382b3f-7902-4843-61cf-ae263c5efa27", + "x-ms-creation-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-group": "$superuser", + "x-ms-last-access-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-lease-state": "available", "x-ms-lease-status": "unlocked", "x-ms-meta-hdi_isfolder": "true", "x-ms-owner": "$superuser", "x-ms-permissions": "rwxr-x---", - "x-ms-request-id": "3803d9c6-901e-0084-281d-d2a0ae000000", + "x-ms-request-id": "df2f739d-001e-0006-3b82-d47e1f000000", "x-ms-resource-type": "directory", "x-ms-server-encrypted": "true", "x-ms-version": "2021-04-10" @@ -442,8 +447,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "061ab627-ac84-4754-78d7-b4e2b7d11f70", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "fde34872-0860-4b4c-640e-1216dff59bc4", "x-ms-version": "2021-04-10" }, "Method": "HEAD", @@ -451,20 +456,20 @@ "BODY": "", "REASON_PHRASE": "The specified blob does not exist.", "STATUS_CODE": "404", - "date": "Tue, 27 Sep 2022 03:01:19 GMT", + "date": "Fri, 30 Sep 2022 04:07:31 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "061ab627-ac84-4754-78d7-b4e2b7d11f70", + "x-ms-client-request-id": "fde34872-0860-4b4c-640e-1216dff59bc4", "x-ms-error-code": "BlobNotFound", - "x-ms-request-id": "3803da20-901e-0084-7c1d-d2a0ae000000", + "x-ms-request-id": "df2f73c6-001e-0006-5982-d47e1f000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestundelete/undelete_dir/sub_file" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "8655ee98-73bc-4597-63af-a1f5548ac3f9", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "f68c25f4-caf6-4330-72db-6de69be48cd3", "x-ms-version": "2021-06-08" }, "Method": "PUT", @@ -473,11 +478,11 @@ "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:21 GMT", + "date": "Fri, 30 Sep 2022 04:07:31 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "8655ee98-73bc-4597-63af-a1f5548ac3f9", - "x-ms-creation-time": "Tue, 27 Sep 2022 03:01:15 GMT", - "x-ms-request-id": "03af34b7-601e-0080-121d-d22da9000000", + "x-ms-client-request-id": "f68c25f4-caf6-4330-72db-6de69be48cd3", + "x-ms-creation-time": "Fri, 30 Sep 2022 04:07:26 GMT", + "x-ms-request-id": "df2f73ea-001e-0006-7582-d47e1f000000", "x-ms-resource-type": "file", "x-ms-version": "2021-06-08" }, @@ -485,29 +490,29 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "f8ccabc0-3e10-499c-4c2c-bce7860b0aae", + "user-agent": "azsdk-cpp-storage-files-datalake/12.4.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "bd8aae06-3b77-449f-4a95-e8900592b7e3", "x-ms-version": "2021-04-10" }, "Method": "GET", "Response": { - "BODY": "", + "BODY": "", "REASON_PHRASE": "OK", "STATUS_CODE": "200", "content-type": "application/xml", - "date": "Tue, 27 Sep 2022 03:01:21 GMT", + "date": "Fri, 30 Sep 2022 04:07:31 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "transfer-encoding": "chunked", - "x-ms-client-request-id": "f8ccabc0-3e10-499c-4c2c-bce7860b0aae", - "x-ms-request-id": "03af374d-601e-0080-691d-d22da9000000", + "x-ms-client-request-id": "bd8aae06-3b77-449f-4a95-e8900592b7e3", + "x-ms-request-id": "df2f7411-001e-0006-1982-d47e1f000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestundelete?comp=list&restype=container&showonly=deleted" }, { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "5455eddc-71a6-4548-4a9a-519a0e0f0723", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "7e4fb6b0-158b-4650-7ab8-b231dfef3816", "x-ms-version": "2021-04-10" }, "Method": "HEAD", @@ -518,21 +523,22 @@ "accept-ranges": "bytes", "content-length": "0", "content-type": "application/octet-stream", - "date": "Tue, 27 Sep 2022 03:01:21 GMT", - "etag": "\"0x8DAA0348AAE3164\"", - "last-modified": "Tue, 27 Sep 2022 03:01:15 GMT", + "date": "Fri, 30 Sep 2022 04:07:32 GMT", + "etag": "\"0x8DAA29948F66653\"", + "last-modified": "Fri, 30 Sep 2022 04:07:26 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", "x-ms-access-tier": "Hot", "x-ms-access-tier-inferred": "true", "x-ms-blob-type": "BlockBlob", - "x-ms-client-request-id": "5455eddc-71a6-4548-4a9a-519a0e0f0723", - "x-ms-creation-time": "Tue, 27 Sep 2022 03:01:15 GMT", + "x-ms-client-request-id": "7e4fb6b0-158b-4650-7ab8-b231dfef3816", + "x-ms-creation-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-group": "$superuser", + "x-ms-last-access-time": "Fri, 30 Sep 2022 04:07:26 GMT", "x-ms-lease-state": "available", "x-ms-lease-status": "unlocked", "x-ms-owner": "$superuser", "x-ms-permissions": "rw-r-----", - "x-ms-request-id": "03af3852-601e-0080-451d-d22da9000000", + "x-ms-request-id": "df2f742a-001e-0006-3282-d47e1f000000", "x-ms-resource-type": "file", "x-ms-server-encrypted": "true", "x-ms-version": "2021-04-10" @@ -541,8 +547,8 @@ }, { "Headers": { - "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 22000 22000.1.amd64fre.co_release.210604-1628)", - "x-ms-client-request-id": "77c75e1a-136c-4119-7de7-70a21e03e300", + "user-agent": "azsdk-cpp-storage-blobs/12.7.0-beta.1 (Windows 10 Enterprise 6.3 19044 19041.1.amd64fre.vb_release.191206-1406)", + "x-ms-client-request-id": "a0309d3c-30e5-407d-6e03-1b346fc9ec0b", "x-ms-version": "2021-04-10" }, "Method": "DELETE", @@ -551,10 +557,10 @@ "REASON_PHRASE": "Accepted", "STATUS_CODE": "202", "content-length": "0", - "date": "Tue, 27 Sep 2022 03:01:22 GMT", + "date": "Fri, 30 Sep 2022 04:07:32 GMT", "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-client-request-id": "77c75e1a-136c-4119-7de7-70a21e03e300", - "x-ms-request-id": "03af390f-601e-0080-691d-d22da9000000", + "x-ms-client-request-id": "a0309d3c-30e5-407d-6e03-1b346fc9ec0b", + "x-ms-request-id": "df2f7448-001e-0006-4e82-d47e1f000000", "x-ms-version": "2021-04-10" }, "Url": "https://REDACTED.blob.core.windows.net/datalakefilesystemclienttestundelete?restype=container" diff --git a/sdk/storage/azure-storage-files-datalake/vcpkg.json b/sdk/storage/azure-storage-files-datalake/vcpkg.json index fff483c127..d745ab4e8d 100644 --- a/sdk/storage/azure-storage-files-datalake/vcpkg.json +++ b/sdk/storage/azure-storage-files-datalake/vcpkg.json @@ -1,6 +1,6 @@ { "name": "azure-storage-files-datalake-cpp", - "version-semver": "12.3.1", + "version-semver": "12.4.0-beta.1", "description": [ "Microsoft Azure Storage Files Data Lake SDK for C++", "This library provides Azure Storage Files Data Lake SDK." diff --git a/sdk/storage/azure-storage-files-shares/CHANGELOG.md b/sdk/storage/azure-storage-files-shares/CHANGELOG.md index dd7a4f26f6..2cc4ee569a 100644 --- a/sdk/storage/azure-storage-files-shares/CHANGELOG.md +++ b/sdk/storage/azure-storage-files-shares/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 12.3.0-beta.2 (Unreleased) +## 12.4.0-beta.1 (Unreleased) ### Features Added @@ -10,6 +10,12 @@ ### Other Changes +## 12.3.0 (2022-10-11) + +### Features Added + +- New features in `12.3.0-beta.1` are now generally available. + ## 12.3.0-beta.1 (2022-09-06) ### Features Added 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 f6b599c768..9508bdd691 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 @@ -9,7 +9,7 @@ #pragma once #define AZURE_STORAGE_FILES_SHARES_VERSION_MAJOR 12 -#define AZURE_STORAGE_FILES_SHARES_VERSION_MINOR 3 +#define AZURE_STORAGE_FILES_SHARES_VERSION_MINOR 4 #define AZURE_STORAGE_FILES_SHARES_VERSION_PATCH 0 #define AZURE_STORAGE_FILES_SHARES_VERSION_PRERELEASE "beta.2" @@ -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-files-shares/vcpkg.json b/sdk/storage/azure-storage-files-shares/vcpkg.json index bbfaff5bf9..be57f18fcd 100644 --- a/sdk/storage/azure-storage-files-shares/vcpkg.json +++ b/sdk/storage/azure-storage-files-shares/vcpkg.json @@ -1,6 +1,6 @@ { "name": "azure-storage-files-shares-cpp", - "version-semver": "12.3.0-beta.1", + "version-semver": "12.3.0", "description": [ "Microsoft Azure Storage Files Shares SDK for C++", "This library provides Azure Storage Files Shares SDK." 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/storage/test-resources-post.ps1 b/sdk/storage/test-resources-post.ps1 index a02df05f80..1a90ff6ff6 100644 --- a/sdk/storage/test-resources-post.ps1 +++ b/sdk/storage/test-resources-post.ps1 @@ -10,6 +10,8 @@ New-AzStorageEncryptionScope -ResourceGroupName $ResourceGroupName -StorageAccou New-AzStorageEncryptionScope -ResourceGroupName $ResourceGroupName -StorageAccountName $DeploymentOutputs['DATALAKE_ACCOUNT_NAME'] -EncryptionScopeName "EncryptionScopeForTest" -StorageEncryption +Enable-AzStorageBlobDeleteRetentionPolicy -ResourceGroupName $ResourceGroupName -StorageAccountName $DeploymentOutputs['DATALAKE_ACCOUNT_NAME'] -RetentionDays 7 + # This script is used to wait until XCache is refreshed for the service properties (30s), and role assignment takes effect (300s). Start-Sleep -s 300 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(""); /** diff --git a/tools/AzureVcpkg.cmake b/tools/AzureVcpkg.cmake new file mode 100644 index 0000000000..4b74c2a360 --- /dev/null +++ b/tools/AzureVcpkg.cmake @@ -0,0 +1,51 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +macro(az_vcpkg_integrate) + # AUTO CMAKE_TOOLCHAIN_FILE: + # User can call `cmake -DCMAKE_TOOLCHAIN_FILE="path_to_the_toolchain"` as the most specific scenario. + # An env var VCPKG_ROOT or VCPKG_INSTALLATION_ROOT can be set to let Azure SDK to set the VCPKG toolchain automatically. + # As the last alternative (default case), Azure SDK will automatically clone VCPKG folder and set toolchain from there. + if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) + if(DEFINED ENV{VCPKG_ROOT}) + set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + CACHE STRING "") + elseif(DEFINED ENV{VCPKG_INSTALLATION_ROOT}) + set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" + CACHE STRING "") + else() + # Set AZURE_SDK_DISABLE_AUTO_VCPKG env var to avoid Azure SDK from cloning and setting VCPKG automatically + # This option delegate package's dependencies installation to user. + 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 master) # use the last commit from VCPKG to get always the last version available from libs + + if(DEFINED ENV{AZURE_SDK_VCPKG_COMMIT}) + set(VCPKG_COMMIT_STRING "$ENV{AZURE_SDK_VCPKG_COMMIT}") # default SDK tested commit + endif() + + include(FetchContent) + FetchContent_Declare( + vcpkg + GIT_REPOSITORY https://github.com/microsoft/vcpkg.git + GIT_TAG ${VCPKG_COMMIT_STRING} + ) + FetchContent_GetProperties(vcpkg) + + # make sure to pull vcpkg only once. + if(NOT vcpkg_POPULATED) + FetchContent_Populate(vcpkg) + endif() + + # use the vcpkg source path + set(CMAKE_TOOLCHAIN_FILE "${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "") + endif() + endif() + endif() + + # enable triplet customization + if(DEFINED ENV{VCPKG_DEFAULT_TRIPLET} AND NOT DEFINED VCPKG_TARGET_TRIPLET) + set(VCPKG_TARGET_TRIPLET "$ENV{VCPKG_DEFAULT_TRIPLET}" CACHE STRING "") + endif() +endmacro() 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) diff --git a/vcpkg.json b/vcpkg.json index 1e586685dd..b88dcc5b0b 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" @@ -15,12 +15,14 @@ }, { "name": "opentelemetry-cpp", - "platform": "!uwp", + "platform": "!(windows & !static)", "version>=": "1.3.0" }, { "name": "wil", "platform": "windows" } + ], + "overrides": [ ] }