Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

fix errors received when holding messages in HTTPServerPipelineHandler #314

Merged
merged 1 commit into from
Apr 16, 2018

Conversation

weissi
Copy link
Member

@weissi weissi commented Apr 14, 2018

Motivation:

We had a bug which is happens in the combination of these states:

  • we held a request in the pipelining handler (because we're procesing a
    previous one)
  • a http handler error happened whilst a response's .head had already
    been sent (but not yet the .end)
  • the HTTPServerProtocolErrors handler is in use

That would lead to this situation:

  • the error isn't held by the pipelining handler
  • the error handler then just sends a full response (.head and .end)
    but the actual http server already send a .head. So all in all, we
    sent .head, .head, .end which is illegal
  • the pipelining handler didn't notice this and beause it saw an .end
    it would send through the next requst
  • now the http server handler is in the situation that it gets .head,
    .head too (which is illegal)

Modifications:

  • hold HTTP errors in the pipelining handler too

Result:

  • more correctness

@weissi weissi requested review from Lukasa and normanmaurer April 14, 2018 12:05
@weissi weissi force-pushed the jw-error-when-pipelining branch from cc9fd17 to e8c1629 Compare April 14, 2018 12:09
ctx.fireErrorCaught(error)
return
}
self.eventBuffer.append(.error(httpError))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn’t right: if we’re not expecting a response this will never unbuffer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agree. I wasn’t quite so sure how exactly we want to handle this situation so I didn’t really want to write all the code&tests. We should discuss and then I’ll implement it in this pr if that works for you.
So do you think we should generally buffer the http errors and deliver them as soon as we can in a way that’s semantically similar to having received one request after the other? I think that’s probably best.
Said that the server protocol error handler will probably still need to become and outbound handler to see if the response has started already, right?

@Lukasa
Copy link
Contributor

Lukasa commented Apr 14, 2018

Generally fine with this approach, just left a correctness note.

_ = ctx.eventLoop.scheduleTask(in: .seconds(10) /* that'll never actually execute */) {
XCTAssertEqual(.none, self.nextExpected)
self.nextExpected = .head
ctx.writeAndFlush(self.wrapOutboundOut(HTTPServerResponsePart.end(nil)), promise: nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this will never execute, shouldn't this XCTFail instead of having production code in it?

try channel.writeInbound(buffer)
try channel.close().wait()
} catch HTTPParserError.invalidContentLength {
// This error is expected
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you're hitting this error? Because I don't think you are. 😁

Copy link
Member Author

@weissi weissi Apr 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 deffo not, probably too much copy and paste

Motivation:

We had a bug which is happens in the combination of these states:
- we held a request in the pipelining handler (because we're procesing a
  previous one)
- a http handler error happened whilst a response's `.head` had already
  been sent (but not yet the `.end`)
- the HTTPServerProtocolErrors handler is in use

That would lead to this situation:
- the error isn't held by the pipelining handler
- the error handler then just sends a full response (`.head` and `.end`)
  but the actual http server already send a `.head`. So all in all, we
  sent `.head`, `.head`, `.end` which is illegal
- the pipelining handler didn't notice this and beause it saw an `.end`
  it would send through the next requst
- now the http server handler is in the situation that it gets `.head`,
  `.head` too (which is illegal)

Modifications:

- hold HTTP errors in the pipelining handler too

Result:

- more correctness
@weissi weissi force-pushed the jw-error-when-pipelining branch from 8ebcaed to 274a203 Compare April 16, 2018 11:32
Copy link
Contributor

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Merge when ready.

@weissi weissi merged commit dc0d731 into apple:master Apr 16, 2018
@weissi weissi deleted the jw-error-when-pipelining branch April 16, 2018 14:13
@Lukasa Lukasa added the 🆕 semver/minor Adds new public API. label Apr 19, 2018
@Lukasa Lukasa added this to the 1.5.0 milestone Apr 19, 2018
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
🆕 semver/minor Adds new public API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants