镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

http2: client browser refresh crashing the server. #15385

Description

@akc42

This is with version 8.5.0 of node.

I have a situation where as the browser window is closing (or refreshing!) it sends a last ditch attempt to release locks that the user may hold. There is an api function for this which when it has completed calls response.end('{}') (I have a convention that all api calls should return a valid json object even if its a null object).

I catch unhandled rejections and print the error stack, along with what url is being processed at the time. The url is a red herring (its a call several milliseconds into the new browser window starting up), but the error is real.

My server falls over with

 Unhandled Rejection: Error [ERR_HTTP2_STREAM_CLOSED]: The stream is already closed
    at Http2ServerResponse.write (internal/http2/compat.js:456:19)
    at Http2ServerResponse.end (internal/http2/compat.js:479:12)
    at API.module.exports (/home/alan/dev/pasv5/server/api/release_lock.js:32:14)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
          Request in Progress At time of Rejection:
            url:/src/pas-notify.html
            body:undefined

What I believe is happening is the api call gets through, takes a while to make a database call to release the locks, and then tries to send the response.end(), by which time the original stream (and maybe even the session) have disappeared.

I would have expected from the new compatability api docs that request would have fired an 'aborted' event at some point before this happens, but I log those and nothing happened.

Looking at the compat code, I can see the error would not have thrown if a callback had been provided to response.write(), but as is indicated in the stack this is called from response.end() where no callback is passed through. Regardless of this issue I do have an on('error') listener on the response. and that wasn't fired either. Should the error be sent there?

Activity

  1. ronag commented on Sep 13, 2017

    @ronag
    Member

    Related #15387?

  2. added
    http2Issues and PRs related to the http2 subsystem.
    on Sep 13, 2017
  3. apapirovski commented on Sep 13, 2017

    @apapirovski
    Contributor

    @akc42 Thanks for the report! Any chance you could post a reduced code sample that illustrates this? Also, I know you were previously able to build from master and test that. Could you do it for this error? I believe that this behaviour might've changed in c981483 (which didn't make it into 8.5.0)

  4. jasnell commented on Sep 13, 2017

    @jasnell
    Member
  5. akc42 commented on Sep 14, 2017

    @akc42
    Author

    @apapirovski https://github.com/akc42/simple-server.git shows this, and I also built against yesterdays master and tried that, but no difference

  6. apapirovski commented on Sep 14, 2017

    @apapirovski
    Contributor

    Thanks so much! As far as I can tell, comparing to http, we should not be throwing in this situation at all — it should just return false to match http.

    @mcollina Do you see any reason that in Http2ServerResponse.end we wouldn't swap the order of these two statements to match the http behaviour? (We would also need to check for stream.finished in addition to stream === undefined.)

    if (chunk !== null && chunk !== undefined) {
      this.write(chunk, encoding);
    }
    
    if (stream === undefined) {
      return;
    }
  7. apapirovski commented on Sep 14, 2017

    @apapirovski
    Contributor

    @akc42 I'm still looking at why it actually closes the stream, that bit seems weird.

  8. apapirovski commented on Sep 14, 2017

    @apapirovski
    Contributor

    Ignore the comment above, the stream being closed made complete sense since the client aborted the request. It looks to me like you're listening to abort rather than aborted which explains why it's not logging. When I switched it to aborted it works as expected.

    I'll get started on a PR to fix the incorrect end behaviour though as it doesn't match the http module.

    Let me know if any of this doesn't line up for you though, @akc42.

  9. akc42 commented on Sep 14, 2017

    @akc42
    Author

    @apapirovski I was half way responding when you made your posts

    I presume what you are saying is that I'll get an 'aborted' event on the request and then response.end doesn't fail but silently returns. That is good for me. BUT according to the docs - there should have been a 'close' event on the response which I didn't get. I assume that should have happened at the same time the aborted event was thrown.

  10. apapirovski commented on Sep 14, 2017

    @apapirovski
    Contributor

    Ah, yea I see what you mean. It doesn't look this was ever working for http2. Working on a PR.

  11. akc42 commented on Sep 18, 2017

    @akc42
    Author

    This shouldn't really be closed until #15415 is

  12. mcollina commented on Sep 18, 2017

    @mcollina
    SponsorMember

    Fixed in 8fa5fcc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    http2Issues and PRs related to the http2 subsystem.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions