Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3367440

Browse files
e3diodarrachequesne
authored andcommitted
fix(uws): properly handle chunked content (#642)
With the engine based on µWebSockets.js (introduced in version 6.1.0),a huge request body split in multiple chunks would throw the followingerror:> node:buffer:254> TypedArrayPrototypeSet(target, source, targetStart);> ^>> TypeError: Cannot perform %TypedArray%.prototype.set on a detached ArrayBuffer> at Buffer.set (<anonymous>)> at _copyActual (node:buffer:254:3)> node:buffer:254> TypedArrayPrototypeSet(target, source, targetStart);> ^>> TypeError: Cannot perform %TypedArray%.prototype.set on a detached ArrayBuffer> at Buffer.set (<anonymous>)> at _copyActual (node:buffer:254:3)> at Function.concat (node:buffer:562:12)> at onEnd (.../node_modules/engine.io/build/transports-uws/polling.js:126:32)> at .../node_modules/engine.io/build/transports-uws/polling.js:143:17Note: µWebSockets.js does not currently support chunked transferencoding.
1 parenta463d26 commit3367440

File tree

2 files changed

+104
-13
lines changed

2 files changed

+104
-13
lines changed

‎lib/transports-uws/polling.ts‎

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,20 @@ export class Polling extends Transport {
122122
return;
123123
}
124124

125+
constexpectedContentLength=Number(req.headers["content-length"]);
126+
127+
if(!expectedContentLength){
128+
this.onError("content-length header required");
129+
res.writeStatus("411 Length Required").end();
130+
return;
131+
}
132+
133+
if(expectedContentLength>this.maxHttpBufferSize){
134+
this.onError("payload too large");
135+
res.writeStatus("413 Payload Too Large").end();
136+
return;
137+
}
138+
125139
constisBinary="application/octet-stream"===req.headers["content-type"];
126140

127141
if(isBinary&&this.protocol===4){
@@ -131,11 +145,11 @@ export class Polling extends Transport {
131145
this.dataReq=req;
132146
this.dataRes=res;
133147

134-
letchunks=[];
135-
letcontentLength=0;
148+
letbuffer;
149+
letoffset=0;
136150

137151
constcleanup=()=>{
138-
this.dataReq=this.dataRes=chunks=null;
152+
this.dataReq=this.dataRes=null;
139153
};
140154

141155
constonClose=()=>{
@@ -154,8 +168,8 @@ export class Polling extends Transport {
154168
res.writeHeader(key,String(headers[key]));
155169
});
156170

157-
constonEnd=()=>{
158-
this.onData(Buffer.concat(chunks).toString());
171+
constonEnd=buffer=>{
172+
this.onData(buffer.toString());
159173

160174
if(this.readyState!=="closing"){
161175
res.end("ok");
@@ -165,18 +179,36 @@ export class Polling extends Transport {
165179

166180
res.onAborted(onClose);
167181

168-
res.onData((chunk,isLast)=>{
169-
chunks.push(Buffer.from(chunk));
170-
contentLength+=Buffer.byteLength(chunk);
171-
if(contentLength>this.maxHttpBufferSize){
172-
this.onError("payload too large");
173-
res.writeStatus("413 Payload Too Large");
174-
res.end();
182+
res.onData((arrayBuffer,isLast)=>{
183+
consttotalLength=offset+arrayBuffer.byteLength;
184+
if(totalLength>expectedContentLength){
185+
this.onError("content-length mismatch");
186+
res.close();// calls onAborted
175187
return;
176188
}
189+
190+
if(!buffer){
191+
if(isLast){
192+
onEnd(Buffer.from(arrayBuffer));
193+
return;
194+
}
195+
buffer=Buffer.allocUnsafe(expectedContentLength);
196+
}
197+
198+
Buffer.from(arrayBuffer).copy(buffer,offset);
199+
177200
if(isLast){
178-
onEnd();
201+
if(totalLength!=expectedContentLength){
202+
this.onError("content-length mismatch");
203+
res.writeStatus("400 Content-Length Mismatch").end();
204+
cleanup();
205+
return;
206+
}
207+
onEnd(buffer);
208+
return;
179209
}
210+
211+
offset=totalLength;
180212
});
181213
}
182214

‎test/server.js‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,6 +1955,65 @@ describe("server", () => {
19551955
});
19561956
});
19571957

1958+
it("should arrive when content is split in multiple chunks (polling)",done=>{
1959+
constengine=listen(
1960+
{
1961+
maxHttpBufferSize:1e10
1962+
},
1963+
port=>{
1964+
constclient=newClientSocket(`ws://localhost:${port}`,{
1965+
transports:["polling"]
1966+
});
1967+
1968+
engine.on("connection",socket=>{
1969+
socket.on("message",data=>{
1970+
client.close();
1971+
done();
1972+
});
1973+
});
1974+
1975+
client.on("open",()=>{
1976+
client.send("a".repeat(1e6));
1977+
});
1978+
}
1979+
);
1980+
});
1981+
1982+
it("should arrive when content is sent with chunked transfer-encoding (polling)",function(done){
1983+
if(process.env.EIO_WS_ENGINE==="uws"){
1984+
// µWebSockets.js does not currently support chunked encoding: https://github.com/uNetworking/uWebSockets.js/issues/669
1985+
returnthis.skip();
1986+
}
1987+
constengine=listen(port=>{
1988+
constclient=newClientSocket(`ws://localhost:${port}`,{
1989+
transports:["polling"]
1990+
});
1991+
1992+
engine.on("connection",socket=>{
1993+
socket.on("message",data=>{
1994+
expect(data).to.eql("123");
1995+
1996+
client.close();
1997+
done();
1998+
});
1999+
});
2000+
2001+
client.on("open",()=>{
2002+
constreq=http.request({
2003+
host:"localhost",
2004+
port,
2005+
path:`/engine.io/?EIO=4&transport=polling&sid=${client.id}`,
2006+
method:"POST"
2007+
});
2008+
2009+
req.write(process.env.EIO_CLIENT==="3" ?"4:41" :"41");
2010+
req.write("2");
2011+
req.write("3");
2012+
req.end();
2013+
});
2014+
});
2015+
});
2016+
19582017
it("should arrive as ArrayBuffer if requested when binary data sent as Buffer (polling)",done=>{
19592018
constbinaryData=Buffer.allocUnsafe(5);
19602019
for(leti=0;i<binaryData.length;i++){

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp