From 2644874d14733b32678a148a8c727c2b8030d5af Mon Sep 17 00:00:00 2001 From: LitoMore Date: Sun, 10 Aug 2025 22:31:06 +0800 Subject: [PATCH 1/2] chore: unblock the deprecated `http_parser` issue --- core/server/error-pages/500.html | 7 +- core/server/test-public/index.html | 4 +- frontend/src/css/custom.css | 2 +- package-lock.json | 11 +- package.json | 4 + vendor/http-deceiver/index.js | 288 +++++++++++++++++++++++++++++ vendor/http-deceiver/package.json | 1 + 7 files changed, 305 insertions(+), 12 deletions(-) create mode 100644 vendor/http-deceiver/index.js create mode 100644 vendor/http-deceiver/package.json diff --git a/core/server/error-pages/500.html b/core/server/error-pages/500.html index 25b4ff148601a..a87dfd2518a19 100644 --- a/core/server/error-pages/500.html +++ b/core/server/error-pages/500.html @@ -1,6 +1,5 @@ -A server error occurred +A server error occurred -

I have nothing to offer for this request

-

… but blood, toil, tears and sweat. -

+

I have nothing to offer for this request

+

… but blood, toil, tears and sweat.

And trying again later.

diff --git a/core/server/test-public/index.html b/core/server/test-public/index.html index 706f8467b06f5..74b953fd05e3c 100644 --- a/core/server/test-public/index.html +++ b/core/server/test-public/index.html @@ -1,7 +1,7 @@ - + - + shields.io diff --git a/frontend/src/css/custom.css b/frontend/src/css/custom.css index 1f4a458f95f8f..02019a9f4de90 100644 --- a/frontend/src/css/custom.css +++ b/frontend/src/css/custom.css @@ -23,7 +23,7 @@ padding: 0 var(--ifm-pre-padding); } -html[data-theme="dark"] .docusaurus-highlight-code-line { +html[data-theme='dark'] .docusaurus-highlight-code-line { background-color: rgba(0, 0, 0, 0.3); } diff --git a/package-lock.json b/package-lock.json index 9b673b5a03295..37e5b746d6eca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -86,6 +86,7 @@ "eslint-plugin-react-hooks": "7.0.1", "eslint-plugin-sort-class-members": "1.21.0", "globals": "16.5.0", + "http-deceiver": "file:vendor/http-deceiver", "icedfrisby": "4.0.0", "icedfrisby-nock": "^2.1.0", "is-svg": "^6.1.0", @@ -17764,9 +17765,8 @@ "license": "BSD-2-Clause" }, "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + "resolved": "vendor/http-deceiver", + "link": true }, "node_modules/http-errors": { "version": "2.0.0", @@ -31237,7 +31237,7 @@ "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", + "http-deceiver": "vender/http-deceiver", "select-hose": "^2.0.0", "spdy-transport": "^3.0.0" }, @@ -35346,6 +35346,7 @@ "type": "github", "url": "https://github.com/sponsors/wooorm" } - } + }, + "vendor/http-deceiver": {} } } diff --git a/package.json b/package.json index 2058317730638..667125a75393b 100644 --- a/package.json +++ b/package.json @@ -174,6 +174,7 @@ "eslint-plugin-react-hooks": "7.0.1", "eslint-plugin-sort-class-members": "1.21.0", "globals": "16.5.0", + "http-deceiver": "file:vendor/http-deceiver", "icedfrisby": "4.0.0", "icedfrisby-nock": "^2.1.0", "is-svg": "^6.1.0", @@ -200,6 +201,9 @@ "tsd": "^0.33.0", "url": "^0.11.4" }, + "overrides": { + "http-deceiver": "$http-deceiver" + }, "engines": { "node": "^22", "npm": "^10 || ^11" diff --git a/vendor/http-deceiver/index.js b/vendor/http-deceiver/index.js new file mode 100644 index 0000000000000..fbb9dd8107d31 --- /dev/null +++ b/vendor/http-deceiver/index.js @@ -0,0 +1,288 @@ +/* eslint-disable */ +/** + * The related issue: + * https://github.com/badges/shields/issues/11071 + * + * The code below is a modified version of the original http-deceiver library. + * It has been adapted to work with Node.js versions that have deprecated + * the original implementation. + * + * The original library can be found at: + * https://github.com/spdy-http2/http-deceiver (MIT License) + * + * This version is specifically tailored to handle the deprecation of + * the `http_parser` module in Node.js v12 and later. + * https://github.com/beenotung/http-deceiver/blob/node-v12-deprecation-fix/lib/deceiver.js (MIT License) + * + * It maintains compatibility with older Node.js versions while providing + * a consistent interface for HTTP request and response parsing. + */ +var assert = require('assert') + +var Buffer = require('buffer').Buffer + +// Node.js version +var mode = /^v0\.8\./.test(process.version) + ? 'rusty' + : /^v0\.(9|10)\./.test(process.version) + ? 'old' + : /^v0\.12\./.test(process.version) + ? 'normal' + : 'modern' + +var HTTPParser + +var methods +var reverseMethods + +// var kOnHeaders +var kOnHeadersComplete +var kOnMessageComplete +var kOnBody +if (mode === 'normal' || mode === 'modern') { + HTTPParser = require('_http_common').HTTPParser + methods = require('_http_common').methods + + // <= v11 + if (!HTTPParser) { + HTTPParser = process.binding('http_parser').HTTPParser + methods = process.binding('http_parser').methods + } + + // <= v5 + if (!methods) { + methods = HTTPParser.methods + } + + reverseMethods = {} + + methods.forEach(function (method, index) { + reverseMethods[method] = index + }) + + // kOnHeaders = HTTPParser.kOnHeaders | 0 + kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0 + kOnMessageComplete = HTTPParser.kOnMessageComplete | 0 + kOnBody = HTTPParser.kOnBody | 0 +} else { + // kOnHeaders = 'onHeaders' + kOnHeadersComplete = 'onHeadersComplete' + kOnMessageComplete = 'onMessageComplete' + kOnBody = 'onBody' +} + +function Deceiver(socket, options) { + this.socket = socket + this.options = options || {} + this.isClient = this.options.isClient +} +module.exports = Deceiver + +Deceiver.create = function create(stream, options) { + return new Deceiver(stream, options) +} + +Deceiver.prototype._toHeaderList = function _toHeaderList(object) { + var out = [] + var keys = Object.keys(object) + + for (var i = 0; i < keys.length; i++) { + out.push(keys[i], object[keys[i]]) + } + + return out +} + +Deceiver.prototype._isUpgrade = function _isUpgrade(request) { + return ( + request.method === 'CONNECT' || + request.headers.upgrade || + (request.headers.connection && + /(^|\W)upgrade(\W|$)/i.test(request.headers.connection)) + ) +} + +// TODO(indutny): support CONNECT +if (mode === 'modern') { + /* + function parserOnHeadersComplete(versionMajor, versionMinor, headers, method, + url, statusCode, statusMessage, upgrade, + shouldKeepAlive) { + */ + Deceiver.prototype.emitRequest = function emitRequest(request) { + var parser = this.socket.parser + assert(parser, 'No parser present') + + parser.execute = null + + var self = this + var method = reverseMethods[request.method] + parser.execute = function execute() { + self._skipExecute(this) + this[kOnHeadersComplete]( + 1, + 1, + self._toHeaderList(request.headers), + method, + request.path, + 0, + '', + self._isUpgrade(request), + true, + ) + return 0 + } + + this._emitEmpty() + } + + Deceiver.prototype.emitResponse = function emitResponse(response) { + var parser = this.socket.parser + assert(parser, 'No parser present') + + parser.execute = null + + var self = this + parser.execute = function execute() { + self._skipExecute(this) + this[kOnHeadersComplete]( + 1, + 1, + self._toHeaderList(response.headers), + response.path, + response.code, + response.status, + response.reason || '', + self._isUpgrade(response), + true, + ) + return 0 + } + + this._emitEmpty() + } +} else { + /* + `function parserOnHeadersComplete(info) {` + + info = { .versionMajor, .versionMinor, .url, .headers, .method, + .statusCode, .statusMessage, .upgrade, .shouldKeepAlive } + */ + Deceiver.prototype.emitRequest = function emitRequest(request) { + var parser = this.socket.parser + assert(parser, 'No parser present') + + var method = request.method + if (reverseMethods) { + method = reverseMethods[method] + } + + var info = { + versionMajor: 1, + versionMinor: 1, + url: request.path, + headers: this._toHeaderList(request.headers), + method: method, + statusCode: 0, + statusMessage: '', + upgrade: this._isUpgrade(request), + shouldKeepAlive: true, + } + + var self = this + parser.execute = function execute() { + self._skipExecute(this) + this[kOnHeadersComplete](info) + return 0 + } + + this._emitEmpty() + } + + Deceiver.prototype.emitResponse = function emitResponse(response) { + var parser = this.socket.parser + assert(parser, 'No parser present') + + var info = { + versionMajor: 1, + versionMinor: 1, + url: response.path, + headers: this._toHeaderList(response.headers), + method: false, + statusCode: response.status, + statusMessage: response.reason || '', + upgrade: this._isUpgrade(response), + shouldKeepAlive: true, + } + + var self = this + parser.execute = function execute() { + self._skipExecute(this) + this[kOnHeadersComplete](info) + return 0 + } + + this._emitEmpty() + } +} + +Deceiver.prototype._skipExecute = function _skipExecute(parser) { + var self = this + var oldExecute = parser.constructor.prototype.execute + var oldFinish = parser.constructor.prototype.finish + + parser.execute = null + parser.finish = null + + parser.execute = function execute(buffer, start, len) { + // Parser reuse + if (this.socket !== self.socket) { + this.execute = oldExecute + this.finish = oldFinish + return this.execute(buffer, start, len) + } + + if (start !== undefined) { + buffer = buffer.slice(start, start + len) + } + self.emitBody(buffer) + return len + } + + parser.finish = function finish() { + // Parser reuse + if (this.socket !== self.socket) { + this.execute = oldExecute + this.finish = oldFinish + return this.finish() + } + + this.execute = oldExecute + this.finish = oldFinish + self.emitMessageComplete() + } +} + +Deceiver.prototype.emitBody = function emitBody(buffer) { + var parser = this.socket.parser + assert(parser, 'No parser present') + + parser[kOnBody](buffer, 0, buffer.length) +} + +Deceiver.prototype._emitEmpty = function _emitEmpty() { + // Emit data to force out handling of UPGRADE + var empty = new Buffer(0) + if (this.socket.ondata) { + this.socket.ondata(empty, 0, 0) + } else { + this.socket.emit('data', empty) + } +} + +Deceiver.prototype.emitMessageComplete = function emitMessageComplete() { + var parser = this.socket.parser + assert(parser, 'No parser present') + + parser[kOnMessageComplete]() +} diff --git a/vendor/http-deceiver/package.json b/vendor/http-deceiver/package.json new file mode 100644 index 0000000000000..0967ef424bce6 --- /dev/null +++ b/vendor/http-deceiver/package.json @@ -0,0 +1 @@ +{} From 81d5af9d2d49c53d651bdf8f1ad22849318ab824 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Fri, 14 Nov 2025 00:44:33 +0800 Subject: [PATCH 2/2] Add license & readme --- vendor/http-deceiver/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 vendor/http-deceiver/README.md diff --git a/vendor/http-deceiver/README.md b/vendor/http-deceiver/README.md new file mode 100644 index 0000000000000..e26298ad9c900 --- /dev/null +++ b/vendor/http-deceiver/README.md @@ -0,0 +1,17 @@ +# vendor/http-deceiver + +This is a workaround to bypass the blocker for https://github.com/badges/shields/issues/11071. + +Related PR: https://github.com/badges/shields/pull/11279. + +## LICENSE + +This software is licensed under the MIT License. + +Copyright Fedor Indutny, 2015. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.