suppose i have an HTTP listener that accumulates a
class Listener:ChannelInboundHandler, RemovableChannelHandler
typealias InboundIn = HTTPServerRequestPart
typealias OutboundOut = HTTPServerResponsePart
var request:(head:HTTPRequestHead, stream:[ByteBuffer])?
func channelRead(context:ChannelHandlerContext, data:NIOAny)
case .body(let buffer):
if case (let head, var body)? = self.request
self.request = nil
self.request = (head, body)
but then it occurred to me that SwiftNIO might be reusing the same
ByteBuffer for multiple HTTP request fragments, and that holding onto copies of them might trigger copy-on-write. what is the best way to receive an HTTP payload, assuming we are waiting to encounter the
end segment before using the payload?
I'll let someone else pipe in about the low level details, but it may be useful to look at
swift-nio-extras which has a number of classes that follow this pattern, like FixedLengthFrameDecoder (and indeed some useful types that may be directly usable for your use case). I'd imagine following the same patterns, or using the provided types directly would yield reasonably good performance.
If they normally reuse the buffer, they'll have to allocate a new buffer instead. If they don't normally reuse the buffer, they'll have to allocate a new buffer anyway. So we're talking about saving a memcpy or two depending on the order of operations, which isn't nothing but which probably doesn't matter until a benchmark says it does.
This pattern is just fine. When you're a long way down a pipeline it's very hard to know whether a
ByteBuffer is going to be re-used. NIO will opportunistically attempt to re-use a
ByteBuffer for a subsequent read on a socket, but we can't guarantee it'll work, so as a practical matter you're totally fine to buffer in this way.