-
Notifications
You must be signed in to change notification settings - Fork 120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix crash for large HTTP request headers #661
Changes from 17 commits
0aecc2b
c43bccc
fb64416
cb026ca
a7f64d4
3f8f55f
efa86b5
38b3bf0
8ad3d8a
c9a2814
5fb70dc
183f75e
9603f98
7d96a89
1ddafda
55849b5
31cc312
18f6505
247928a
7fcecdf
43ebc95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -183,9 +183,19 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler { | |
|
||
private func run(_ action: HTTP1ConnectionStateMachine.Action, context: ChannelHandlerContext) { | ||
switch action { | ||
case .sendRequestHead(let head, startBody: let startBody): | ||
self.sendRequestHead(head, startBody: startBody, context: context) | ||
case .sendRequestHead(let head, let sendEnd): | ||
self.sendRequestHead(head, sendEnd: sendEnd, context: context) | ||
case .notifyRequestHeadSendSuccessfully(let resumeRequestBodyStream, let startIdleTimer): | ||
|
||
self.request!.requestHeadSent() | ||
if resumeRequestBodyStream { | ||
self.request!.resumeRequestBodyStream() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Relatedly, why is this safe? Can it end up There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great catch! This is not safe. I added a test which crashed previously bit is fixed by chaining the implantation to unwrap safely: 18f6505 |
||
} | ||
if startIdleTimer { | ||
if let timeoutAction = self.idleReadTimeoutStateMachine?.requestEndSent() { | ||
self.runTimeoutAction(timeoutAction, context: context) | ||
} | ||
} | ||
case .sendBodyPart(let part, let writePromise): | ||
context.writeAndFlush(self.wrapOutboundOut(.body(part)), promise: writePromise) | ||
|
||
|
@@ -320,32 +330,15 @@ final class HTTP1ClientChannelHandler: ChannelDuplexHandler { | |
} | ||
} | ||
|
||
private func sendRequestHead(_ head: HTTPRequestHead, startBody: Bool, context: ChannelHandlerContext) { | ||
if startBody { | ||
context.writeAndFlush(self.wrapOutboundOut(.head(head)), promise: nil) | ||
|
||
// The above write might trigger an error, which may lead to a call to `errorCaught`, | ||
// which in turn, may fail the request and pop it from the handler. For this reason | ||
// we must check if the request is still present here. | ||
guard let request = self.request else { return } | ||
request.requestHeadSent() | ||
|
||
request.resumeRequestBodyStream() | ||
} else { | ||
private func sendRequestHead(_ head: HTTPRequestHead, sendEnd: Bool, context: ChannelHandlerContext) { | ||
if sendEnd { | ||
context.write(self.wrapOutboundOut(.head(head)), promise: nil) | ||
context.write(self.wrapOutboundOut(.end(nil)), promise: nil) | ||
context.flush() | ||
|
||
// The above write might trigger an error, which may lead to a call to `errorCaught`, | ||
// which in turn, may fail the request and pop it from the handler. For this reason | ||
// we must check if the request is still present here. | ||
guard let request = self.request else { return } | ||
request.requestHeadSent() | ||
|
||
if let timeoutAction = self.idleReadTimeoutStateMachine?.requestEndSent() { | ||
self.runTimeoutAction(timeoutAction, context: context) | ||
} | ||
} else { | ||
context.writeAndFlush(self.wrapOutboundOut(.head(head)), promise: nil) | ||
} | ||
self.run(self.state.headSent(), context: context) | ||
} | ||
|
||
private func runTimeoutAction(_ action: IdleReadStateMachine.Action, context: ChannelHandlerContext) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this force-unwrap safe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment