nodeca / probe-image-size

Get image size without full download. Supported image types: JPG, GIF, PNG, WebP, BMP, TIFF, SVG, PSD, ICO.
MIT License
978 stars 77 forks source link

ERR_STREAM_PUSH_AFTER_EOF in probe-image-size/lib/parse_stream/svg.js:163:20 #52

Closed misos1 closed 3 years ago

misos1 commented 3 years ago

Test case (test.js):

let probe = require("probe-image-size");
let Promise = require("bluebird");
let axios = require("axios");
let server = require("express")();

server.post("/probe", async function(req, res)
{
    await new Promise(resolve => setImmediate(resolve));
    await probe(req);
    res.end();
});

let request = axios.create({ baseURL: "http://127.0.0.1:8888", validateStatus: null, maxRedirects: 0 });

let svg = `<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100pt" height="100pt" viewBox="0 0 100 100" version="1.1">`;
for(let i = 0; i < 100000; i++) svg += " ";

async function main()
{
    await new Promise(resolve => server.listen(8888, resolve));
    while(true) await request.post("/probe", svg).catch(() => {});
}

main();

Install and run (it may take some time):

npm install probe-image-size bluebird axios express
node test.js

Possible output:

events.js:292
      throw er; // Unhandled 'error' event
      ^

Error [ERR_STREAM_PUSH_AFTER_EOF]: stream.push() after EOF
    at readableAddChunk (internal/streams/readable.js:272:30)
    at Transform.Readable.push (internal/streams/readable.js:223:10)
    at Transform.push (internal/streams/transform.js:166:32)
    at Transform.transform [as _transform] (.../node_modules/probe-image-size/lib/parse_stream/svg.js:163:20)
    at Transform._read (internal/streams/transform.js:205:10)
    at Transform._write (internal/streams/transform.js:193:12)
    at writeOrBuffer (internal/streams/writable.js:358:12)
    at Transform.Writable.write (internal/streams/writable.js:303:10)
    at PassThrough.ondata (internal/streams/readable.js:719:22)
    at PassThrough.emit (events.js:327:22)
    at addChunk (internal/streams/readable.js:309:12)
    at readableAddChunk (internal/streams/readable.js:284:9)
    at PassThrough.Readable.push (internal/streams/readable.js:223:10)
    at PassThrough.Transform.push (internal/streams/transform.js:166:32)
    at PassThrough.afterTransform (internal/streams/transform.js:101:10)
    at PassThrough._transform (internal/streams/passthrough.js:46:3)
Emitted 'error' event on Transform instance at:
    at emitErrorNT (internal/streams/destroy.js:106:8)
    at emitErrorCloseNT (internal/streams/destroy.js:74:3)
    at processTicksAndRejections (internal/process/task_queues.js:80:21) {
  code: 'ERR_STREAM_PUSH_AFTER_EOF'
}
puzrin commented 3 years ago

Please, provide details how to reproduce.

misos1 commented 3 years ago

Yes, I am trying to produce some minimal test case but maybe I hoped that there is something obvious. Till now seems it does not happen for example with heic.

puzrin commented 3 years ago

It's not obvious, sorry. Example needed.

misos1 commented 3 years ago

@puzrin I updated it with example. Sorry for those additional dependencies (they may make the right timing or so).

misos1 commented 3 years ago

Maybe the problem is that it will not change state to STATE_IGNORE right after it gets results? https://github.com/nodeca/probe-image-size/blob/master/lib/parse_stream/svg.js#L157-L175

misos1 commented 3 years ago

Looking at it and realising that writing null to object stream ends it - it is actually pretty obvious and posted callstack directly blames line 163.

Simplified test case:

let { PassThrough } = require("stream");
let probe = require("probe-image-size");

let stm = new PassThrough();
probe(stm);
stm.write(`<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100pt" height="100pt" viewBox="0 0 100 100" version="1.1">`);
stm.write(" ");