creationix/http-parser-js

TypeError: this[kOnHeaders] is not a function

clovnrian opened this issue · 5 comments

Hi,

we start using this package few days ago and we notice this error which appear after some time so it's really hard to debug. We are using it in script which makes 1000s of requests so we are not sure if this is global problem or just problem with specific requests.

Node: v12.19.0
Node arguments: --tls-min-v1.0 --insecure-http-parser --http-parser=legacy --max-http-header-size=80000
http-parser: v0.5.2

TypeError: this[kOnHeaders] is not a function                                                                                     
at HTTPParser.BODY_CHUNKTRAILERS (.../node_modules/http-parser-js/http-parser.js:416:39)
at HTTPParser.execute (../node_modules/http-parser-js/http-parser.js:120:27)              
at TLSSocket.socketOnData (_http_client.js:475:22)                                                                                     
at TLSSocket.emit (events.js:314:20)                                                                                                   
at TLSSocket.EventEmitter.emit (domain.js:483:12)                                                                                     
at addChunk (_stream_readable.js:298:12)                                                                                               
at readableAddChunk (_stream_readable.js:273:9)                                                                                        
at TLSSocket.Readable.push (_stream_readable.js:214:10)                                                                                
at TLSWrap.onStreamRead (internal/stream_base_commons.js:188:23)

I found definition of kOnHeaders function in http-parser.js file.

// Some handler stubs, needed for compatibility
HTTPParser.prototype[kOnHeaders] =
HTTPParser.prototype[kOnHeadersComplete] =
HTTPParser.prototype[kOnBody] =
HTTPParser.prototype[kOnMessageComplete] = function () {};

And nowhere in script is re-written or deleted, so we really have no idea what can cause this issue.

Can you help us?

Those fields are set by certain versions of Node.js (v12 does, I believe) - set here: https://github.com/nodejs/node/blob/v12.x/lib/_http_common.js#L169

I'm not sure why or how it would ever become a non-function, but two things to try to narrow it down: add if (typeof this[kOnHeaders] !== 'function') console.log(this) before the offending line, to see what that field gets set to, and try changing kOnHeaders to be something else (perhaps a string), in case something, somewhere is smashing parser[0] for some reason (though, I'm not sure if something else somewhere assumes this is always 0 because the native parser uses 0, so that might just immediately explode ^_^).

Hi @Jimbly and thanks for prompt response. I did what you suggest and here is what I found. It's not complete log, because it has more than 1000 rows.

I can see the HTTPParser[0] === null which should be the kOnHeaders function, but I can't understand why and where is this changed.

HTTPParser {
  '0': null,
  '1': [Function: parserOnHeadersComplete],
  '2': [Function: parserOnBody],
  '3': [Function: parserOnMessageComplete],
  '4': null,
  incoming: IncomingMessage {
    httpVersionMajor: 1,
    httpVersionMinor: 1,
    httpVersion: '1.1',
    complete: false,
    headers: {
      date: 'Wed, 16 Dec 2020 11:10:58 GMT',
      'x-powered-by': 'Servlet/3.0',
      'content-type': 'text/xml',
      'content-language': 'es-MX',
      expires: 'Thu, 01 Dec 1994 16:00:00 GMT',
      'cache-control': 'no-cache="set-cookie, set-cookie2"',
      'set-cookie': [Array],
      'access-control-allow-origin': '*',
      connection: 'close',
      'transfer-encoding': 'chunked'
    },
    rawHeaders: [
      'Date',
      'Wed, 16 Dec 2020 11:10:58 GMT',
      'X-Powered-By',
      'Servlet/3.0',
      'Content-Type',
      'text/xml',
      'Content-Language',
      'es-MX',
      'Expires',
      'Thu, 01 Dec 1994 16:00:00 GMT',
      'Cache-Control',
      'no-cache="set-cookie, set-cookie2"',
      'Set-Cookie',
      'dtCookie=|X2RlZmF1bHR8MA; Path=/; Domain=.segurosafirme.com.mx',
      'Access-Control-Allow-Origin',
      '*',
      'Connection',
      'close',
      'Transfer-Encoding',
      'chunked'
    ],
    trailers: {},
    rawTrailers: [],
    aborted: false,
    upgrade: false,
    url: '',
    method: null,
    statusCode: 200,
    statusMessage: 'OK',
  }
  maxHeaderPairs: 2000,
  _consumed: false,
  onIncoming: [Function: parserOnIncomingClient],
  type: 'RESPONSE',
  state: 'BODY_CHUNKTRAILERS',
  info: {
    headers: [
      'Date',
      'Wed, 16 Dec 2020 11:10:58 GMT',
      'X-Powered-By',
      'Servlet/3.0',
      'Content-Type',
      'text/xml',
      'Content-Language',
      'es-MX',
      'Expires',
      'Thu, 01 Dec 1994 16:00:00 GMT',
      'Cache-Control',
      'no-cache="set-cookie, set-cookie2"',
      'Set-Cookie',
      'dtCookie=|X2RlZmF1bHR8MA; Path=/; Domain=.segurosafirme.com.mx',
      'Access-Control-Allow-Origin',
      '*',
      'Connection',
      'close',
      'Transfer-Encoding',
      'chunked'
    ],
    upgrade: false,
    versionMajor: 1,
    versionMinor: 1,
    statusCode: 200,
    statusMessage: 'OK',
    shouldKeepAlive: false
  },
  trailers: [
    'Date',
    'Wed, 16 Dec 2020 11:10:58 GMT',
    'X-Powered-By',
    'Servlet/3.0',
    'Content-Type',
    'text/xml',
    'Content-Language',
    'es-MX',
    'Expires',
    'Thu, 01 Dec 1994 16:00:00 GMT',
    'Cache-Control',
    'no-cache="set-cookie, set-cookie2"',
    'Set-Cookie',
    'dtCookie=|X2RlZmF1bHR8MA; Path=/; Domain=.segurosafirme.com.mx',
    'Access-Control-Allow-Origin',
    '*',
    'Connection',
    'close',
    'Transfer-Encoding',
    'chunked'
  ],
  line: '',
  isChunked: true,
  connection: 'close',
  headerSize: 0,
  body_bytes: NaN,
  isUserCall: false,
  hadError: false,

That is strange! Can try changing kOnHeaders to something other than 0 to rule out whether it's something accidentally stepping on [0] or something specific going wrong, or can perhaps just assert when the offending change happens by adding something like this to the end of http-parser.js:

Object.defineProperty(HTTPParser.prototype, '0', {
  get: function () {
    return this.on0;
  },
  set: function (to) {
    assert(to !== null);
    return (this.on0 = to);
  }
});

Hi! I think this is now resolved, there were multiple fields that were resolving to 0 (kOnTimeout was added in a newer Node version), and they should no longer conflict.

Thanks for quick resolve.