Skip to content

RST packet instead of a FIN packet to close the response on Heroku #3480

@jmorrell

Description

@jmorrell

Are you sure this is an issue with hapi or are you just looking for some help?

Everything points to this being an error in hapi (or perhaps Node streams), but I've not yet been able to reproduce it outside of Heroku's environment.

What are you trying to achieve or the steps to reproduce?

One of our clients came to us experiencing many H18 errors with their Hapi app in production. They kindly created a minimal example of the issue, which is a Hapi hello-world server: https://github.com/kimmobrunfeldt/heroku-hapi-503-bug You can deploy this to Heroku to try it yourself with one click.

To trigger the error you can curl the service with a small data payload:

curl -d'a' https://heroku-hapi-503-bug.herokuapp.com

What was the result you received?

About 30% of the time this will work as expected, and about 70% of the time this will result in a 503 error. Weird.

Concerned that this was a bug in our router I escalated this to our Platform team. One thing that immediately jumped out was that attaching strace to the Node instance immediately resolved the issue producing only 404s. Tricky.

tcpdump

So we ran tcpdump on the response generated by the application.

Here's what's happening during a 503:

68747470733a2f2f646c2e64726f70626f7875736572636f6e74656e742e636f6d2f732f6167323271326c70386b62703479712f323031372d30342d30362532306174253230322e3436253230504d2e706e67

Compared to what happens during a 404:

68747470733a2f2f646c2e64726f70626f7875736572636f6e74656e742e636f6d2f732f666e6e77363635636262667a3279772f323031372d30342d30362532306174253230322e3436253230504d253230253238312532392e706e67

The server sends a RST packet instead of a FIN packet to close the response

Full packet capture is available here: 462013.pcap.zip

streams

Playing around with the internals, I ended up making the problem go away by modifying lib/transmit.js https://github.com/hapijs/hapi/blob/master/lib/transmit.js#L298 by adding an additional stream that did nothing more than pipe the data along:

const through = require('through');

const donothing = through(
  function (data) {
    this.emit('data', data);
  },
  function () {
    this.emit('end');
  }
);
    const tap = response._tap();
    const preview = (tap ? source.pipe(tap) : source);
    const compressed = (compressor ? preview.pipe(compressor) : preview);
    const ranged = (ranger ? compressed.pipe(ranger) : compressed);
    ranged.pipe(donothing).pipe(request.raw.res);

Though I'm unsure of what the implications of that are.

git bisect

Finally, I realized that even if we don't understand the underlying cause, we have a reproducible test case. I tested an older version of Hapi that did not suffer from the same issue and created a git bisect script to narrow down when this might have been introduced: https://github.com/jmorrell/heroku-hapi-H18-bisect

This points to this commit as the one that introduced this odd behavior.

98d34046392006540b64a799b6ca58150d08df2c is the first bad commit
commit 98d34046392006540b64a799b6ca58150d08df2c
Author: Eran Hammer <[email protected]>
Date:   Mon Oct 26 00:49:23 2015 -0700

    Skip most lifecycle on not found and bad path. Closes #2867

:100755 100755 1cd1680739ce6bf95b76abe496e26534d094beaa 2decb33f2a69bb7d22862c6c5b54fef83c437e21 M      API.md
:040000 040000 87075a6a7a8ab1d85b4b4d259ce14a2b16870dab 481e5da93ba66490cc62ca1fc242d6f153daa701 M      lib
:040000 040000 84db0ba536bb4f4e8290b5c29ce88d7f6ce1c1c7 00ed8d03c69ce0759262669c81c882dc1c20d890 M      test
bisect run success

Context

  • node version: 7.9.0
  • hapi version: Many affected
  • os:
~ $ uname -a
Linux 3d243743-fcf2-4103-8c24-72657c71ef36 3.13.0-112-generic #159-Ubuntu SMP Fri Mar 3 15:26:07 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Metadata

Metadata

Assignees

Labels

bugBug or defect

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions