-
Notifications
You must be signed in to change notification settings - Fork 10.1k
Closed
Description
You want to:
- report a bug
- request a feature
Current behaviour
Application crashes with a ECONNRESET when an HTTP/2 upgrade is attempted (and uncleanly aborted) to a socket on which Socket.IO is listening. Output:
root@host:~# node /usr/lib/node_modules/mymodule/server.py
server listening on port 3000
events.js:174
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
Emitted 'error' event at:
at emitErrorNT (internal/streams/destroy.js:91:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
at process._tickCallback (internal/process/next_tick.js:63:19)
Steps to reproduce (if the current behaviour is a bug)
- Start this server: https://github.com/chris-laplante/socket.io-fiddle/blob/master/server.js
- Execute this Python script on a different machine (updating the SERVER_IP variable appropriately):
import socket
import struct
SERVER_IP = "1.2.3.4"
def crash():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.connect((SERVER_IP, 3000))
l_onoff = 1
l_linger = 0
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", l_onoff, l_linger))
# Sending the upgrade header will cause the server to crash
message = b"HEAD / HTTP/1.1\r\nconnection: Upgrade, HTTP2-Settings\r\nupgrade: h2c\r\nhttp2-settings: AAMAAABkAAQAAP__\r\nHost: www.example.com\r\n\r\n"
# Sending a normal HEAD without upgrade header won't crash
#message = b"HEAD / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
s.send(message)
print(s.recv(1000).decode())
s.close()
if __name__ == "__main__":
crash()
Expected behaviour
One of the "error" handlers fires. At the very least, the server doesn't crash.
Setup
- OS: Linux 4.9.0
- browser: N/A
- socket.io version: 2.3.0
- Node: v10.16.3
Other information (e.g. stacktraces, related issues, suggestions how to fix)
Output when running the server with NODE_DEBUG="net,http" is below:
root@host:~# NODE_DEBUG="net,http" node /usr/lib/node_modules/mymodule/server.py
NET 9054: setupListenHandle null 3000 4 0 undefined
NET 9054: setupListenHandle: create a handle
NET 9054: bind to ::
server listening on port 3000
NET 9054: onconnection
NET 9054: _read
NET 9054: Socket._read readStart
HTTP 9054: SERVER new http connection
HTTP 9054: SERVER socketOnParserExecute 127
HTTP 9054: SERVER upgrade or connect HEAD
HTTP 9054: SERVER have listener for upgrade
NET 9054: _final: not ended, call shutdown()
NET 9054: afterShutdown destroyed=false ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: null,
ended: false,
endEmitted: false,
reading: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
paused: false,
emitClose: false,
autoDestroy: false,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null }
NET 9054: destroy
NET 9054: close
NET 9054: close handle
NET 9054: has server
NET 9054: SERVER _emitCloseIfDrained
NET 9054: SERVER handle? true connections? 0
events.js:174
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
Emitted 'error' event at:
at emitErrorNT (internal/streams/destroy.js:91:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
at process._tickCallback (internal/process/next_tick.js:63:19)
I have also tried wrapping the application in a domain and catching all 'error' events, then printing them out. The output looks something like this:
NET 13095: onconnection
NET 13095: _read
NET 13095: Socket._read readStart
HTTP 13095: SERVER new http connection
HTTP 13095: SERVER socketOnParserExecute 126
HTTP 13095: SERVER upgrade or connect HEAD
HTTP 13095: SERVER have listener for upgrade
NET 13095: _final: not ended, call shutdown()
NET 13095: afterShutdown destroyed=false ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: null,
ended: false,
endEmitted: false,
reading: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
paused: false,
emitClose: false,
autoDestroy: false,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null }
NET 13095: destroy
NET 13095: close
NET 13095: close handle
NET 13095: has server
NET 13095: SERVER _emitCloseIfDrained
NET 13095: SERVER handle? true connections? 0
{ Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
---------------------------------------------
at Object.<anonymous> (/usr/lib/node_modules/mymodule/server2.py:15:4)
at Module._compile (internal/modules/cjs/loader.js:778:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
errno: 'ECONNRESET',
code: 'ECONNRESET',
syscall: 'read',
domainEmitter:
Socket {
connecting: false,
_hadError: false,
_handle: null,
_parent: null,
_host: null,
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: null,
ended: false,
endEmitted: false,
reading: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
paused: false,
emitClose: false,
autoDestroy: false,
destroyed: true,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: false,
domain:
Domain {
domain: null,
_events: [Object],
_eventsCount: 3,
_maxListeners: undefined,
members: [],
[Symbol(kWeak)]: WeakReference {} },
_events:
[Object: null prototype] { end: [Function], timeout: [Function] },
_eventsCount: 2,
_maxListeners: undefined,
_writableState:
WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: true,
needDrain: false,
ending: true,
ended: true,
finished: true,
destroyed: true,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
bufferedRequest: null,
lastBufferedRequest: null,
pendingcb: 0,
prefinished: true,
errorEmitted: true,
emitClose: false,
autoDestroy: false,
bufferedRequestCount: 0,
corkedRequestsFree: [Object] },
writable: false,
allowHalfOpen: true,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server:
Server {
domain: [Domain],
_events: [Object],
_eventsCount: 5,
_maxListeners: undefined,
_connections: 0,
_handle: [TCP],
_usingWorkers: false,
_workers: [],
_unref: false,
allowHalfOpen: true,
pauseOnConnect: false,
httpAllowHalfOpen: false,
timeout: 120000,
keepAliveTimeout: 5000,
maxHeadersCount: null,
headersTimeout: 40000,
_connectionKey: '6::::3000',
[Symbol(IncomingMessage)]: [Function],
[Symbol(ServerResponse)]: [Function],
[Symbol(asyncId)]: 8 },
_server:
Server {
domain: [Domain],
_events: [Object],
_eventsCount: 5,
_maxListeners: undefined,
_connections: 0,
_handle: [TCP],
_usingWorkers: false,
_workers: [],
_unref: false,
allowHalfOpen: true,
pauseOnConnect: false,
httpAllowHalfOpen: false,
timeout: 120000,
keepAliveTimeout: 5000,
maxHeadersCount: null,
headersTimeout: 40000,
_connectionKey: '6::::3000',
[Symbol(IncomingMessage)]: [Function],
[Symbol(ServerResponse)]: [Function],
[Symbol(asyncId)]: 8 },
timeout: 120000,
parser: null,
on: [Function: socketOnWrap],
_paused: false,
[Symbol(asyncId)]: 78,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]:
Timeout {
_called: false,
_idleTimeout: -1,
_idlePrev: null,
_idleNext: null,
_idleStart: 167139,
_onTimeout: null,
_timerArgs: undefined,
_repeat: null,
_destroyed: true,
domain: [Domain],
[Symbol(unrefed)]: true,
[Symbol(asyncId)]: 83,
[Symbol(triggerId)]: 78 },
[Symbol(kBytesRead)]: 126,
[Symbol(kBytesWritten)]: 0 },
domain:
Domain {
domain: null,
_events:
[Object: null prototype] {
removeListener: [Function],
newListener: [Function],
error: [Function] },
_eventsCount: 3,
_maxListeners: undefined,
members: [],
[Symbol(kWeak)]: WeakReference {} },
domainThrown: false }
Metadata
Metadata
Assignees
Labels
No labels