@@ -5,90 +5,92 @@ import Middleware
55
66@available ( macOS 26 . 0 , iOS 26 . 0 , watchOS 26 . 0 , tvOS 26 . 0 , visionOS 26 . 0 , * )
77struct HTTPRequestLoggingMiddleware <
8- RequestConludingAsyncReader : ConcludingAsyncReader ,
8+ RequestConcludingAsyncReader : ConcludingAsyncReader & ~ Copyable ,
99 ResponseConcludingAsyncWriter: ConcludingAsyncWriter & ~ Copyable
1010> : Middleware
1111where
12- RequestConludingAsyncReader . Underlying: AsyncReader < Span < UInt8 > , any Error > ,
13- RequestConludingAsyncReader . FinalElement == HTTPFields ? ,
14- ResponseConcludingAsyncWriter. Underlying: AsyncWriter < Span < UInt8 > , any Error > ,
12+ RequestConcludingAsyncReader . Underlying. ReadElement == Span < UInt8 > ,
13+ RequestConcludingAsyncReader . FinalElement == HTTPFields ? ,
14+ ResponseConcludingAsyncWriter. Underlying. WriteElement == Span < UInt8 > ,
1515 ResponseConcludingAsyncWriter. FinalElement == HTTPFields ?
1616{
17- typealias Input = (
18- HTTPRequest , RequestConludingAsyncReader , ( HTTPResponse ) async throws -> ResponseConcludingAsyncWriter
19- )
20- typealias NextInput = (
21- HTTPRequest ,
22- HTTPRequestLoggingConcludingAsyncReader < RequestConludingAsyncReader > ,
23- (
24- HTTPResponse
25- ) async throws -> HTTPResponseLoggingConcludingAsyncWriter < ResponseConcludingAsyncWriter >
26- )
17+ typealias Input = RequestResponseMiddlewareBox < RequestConcludingAsyncReader , ResponseConcludingAsyncWriter >
18+ typealias NextInput = RequestResponseMiddlewareBox <
19+ HTTPRequestLoggingConcludingAsyncReader < RequestConcludingAsyncReader > ,
20+ HTTPResponseLoggingConcludingAsyncWriter < ResponseConcludingAsyncWriter >
21+ >
2722
2823 let logger : Logger
2924
3025 init (
31- requestConludingAsyncReaderType : RequestConludingAsyncReader . Type = RequestConludingAsyncReader . self,
26+ requestConcludingAsyncReaderType : RequestConcludingAsyncReader . Type = RequestConcludingAsyncReader . self,
3227 responseConcludingAsyncWriterType: ResponseConcludingAsyncWriter . Type = ResponseConcludingAsyncWriter . self,
3328 logger: Logger
3429 ) {
3530 self . logger = logger
3631 }
3732
3833 func intercept(
39- input: Input ,
40- next: ( NextInput ) async throws -> Void
34+ input: consuming Input ,
35+ next: ( consuming NextInput ) async throws -> Void
4136 ) async throws {
42- let request = input. 0
43- let requestAsyncReader = input. 1
44- let respond = input. 2
45- self . logger. info ( " Received request \( request. path ?? " unknown " ) \( request. method. rawValue) " )
46- defer {
47- self . logger. info ( " Finished request \( request. path ?? " unknown " ) \( request. method. rawValue) " )
48- }
49- let wrappedReader = HTTPRequestLoggingConcludingAsyncReader (
50- base: requestAsyncReader,
51- logger: self . logger
52- )
53- try await next (
54- ( request, wrappedReader, { httpResponse in
55- let writer = try await respond ( httpResponse)
56- return HTTPResponseLoggingConcludingAsyncWriter (
57- base: writer,
58- logger: self . logger
59- )
37+ try await input. withContents { request, requestReader, responseSender in
38+ self . logger. info ( " Received request \( request. path ?? " unknown " ) \( request. method. rawValue) " )
39+ defer {
40+ self . logger. info ( " Finished request \( request. path ?? " unknown " ) \( request. method. rawValue) " )
41+ }
42+ let wrappedReader = HTTPRequestLoggingConcludingAsyncReader (
43+ base: requestReader,
44+ logger: self . logger
45+ )
46+
47+ var maybeSender = Optional ( responseSender)
48+ let requestResponseBox = RequestResponseMiddlewareBox (
49+ request: request,
50+ requestReader: wrappedReader,
51+ responseSender: HTTPResponseSender { [ logger] response in
52+ if let sender = maybeSender. take ( ) {
53+ let writer = try await sender. sendResponse ( response)
54+ return HTTPResponseLoggingConcludingAsyncWriter (
55+ base: writer,
56+ logger: logger
57+ )
58+ } else {
59+ fatalError ( " Called closure more than once " )
60+ }
6061 }
6162 )
62- )
63+ try await next ( requestResponseBox)
64+ }
6365 }
6466}
6567
6668@available ( macOS 26 . 0 , iOS 26 . 0 , watchOS 26 . 0 , tvOS 26 . 0 , visionOS 26 . 0 , * )
6769struct HTTPRequestLoggingConcludingAsyncReader <
68- Base: ConcludingAsyncReader
69- > : ConcludingAsyncReader
70+ Base: ConcludingAsyncReader & ~ Copyable
71+ > : ConcludingAsyncReader , ~ Copyable
7072where
71- Base. Underlying: AsyncReader < Span < UInt8 > , any Error > ,
73+ Base. Underlying. ReadElement == Span < UInt8 > ,
7274 Base. FinalElement == HTTPFields ?
7375{
7476 typealias Underlying = RequestBodyAsyncReader
7577 typealias FinalElement = HTTPFields ?
7678
77- struct RequestBodyAsyncReader : AsyncReader {
79+ struct RequestBodyAsyncReader : AsyncReader , ~ Copyable {
7880 typealias ReadElement = Span < UInt8 >
7981 typealias ReadFailure = any Error
8082
8183 private var underlying : Base . Underlying
8284 private let logger : Logger
8385
84- init ( underlying: Base . Underlying , logger: Logger ) {
86+ init ( underlying: consuming Base . Underlying , logger: Logger ) {
8587 self . underlying = underlying
8688 self . logger = logger
8789 }
8890
8991 mutating func read< Return> (
9092 body: ( consuming Span < UInt8 > ? ) async throws -> Return
91- ) async throws ( any Error ) -> Return {
93+ ) async throws -> Return {
9294 let logger = self . logger
9395 return try await self . underlying. read { span in
9496 logger. info ( " Received next chunk \( span? . count ?? 0 ) " )
@@ -100,27 +102,28 @@ where
100102 private var base : Base
101103 private let logger : Logger
102104
103- init ( base: Base , logger: Logger ) {
105+ init ( base: consuming Base , logger: Logger ) {
104106 self . base = base
105107 self . logger = logger
106108 }
107109
108- func consumeAndConclude< Return> (
109- body: ( inout RequestBodyAsyncReader ) async throws -> Return
110- ) async throws -> ( Return , HTTPFields ? ) {
111- let ( result, trailers) = try await self . base. consumeAndConclude { bodyAsyncReader in
112- var wrappedReader = RequestBodyAsyncReader (
113- underlying: bodyAsyncReader ,
114- logger: self . logger
110+ consuming func consumeAndConclude< Return> (
111+ body: ( consuming Underlying ) async throws -> Return
112+ ) async throws -> ( Return , FinalElement ) {
113+ let ( result, trailers) = try await self . base. consumeAndConclude { [ logger ] reader in
114+ let wrappedReader = RequestBodyAsyncReader (
115+ underlying: reader ,
116+ logger: logger
115117 )
116- return try await body ( & wrappedReader)
118+ return try await body ( wrappedReader)
117119 }
118120
119121 if let trailers {
120122 self . logger. info ( " Received request trailers \( trailers) " )
121123 } else {
122124 self . logger. info ( " Received no request trailers " )
123125 }
126+
124127 return ( result, trailers)
125128 }
126129}
@@ -130,7 +133,7 @@ struct HTTPResponseLoggingConcludingAsyncWriter<
130133 Base: ConcludingAsyncWriter & ~ Copyable
131134> : ConcludingAsyncWriter , ~ Copyable
132135where
133- Base. Underlying: AsyncWriter < Span < UInt8 > , any Error > ,
136+ Base. Underlying. WriteElement == Span < UInt8 > ,
134137 Base. FinalElement == HTTPFields ?
135138{
136139 typealias Underlying = ResponseBodyAsyncWriter
0 commit comments