nwtgck / piping-server

Infinitely transfer between every device over pure HTTP with pipes or browsers
MIT License
2.91k stars 153 forks source link

Error when trying to pipe large binary file #929

Open Sov3rain opened 4 months ago

Sov3rain commented 4 months ago

Hi there,

I'm getting an error when trying to pipe a binary file (a 3D model in .glb). Here is the server error:

[ERROR] default - on uncaughtException Error [ERR_STREAM_WRITE_AFTER_END]: write after end
at new NodeError (node:internal/errors:405:5)
at ServerResponse.end (node:_http_outgoing:1017:15)
at PassThrough.<anonymous> (/app/dist/src/piping.js:315:40)
at PassThrough.emit (node:events:514:28)
at errorEventQueue (/app/node_modules/multiparty/index.js:645:18)
at handleError (/app/node_modules/multiparty/index.js:211:9)
at IncomingMessage.onReqAborted (/app/node_modules/multiparty/index.js:197:5)
at IncomingMessage.emit (node:events:514:28)
at IncomingMessage._destroy (node:_http_incoming:224:10)
at _destroy (node:internal/streams/destroy:109:10) {
code: 'ERR_STREAM_WRITE_AFTER_END'
}

The file is 47 MB.

What I'm doing to get there:

Let me know if you need more details.

Environment: Deployed from the Dockerfile on Railway.app

Sov3rain commented 4 months ago

From what I understand from this, it seems like the response is closed too early. Is that correct?

EDIT: related to #261 ?

nwtgck commented 1 month ago

I have the same error, but I could not reproduce it 100% yet. I will continue to investigate.

Sov3rain commented 1 month ago

Yeah, same here, the issue is not 100% reproductible.

nwtgck commented 1 month ago

I've found a 100% reproducible case.

A sender uses HTTP/1.1 over TLS and a receiver uses plain HTTP/1.1.

# sender
curl -T- --http1.1 -k https://localhost:8443/mydata
# receiver
curl http://localhost:8080/mydata

Close the receiver by Ctrl-C during transferring and the server emits the following error:

[ERROR] default - on uncaughtException Error [ERR_STREAM_WRITE_AFTER_END]: write after end
    at write_ (node:_http_outgoing:911:11)
    at ServerResponse.write (node:_http_outgoing:864:15)
    at abortedListener (/app/dist/src/piping.js:234:44)
    at IncomingMessage.<anonymous> (/app/dist/src/piping.js:292:21)
    at IncomingMessage.emit (node:events:519:28)
    at emitErrorNT (node:internal/streams/destroy:169:8)
    at emitErrorCloseNT (node:internal/streams/destroy:128:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'ERR_STREAM_WRITE_AFTER_END'
}

edit: The following case also reproduced the issue.

nwtgck commented 1 month ago

I assume your receiver closed for some reason and the server emitted the error. I'm still not sure why the server behaves differently in plain HTTP/1.1 and HTTP/1.1 over TLS.

Sov3rain commented 1 month ago

I'll be honest here, I've got no idea how to verify what protocol is used. I use a piping server exclusively on the frontend, to pass large 3D models from desktop to mobile and view them in a 3D viewer.

Nothing fancy, just fetch calls.

nwtgck commented 1 month ago

What are your HTTP clients? Google Chrome?


If you are intereseted in what protocol is used and the frontend is a browser, try the following steps.

Open a browser (like Chrome) and click F12 for DevTools.

image

Go to the Network tab as follows.

image

Reload the page.

image

Left click the bar with "Name", "Type", "Initiator"... and check "Protocol" as follows.

image

If "Protocol" is "h2", HTTP/2 is used.

If http/1.1 is shown, HTTP/1.1 is used.

image
Sov3rain commented 1 month ago

Thanks for the quick tutorial! I'll make sure to test it out when i'm able to somewhat repro the issue.

I'm using Brave browser, which is a Chromium based browser. Brave Shields disabled (adblockers and such).