test failed in chrome browser and nodejs
masx200 opened this issue · 5 comments
chrome 版本 102.0.1245.44 (正式版本) (64 位)
Node.js v18.3.0
https://cdn.skypack.dev/http-parser-js@0.5.6/http-parser.js?dts
https://esm.sh/http-parser-js@0.5.6/http-parser.js?dts
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script type="module" src="./test-http-parser-js.mjs"></script>
</body>
</html>
import {
// HeaderObject,
HTTPParser,
} from "https://esm.sh/http-parser-js@0.5.6/http-parser.js?dts";
console.log(HTTPParser);
export async function parseRequest(input /* : Uint8Array */) {
const parser = new HTTPParser(HTTPParser.REQUEST);
console.log(parser);
let complete = false;
let shouldKeepAlive;
let upgrade;
let method;
let url;
let versionMajor;
let versionMinor;
let headers /* : never[] | HeaderObject */ = [];
let trailers /* : string[] */ = [];
const bodyChunks /* : Uint8Array[] */ = [];
parser[HTTPParser.kOnHeadersComplete] = function (req) {
console.log("kOnHeadersComplete", req);
shouldKeepAlive = req.shouldKeepAlive;
upgrade = req.upgrade;
// deno-lint-ignore ban-ts-comment
//@ts-ignore
method = HTTPParser.methods[req.method];
url = req.url;
versionMajor = req.versionMajor;
versionMinor = req.versionMinor;
headers = req.headers;
};
parser[HTTPParser.kOnBody] = function (chunk, offset, length) {
console.log("kOnBody", chunk, offset, length);
bodyChunks.push(chunk.slice(offset, offset + length));
};
// This is actually the event for trailers, go figure.
parser[HTTPParser.kOnHeaders] = function (t) {
console.log("kOnHeaders", t);
trailers = t;
};
parser[HTTPParser.kOnMessageComplete] = function () {
console.log("kOnMessageComplete");
complete = true;
};
// Since we are sending the entire Buffer at once here all callbacks above happen synchronously.
// The parser does not do _anything_ asynchronous.
// However, you can of course call execute() multiple times with multiple chunks, e.g. from a stream.
// But then you have to refactor the entire logic to be async (e.g. resolve a Promise in kOnMessageComplete and add timeout logic).
const error = parser.execute(input);
if (error instanceof Error) {
throw error;
}
parser.finish();
if (!complete) {
throw new Error("Could not parse request");
}
const body = await new Blob(bodyChunks).arrayBuffer();
return {
shouldKeepAlive,
upgrade,
method,
url,
versionMajor,
versionMinor,
headers,
body,
trailers,
};
}
console.log("Example: basic GET request:");
const input =
'GET /v.gif?t=1655787151198&pid=103&referrer=https%3A%2F%2Fbaike.baidu.com%2Fitem%2FCRLF%2F7659459&type=10010009&index=1655787089090&_dTm=62108&_did=1655787151198&lemmaId=1157566&newLemmaId=7659459&subLemmaId=1157566&lemmaTitle=CRLF&url=https%3A%2F%2Fbaike.baidu.com%2Fitem%2FCRLF%2F7659459 HTTP/1.1\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\r\nCache-Control: max-age=0\r\nConnection: keep-alive\r\nCookie: __yjs_duid=1_fa1b0419ac25df147d4e4501b94dabba1645767195236; BAIDUID=1C8DAF19769B90116DDCA39B63310EE5:FG=1; BIDUPSID=1C8DAF19769B90116DDCA39B63310EE5; PSTM=1648793481; BAIDUID_BFESS=6A3143B22B963455BAA872B8D3C6DBEA:FG=1; BDUSS=k1WmxpOElFaFUzM0Q5ZnQyWGxuQTRuMzA2RERIQmpXWjhKMU1PZUZoZm1MTUZpSVFBQUFBJCQAAAAAAAAAAAEAAADPRYIEbWFzeDIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOafmWLmn5liVk; BDUSS_BFESS=k1WmxpOElFaFUzM0Q5ZnQyWGxuQTRuMzA2RERIQmpXWjhKMU1PZUZoZm1MTUZpSVFBQUFBJCQAAAAAAAAAAAEAAADPRYIEbWFzeDIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOafmWLmn5liVk; ab_sr=1.0.1_OTRjNjg1ZTI1YjllNjQwOTdmMGI3M2EwYTEzNmI1NzM3NzZlMjVlNGFmODljNzZjYWI2MGI5OGViOTA1NjYyZTc5ZjI0ZjliNWFhMTU5MTFjZWExNDNmOWYzNWJmOGQ1MjcxOWM0ODMyNGI4MjliMDJiNjNhNTk0NTMzNTM3ZjU4YzNmN2I1OGEzMmQ1NGUxNDJmMjkwNDdkMTMwOThiMTk4NTNkY2E1NDQxYTVkZWI4YjRmZGI4YTBjNzYxNWNh; RT="z=1&dm=baidu.com&si=qoeulsf2old&ss=l4novq29&sl=5&tt=1yr&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=b0z"\r\nDNT: 1\r\nHost: nsclick.baidu.com\r\nReferer: https://baike.baidu.com/item/CRLF/7659459\r\nSec-Fetch-Dest: empty\r\nSec-Fetch-Mode: no-cors\r\nSec-Fetch-Site: same-site\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.124 Safari/537.36 Edg/102.0.1245.44\r\nsec-ch-ua: " Not A;Brand";v="99", "Chromium";v="102", "Microsoft Edge";v="102"\r\nsec-ch-ua-mobile: ?0\r\nsec-ch-ua-platform: "Windows"\r\n\r\n';
console.log(input);
const parsed = await parseRequest(new TextEncoder().encode(input));
console.log(parsed);
in browser chrome
Uncaught Error: Parse Error
at f (http-parser.js:2:7310)
at s.REQUEST_LINE (http-parser.js:2:3922)
at s.execute (http-parser.js:2:2430)
at parseRequest (test-http-parser-js.mjs:53:26)
at test-http-parser-js.mjs:82:22
in nodejs
node C:\Documents\test\test-http-parser-js.mjs
C:\Documents\test\node_modules\http-parser-js\http-parser.js:484
var err = new Error("Parse Error");
^
Error: Parse Error
at parseErrorCode (C:\Documents\test\node_modules\http-parser-js\http-parser.js:484:13)
at HTTPParser.REQUEST_LINE (C:\Documents\test\node_modules\http-parser-js\http-parser.js:244:11)
at HTTPParser.execute (C:\Documents\test\node_modules\http-parser-js\http-parser.js:130:27)
at parseRequest (file:///C:/Documents/test/test-http-parser-js.mjs:55:24)
at file:///C:/Documents/test/test-http-parser-js.mjs:84:22
at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:409:24)
at async loadESM (node:internal/process/esm_loader:85:5)
at async handleMainPromise (node:internal/modules/run_main:61:12) {
code: 'HPE_INVALID_CONSTANT'
}
Node.js v18.3.0
{
"dependencies": {
"http-parser-js": "^0.5.6"
}
}
PR's welcome if the cause is identified, and add the request to test-http-parser-durability.js
for future testing.
Line 190 in ad2ac40
I know the reason for the error. There is no buffer object in the browser. You can only use uint8array. Its tostring method is different from that of buffer.
https://developer.mozilla.org/zh-CN/docs/Web/API/TextDecoder
Decoding strings in browsers should use TextDecoder
Yeah, this is a Node module and takes a Buffer as input, if you want to use it in the browser, easiest is probably to use an appropriate polyfill.
import { HTTPParser } from "https://esm.sh/http-parser-js@0.5.6/http-parser.js?dts";
console.log(HTTPParser);
import { Buffer } from "https://esm.sh/buffer@6.0.3?dts";
export async function parseRequest(input /* : Uint8Array */) {
input = Buffer.from(input);
const parser = new HTTPParser(HTTPParser.REQUEST);
console.log(parser);
let complete = false;
let shouldKeepAlive;
let upgrade;
let method;
let url;
let versionMajor;
let versionMinor;
let headers /* : never[] | HeaderObject */ = [];
let trailers /* : string[] */ = [];
const bodyChunks /* : Uint8Array[] */ = [];
parser[HTTPParser.kOnHeadersComplete] = function (req) {
console.log("kOnHeadersComplete", req);
shouldKeepAlive = req.shouldKeepAlive;
upgrade = req.upgrade;
// deno-lint-ignore ban-ts-comment
//@ts-ignore
method = HTTPParser.methods[req.method];
url = req.url;
versionMajor = req.versionMajor;
versionMinor = req.versionMinor;
headers = req.headers;
};
parser[HTTPParser.kOnBody] = function (chunk, offset, length) {
console.log("kOnBody", chunk, offset, length);
bodyChunks.push(chunk.slice(offset, offset + length));
};
// This is actually the event for trailers, go figure.
parser[HTTPParser.kOnHeaders] = function (t) {
console.log("kOnHeaders", t);
trailers = t;
};
parser[HTTPParser.kOnMessageComplete] = function () {
console.log("kOnMessageComplete");
complete = true;
};
// Since we are sending the entire Buffer at once here all callbacks above happen synchronously.
// The parser does not do _anything_ asynchronous.
// However, you can of course call execute() multiple times with multiple chunks, e.g. from a stream.
// But then you have to refactor the entire logic to be async (e.g. resolve a Promise in kOnMessageComplete and add timeout logic).
const error = parser.execute(input);
if (error instanceof Error) {
throw error;
}
parser.finish();
if (!complete) {
throw new Error("Could not parse request");
}
const body = await new Blob(bodyChunks).arrayBuffer();
return {
shouldKeepAlive,
upgrade,
method,
url,
versionMajor,
versionMinor,
headers,
body,
trailers,
};
}
console.log("Example: basic GET request:");
const input =
'GET /v.gif?t=1655787151198&pid=103&referrer=https%3A%2F%2Fbaike.baidu.com%2Fitem%2FCRLF%2F7659459&type=10010009&index=1655787089090&_dTm=62108&_did=1655787151198&lemmaId=1157566&newLemmaId=7659459&subLemmaId=1157566&lemmaTitle=CRLF&url=https%3A%2F%2Fbaike.baidu.com%2Fitem%2FCRLF%2F7659459 HTTP/1.1\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\r\nCache-Control: max-age=0\r\nConnection: keep-alive\r\nCookie: __yjs_duid=1_fa1b0419ac25df147d4e4501b94dabba1645767195236; BAIDUID=1C8DAF19769B90116DDCA39B63310EE5:FG=1; BIDUPSID=1C8DAF19769B90116DDCA39B63310EE5; PSTM=1648793481; BAIDUID_BFESS=6A3143B22B963455BAA872B8D3C6DBEA:FG=1; BDUSS=k1WmxpOElFaFUzM0Q5ZnQyWGxuQTRuMzA2RERIQmpXWjhKMU1PZUZoZm1MTUZpSVFBQUFBJCQAAAAAAAAAAAEAAADPRYIEbWFzeDIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOafmWLmn5liVk; BDUSS_BFESS=k1WmxpOElFaFUzM0Q5ZnQyWGxuQTRuMzA2RERIQmpXWjhKMU1PZUZoZm1MTUZpSVFBQUFBJCQAAAAAAAAAAAEAAADPRYIEbWFzeDIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOafmWLmn5liVk; ab_sr=1.0.1_OTRjNjg1ZTI1YjllNjQwOTdmMGI3M2EwYTEzNmI1NzM3NzZlMjVlNGFmODljNzZjYWI2MGI5OGViOTA1NjYyZTc5ZjI0ZjliNWFhMTU5MTFjZWExNDNmOWYzNWJmOGQ1MjcxOWM0ODMyNGI4MjliMDJiNjNhNTk0NTMzNTM3ZjU4YzNmN2I1OGEzMmQ1NGUxNDJmMjkwNDdkMTMwOThiMTk4NTNkY2E1NDQxYTVkZWI4YjRmZGI4YTBjNzYxNWNh; RT="z=1&dm=baidu.com&si=qoeulsf2old&ss=l4novq29&sl=5&tt=1yr&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=b0z"\r\nDNT: 1\r\nHost: nsclick.baidu.com\r\nReferer: https://baike.baidu.com/item/CRLF/7659459\r\nSec-Fetch-Dest: empty\r\nSec-Fetch-Mode: no-cors\r\nSec-Fetch-Site: same-site\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.124 Safari/537.36 Edg/102.0.1245.44\r\nsec-ch-ua: " Not A;Brand";v="99", "Chromium";v="102", "Microsoft Edge";v="102"\r\nsec-ch-ua-mobile: ?0\r\nsec-ch-ua-platform: "Windows"\r\n\r\n';
console.log(input);
const parsed = await parseRequest(new TextEncoder().encode(input));
console.log(parsed);