diff --git a/build/dependencies.props b/build/dependencies.props index bb260a366..b5274ed65 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -6,7 +6,7 @@ 3.23.1 2.55.0 2.46.6 - 2.57.0 + 2.59.0 8.0.0-rc.1.23378.7 7.0.5 6.0.11 diff --git a/examples/Spar/Server/ClientApp/package-lock.json b/examples/Spar/Server/ClientApp/package-lock.json index cf74ae03a..237267ff8 100644 --- a/examples/Spar/Server/ClientApp/package-lock.json +++ b/examples/Spar/Server/ClientApp/package-lock.json @@ -36,12 +36,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" @@ -108,28 +109,20 @@ } }, "node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", @@ -248,13 +241,10 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, "engines": { "node": ">=6.9.0" } @@ -272,38 +262,25 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -428,21 +405,30 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -487,13 +473,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -501,9 +487,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1666,33 +1652,33 @@ } }, "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1701,12 +1687,13 @@ } }, "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1719,29 +1706,52 @@ "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", "dev": true }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@mrmlnc/readdir-enhanced": { @@ -9376,12 +9386,13 @@ } }, "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "requires": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, "@babel/compat-data": { @@ -9428,22 +9439,15 @@ } }, "@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" } }, "@babel/helper-annotate-as-pure": { @@ -9535,13 +9539,10 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true }, "@babel/helper-explode-assignable-expression": { "version": "7.16.7", @@ -9553,32 +9554,22 @@ } }, "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { @@ -9673,18 +9664,24 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { @@ -9717,20 +9714,20 @@ } }, "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { @@ -10505,41 +10502,42 @@ } }, "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -10549,26 +10547,43 @@ "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@mrmlnc/readdir-enhanced": { diff --git a/src/Grpc.AspNetCore.Server/Internal/GrpcProtocolHelpers.cs b/src/Grpc.AspNetCore.Server/Internal/GrpcProtocolHelpers.cs index 11aa0d1a7..ef5a7b191 100644 --- a/src/Grpc.AspNetCore.Server/Internal/GrpcProtocolHelpers.cs +++ b/src/Grpc.AspNetCore.Server/Internal/GrpcProtocolHelpers.cs @@ -1,4 +1,4 @@ -#region Copyright notice and license +#region Copyright notice and license // Copyright 2019 The gRPC Authors // @@ -234,4 +234,17 @@ internal static bool ShouldSkipHeader(string name) { return name.StartsWith(':') || GrpcProtocolConstants.FilteredHeaders.Contains(name); } + + internal static IHttpRequestLifetimeFeature GetRequestLifetimeFeature(HttpContext httpContext) + { + var lifetimeFeature = httpContext.Features.Get(); + if (lifetimeFeature is null) + { + // This should only run in tests where the HttpContext is manually created. + lifetimeFeature = new HttpRequestLifetimeFeature(); + httpContext.Features.Set(lifetimeFeature); + } + + return lifetimeFeature; + } } diff --git a/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamReader.cs b/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamReader.cs index 3525cf37a..528aeed87 100644 --- a/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamReader.cs +++ b/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamReader.cs @@ -17,8 +17,10 @@ #endregion using System.Diagnostics; +using System.IO.Pipelines; using Grpc.Core; using Grpc.Shared; +using Microsoft.AspNetCore.Http.Features; namespace Grpc.AspNetCore.Server.Internal; @@ -28,6 +30,8 @@ internal class HttpContextStreamReader : IAsyncStreamReader { private readonly HttpContextServerCallContext _serverCallContext; private readonly Func _deserializer; + private readonly PipeReader _bodyReader; + private readonly IHttpRequestLifetimeFeature _requestLifetimeFeature; private bool _completed; private long _readCount; private bool _endOfStream; @@ -36,6 +40,12 @@ public HttpContextStreamReader(HttpContextServerCallContext serverCallContext, F { _serverCallContext = serverCallContext; _deserializer = deserializer; + + // Copy HttpContext values. + // This is done to avoid a race condition when reading them from HttpContext later when running in a separate thread. + _bodyReader = _serverCallContext.HttpContext.Request.BodyReader; + // Copy lifetime feature because HttpContext.RequestAborted on .NET 6 doesn't return the real cancellation token. + _requestLifetimeFeature = GrpcProtocolHelpers.GetRequestLifetimeFeature(_serverCallContext.HttpContext); } public TRequest Current { get; private set; } = default!; @@ -54,7 +64,7 @@ async Task MoveNextAsync(ValueTask readStreamTask) return Task.FromCanceled(cancellationToken); } - if (_completed || _serverCallContext.CancellationToken.IsCancellationRequested) + if (_completed || _requestLifetimeFeature.RequestAborted.IsCancellationRequested) { return Task.FromException(new InvalidOperationException("Can't read messages after the request is complete.")); } @@ -63,7 +73,7 @@ async Task MoveNextAsync(ValueTask readStreamTask) // In a long running stream this can allow the previous value to be GCed. Current = null!; - var request = _serverCallContext.HttpContext.Request.BodyReader.ReadStreamMessageAsync(_serverCallContext, _deserializer, cancellationToken); + var request = _bodyReader.ReadStreamMessageAsync(_serverCallContext, _deserializer, cancellationToken); if (!request.IsCompletedSuccessfully) { return MoveNextAsync(request); diff --git a/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamWriter.cs b/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamWriter.cs index 1518fc9eb..b6a67f9fd 100644 --- a/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamWriter.cs +++ b/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamWriter.cs @@ -17,8 +17,10 @@ #endregion using System.Diagnostics; +using System.IO.Pipelines; using Grpc.Core; using Grpc.Shared; +using Microsoft.AspNetCore.Http.Features; namespace Grpc.AspNetCore.Server.Internal; @@ -29,6 +31,8 @@ internal class HttpContextStreamWriter : IServerStreamWriter _serializer; + private readonly PipeWriter _bodyWriter; + private readonly IHttpRequestLifetimeFeature _requestLifetimeFeature; private readonly object _writeLock; private Task? _writeTask; private bool _completed; @@ -39,6 +43,12 @@ public HttpContextStreamWriter(HttpContextServerCallContext context, Actiontrue true - net462;netstandard1.5;netstandard2.0 + net462;netstandard2.0 README.md diff --git a/src/Grpc.Core.Api/Grpc.Core.Api.csproj b/src/Grpc.Core.Api/Grpc.Core.Api.csproj index 6cf865ff7..bb6756d1e 100755 --- a/src/Grpc.Core.Api/Grpc.Core.Api.csproj +++ b/src/Grpc.Core.Api/Grpc.Core.Api.csproj @@ -5,7 +5,7 @@ true true - net462;netstandard1.5;netstandard2.0;netstandard2.1 + net462;netstandard2.0;netstandard2.1 README.md true diff --git a/src/Grpc.Core.Api/Internal/ClientDebuggerHelpers.cs b/src/Grpc.Core.Api/Internal/ClientDebuggerHelpers.cs index f309fd8ce..3ca7b0dba 100644 --- a/src/Grpc.Core.Api/Internal/ClientDebuggerHelpers.cs +++ b/src/Grpc.Core.Api/Internal/ClientDebuggerHelpers.cs @@ -25,11 +25,7 @@ namespace Grpc.Core.Internal; internal static class ClientDebuggerHelpers { -#if NETSTANDARD1_5 - private static TypeInfo? GetParentType(Type clientType) -#else private static Type? GetParentType(Type clientType) -#endif { // Attempt to get the parent type for a generated client. // A generated client is always nested inside a static type that contains information about the client. @@ -48,11 +44,7 @@ internal static class ClientDebuggerHelpers return null; } -#if NETSTANDARD1_5 - var parentType = clientType.DeclaringType.GetTypeInfo(); -#else var parentType = clientType.DeclaringType; -#endif // Check parent type is static. A C# static type is sealed and abstract. if (parentType == null || (!parentType.IsSealed && !parentType.IsAbstract)) { @@ -101,10 +93,6 @@ internal static class ClientDebuggerHelpers return methods; static bool IsMethodField(FieldInfo field) => -#if NETSTANDARD1_5 - typeof(IMethod).GetTypeInfo().IsAssignableFrom(field.FieldType); -#else typeof(IMethod).IsAssignableFrom(field.FieldType); -#endif } } diff --git a/src/Grpc.Core.Api/Status.cs b/src/Grpc.Core.Api/Status.cs index 01055cd9e..45d795562 100644 --- a/src/Grpc.Core.Api/Status.cs +++ b/src/Grpc.Core.Api/Status.cs @@ -15,6 +15,7 @@ #endregion using System; +using System.Diagnostics; namespace Grpc.Core; @@ -22,6 +23,7 @@ namespace Grpc.Core; /// /// Represents RPC result, which consists of and an optional detail string. /// +[DebuggerDisplay("{DebuggerToString(),nq}")] public struct Status { /// @@ -93,4 +95,19 @@ public override string ToString() } return $"Status(StatusCode=\"{StatusCode}\", Detail=\"{Detail}\")"; } + + private string DebuggerToString() + { + var text = $"StatusCode = {StatusCode}"; + if (!string.IsNullOrEmpty(Detail)) + { + text += $@", Detail = ""{Detail}"""; + } + if (DebugException != null) + { + text += $@", DebugException = ""{DebugException.GetType()}: {DebugException.Message}"""; + } + + return text; + } } diff --git a/src/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/Grpc.HealthCheck/Grpc.HealthCheck.csproj index c6a40f099..d3e02fc34 100755 --- a/src/Grpc.HealthCheck/Grpc.HealthCheck.csproj +++ b/src/Grpc.HealthCheck/Grpc.HealthCheck.csproj @@ -5,7 +5,7 @@ true true - net462;netstandard1.5;netstandard2.0 + net462;netstandard2.0 README.md diff --git a/src/Grpc.Net.Client/Balancer/Internal/SocketConnectivitySubchannelTransport.cs b/src/Grpc.Net.Client/Balancer/Internal/SocketConnectivitySubchannelTransport.cs index b602843f2..85669a691 100644 --- a/src/Grpc.Net.Client/Balancer/Internal/SocketConnectivitySubchannelTransport.cs +++ b/src/Grpc.Net.Client/Balancer/Internal/SocketConnectivitySubchannelTransport.cs @@ -190,6 +190,9 @@ public async ValueTask TryConnectAsync(ConnectContext context) } catch (Exception ex) { + // Socket is recreated every connect attempt. Explicitly dispose failed socket before next attempt. + socket.Dispose(); + SocketConnectivitySubchannelTransportLog.ErrorConnectingSocket(_logger, _subchannel.Id, currentEndPoint, ex); if (firstConnectionError == null) diff --git a/src/Grpc.Net.Client/GrpcChannel.cs b/src/Grpc.Net.Client/GrpcChannel.cs index 71adcda91..47a782ad0 100644 --- a/src/Grpc.Net.Client/GrpcChannel.cs +++ b/src/Grpc.Net.Client/GrpcChannel.cs @@ -266,17 +266,9 @@ private static HttpHandlerContext CalculateHandlerContext(ILogger logger, Uri ad } if (HttpRequestHelpers.HasHttpHandlerType(channelOptions.HttpHandler, "System.Net.Http.SocketsHttpHandler")) { - HttpHandlerType type; - TimeSpan? connectTimeout; - TimeSpan? connectionIdleTimeout; - #if NET5_0_OR_GREATER var socketsHttpHandler = HttpRequestHelpers.GetHttpHandlerType(channelOptions.HttpHandler)!; - type = HttpHandlerType.SocketsHttpHandler; - connectTimeout = socketsHttpHandler.ConnectTimeout; - connectionIdleTimeout = GetConnectionIdleTimeout(socketsHttpHandler); - // Check if the SocketsHttpHandler is being shared by channels. // It has already been setup by another channel (i.e. ConnectCallback is set) then // additional channels can use advanced connectivity features. @@ -286,33 +278,34 @@ private static HttpHandlerContext CalculateHandlerContext(ILogger logger, Uri ad // This channel can't support advanced connectivity features. if (socketsHttpHandler.ConnectCallback != null) { - type = HttpHandlerType.Custom; - connectTimeout = null; - connectionIdleTimeout = null; + return new HttpHandlerContext(HttpHandlerType.Custom); } } + // Load balancing has been disabled on the SocketsHttpHandler. + if (socketsHttpHandler.Properties.TryGetValue("__GrpcLoadBalancingDisabled", out var value) + && value is bool loadBalancingDisabled && loadBalancingDisabled) + { + return new HttpHandlerContext(HttpHandlerType.Custom); + } + // If a proxy is specified then requests could be sent via an SSL tunnel. // A CONNECT request is made to the proxy to establish the transport stream and then // gRPC calls are sent via stream. This feature isn't supported by load balancer. // Proxy can be specified via: // - SocketsHttpHandler.Proxy. Set via app code. // - HttpClient.DefaultProxy. Set via environment variables, e.g. HTTPS_PROXY. - if (type == HttpHandlerType.SocketsHttpHandler) + if (IsProxied(socketsHttpHandler, address, isSecure)) { - if (IsProxied(socketsHttpHandler, address, isSecure)) - { - logger.LogInformation("Proxy configuration is detected. How the gRPC client creates connections can cause unexpected behavior when a proxy is configured. " + - "To ensure the client correctly uses a proxy, configure GrpcChannelOptions.HttpHandler to use HttpClientHandler. " + - "Note that HttpClientHandler isn't compatible with load balancing."); - } + logger.LogInformation("Proxy configuration is detected. How the gRPC client creates connections can cause unexpected behavior when a proxy is configured. " + + "To ensure the client correctly uses a proxy, configure GrpcChannelOptions.HttpHandler to use HttpClientHandler. " + + "Note that HttpClientHandler isn't compatible with load balancing."); } + + return new HttpHandlerContext(HttpHandlerType.SocketsHttpHandler, socketsHttpHandler.ConnectTimeout, GetConnectionIdleTimeout(socketsHttpHandler)); #else - type = HttpHandlerType.SocketsHttpHandler; - connectTimeout = null; - connectionIdleTimeout = null; + return new HttpHandlerContext(HttpHandlerType.SocketsHttpHandler); #endif - return new HttpHandlerContext(type, connectTimeout, connectionIdleTimeout); } if (HttpRequestHelpers.GetHttpHandlerType(channelOptions.HttpHandler) != null) { diff --git a/src/Grpc.Reflection/Grpc.Reflection.csproj b/src/Grpc.Reflection/Grpc.Reflection.csproj index 0a52e1642..63b23d665 100755 --- a/src/Grpc.Reflection/Grpc.Reflection.csproj +++ b/src/Grpc.Reflection/Grpc.Reflection.csproj @@ -5,7 +5,7 @@ true true - net462;netstandard1.5;netstandard2.0 + net462;netstandard2.0 README.md diff --git a/src/Shared/HttpRequestHelpers.cs b/src/Shared/HttpRequestHelpers.cs index 2f75e9c68..a08accd5e 100644 --- a/src/Shared/HttpRequestHelpers.cs +++ b/src/Shared/HttpRequestHelpers.cs @@ -1,4 +1,4 @@ -#region Copyright notice and license +#region Copyright notice and license // Copyright 2019 The gRPC Authors // @@ -53,7 +53,7 @@ public static bool HasHttpHandlerType(HttpMessageHandler handler, string handler public static HttpMessageHandler? GetHttpHandlerType(HttpMessageHandler handler, string handlerTypeName) { - if (handler?.GetType().FullName == handlerTypeName) + if (IsType(handler.GetType(), handlerTypeName)) { return handler; } @@ -62,8 +62,7 @@ public static bool HasHttpHandlerType(HttpMessageHandler handler, string handler while (currentHandler is DelegatingHandler delegatingHandler) { currentHandler = delegatingHandler.InnerHandler; - - if (currentHandler?.GetType().FullName == handlerTypeName) + if (currentHandler != null && IsType(currentHandler.GetType(), handlerTypeName)) { return currentHandler; } @@ -72,6 +71,21 @@ public static bool HasHttpHandlerType(HttpMessageHandler handler, string handler return null; } + private static bool IsType(Type type, string handlerTypeName) + { + Type? currentType = type; + do + { + if (currentType.FullName == handlerTypeName) + { + return true; + } + + } while ((currentType = currentType.BaseType) != null); + + return false; + } + public static bool HasHttpHandlerType(HttpMessageHandler handler) where T : HttpMessageHandler { return GetHttpHandlerType(handler) != null; diff --git a/test/Grpc.AspNetCore.Server.Tests/DuplexStreamingServerCallHandlerTests.cs b/test/Grpc.AspNetCore.Server.Tests/DuplexStreamingServerCallHandlerTests.cs new file mode 100644 index 000000000..c2bd64e12 --- /dev/null +++ b/test/Grpc.AspNetCore.Server.Tests/DuplexStreamingServerCallHandlerTests.cs @@ -0,0 +1,67 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#endregion + +using Grpc.AspNetCore.Server.Internal.CallHandlers; +using Grpc.AspNetCore.Server.Tests.TestObjects; +using Grpc.Core; +using Grpc.Shared.Server; +using Grpc.Tests.Shared; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Logging.Abstractions; +using NUnit.Framework; + +namespace Grpc.AspNetCore.Server.Tests; + +[TestFixture] +public class DuplexStreamingServerCallHandlerTests +{ + private static readonly Marshaller _marshaller = new Marshaller((message, context) => { context.Complete(Array.Empty()); }, context => new TestMessage()); + + [Test] + public async Task HandleCallAsync_ConcurrentReadAndWrite_Success() + { + // Arrange + var invoker = new DuplexStreamingServerMethodInvoker( + (service, reader, writer, context) => + { + var message = new TestMessage(); + var readTask = Task.Run(() => reader.MoveNext()); + var writeTask = Task.Run(() => writer.WriteAsync(message)); + return Task.WhenAll(readTask, writeTask); + }, + new Method(MethodType.DuplexStreaming, "test", "test", _marshaller, _marshaller), + HttpContextServerCallContextHelper.CreateMethodOptions(), + new TestGrpcServiceActivator()); + var handler = new DuplexStreamingServerCallHandler(invoker, NullLoggerFactory.Instance); + + // Verify there isn't a race condition when reading/writing on seperate threads. + // This test primarily exists to ensure that the stream reader and stream writer aren't accessing non-thread safe APIs on HttpContext. + for (var i = 0; i < 10_000; i++) + { + var httpContext = HttpContextHelpers.CreateContext(); + + // Act + await handler.HandleCallAsync(httpContext); + + // Assert + var trailers = httpContext.Features.Get()!.Trailers; + Assert.AreEqual("0", trailers["grpc-status"].ToString()); + } + } +} diff --git a/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs b/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs index c2c3f2aa3..15a9abb12 100644 --- a/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs +++ b/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs @@ -649,8 +649,11 @@ public void WinHttpHandler_UnsupportedWindows_Throw() "For more information, see https://aka.ms/aspnet/grpc/netframework."); } - [Test] - public void WinHttpHandler_SupportedWindows_Success() +#pragma warning disable CS0436 // Just need to have a type called WinHttpHandler to activate new behavior. + [TestCase(typeof(WinHttpHandler))] +#pragma warning restore CS0436 + [TestCase(typeof(WinHttpHandlerInherited))] + public void WinHttpHandler_SupportedWindows_Success(Type handlerType) { // Arrange var services = new ServiceCollection(); @@ -660,9 +663,7 @@ public void WinHttpHandler_SupportedWindows_Success() OSVersion = Version.Parse("10.0.20348.169") }); -#pragma warning disable CS0436 // Just need to have a type called WinHttpHandler to activate new behavior. - var winHttpHandler = new WinHttpHandler(new TestHttpMessageHandler()); -#pragma warning restore CS0436 + var winHttpHandler = (HttpMessageHandler)Activator.CreateInstance(handlerType, new TestHttpMessageHandler())!; // Act var channel = GrpcChannel.ForAddress("https://localhost", new GrpcChannelOptions @@ -675,6 +676,15 @@ public void WinHttpHandler_SupportedWindows_Success() Assert.AreEqual(HttpHandlerType.WinHttpHandler, channel.HttpHandlerType); } +#pragma warning disable CS0436 // Just need to have a type called WinHttpHandler to activate new behavior. + private class WinHttpHandlerInherited : WinHttpHandler + { + public WinHttpHandlerInherited(HttpMessageHandler innerHandler) : base(innerHandler) + { + } + } +#pragma warning restore CS0436 + #if SUPPORT_LOAD_BALANCING [Test] public void Resolver_SocketHttpHandlerWithConnectCallback_Error()