Skip to content

Commit 4951bff

Browse files
committed
support stream resets through user events
1 parent 170f4ca commit 4951bff

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

Sources/NIOHTTP2/HTTP2StreamChannel.swift

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,10 @@ final class HTTP2StreamChannel: Channel, ChannelCore, @unchecked Sendable {
605605
}
606606

607607
public func close0(error: Error, mode: CloseMode, promise: EventLoopPromise<Void>?) {
608+
self.closeWithCode(code: .cancel, promise: promise)
609+
}
610+
611+
func closeWithCode(code: HTTP2ErrorCode, promise: EventLoopPromise<Void>?) {
608612
// If the stream is already closed, we can fail this early and abort processing. If it's not, we need to emit a
609613
// RST_STREAM frame.
610614
guard self.state != .closed else {
@@ -627,12 +631,17 @@ final class HTTP2StreamChannel: Channel, ChannelCore, @unchecked Sendable {
627631
self.closedCleanly()
628632
case .remoteActive, .active, .closing, .closingNeverActivated:
629633
// In all of these states the stream is still on the network and we need to wait.
630-
self.closedWhileOpen()
634+
self.closedWhileOpen(code: code)
631635
}
632636
}
633637

634638
public func triggerUserOutboundEvent0(_ event: Any, promise: EventLoopPromise<Void>?) {
635-
// do nothing
639+
switch event {
640+
case .reset(let code) as HTTP2StreamChannelEvent:
641+
self.closeWithCode(code: code, promise: promise)
642+
default:
643+
break
644+
}
636645
}
637646

638647
public func channelRead0(_ data: NIOAny) {
@@ -647,7 +656,7 @@ final class HTTP2StreamChannel: Channel, ChannelCore, @unchecked Sendable {
647656
///
648657
/// Will emit a RST_STREAM frame in order to close the stream. Note that this function does not
649658
/// directly close the stream: it waits until the stream closed notification is fired.
650-
private func closedWhileOpen() {
659+
private func closedWhileOpen(code: HTTP2ErrorCode = .cancel) {
651660
precondition(self.state != .closed)
652661
guard self.state != .closing else {
653662
// If we're already closing, nothing to do here.
@@ -656,7 +665,7 @@ final class HTTP2StreamChannel: Channel, ChannelCore, @unchecked Sendable {
656665

657666
self.modifyingState { $0.beginClosing() }
658667
// We should have a stream ID here, force-unwrap is safe.
659-
let resetFrame = HTTP2Frame(streamID: self.streamID!, payload: .rstStream(.cancel))
668+
let resetFrame = HTTP2Frame(streamID: self.streamID!, payload: .rstStream(code))
660669
self.receiveOutboundFrame(resetFrame, promise: nil)
661670
self.multiplexer.flushStream(self.streamID!)
662671
}
@@ -998,3 +1007,9 @@ extension HTTP2StreamChannel {
9981007
SynchronousOptions(channel: self)
9991008
}
10001009
}
1010+
1011+
/// Events that can be sent by the application to be handled by the `HTTP2StreamChannel`
1012+
public enum HTTP2StreamChannelEvent {
1013+
/// Send a `RST_STREAM` with the specified code
1014+
case reset(HTTP2ErrorCode)
1015+
}

0 commit comments

Comments
 (0)