@@ -67,13 +67,10 @@ private async Task<UpstreamResponse> SendUpstreamRequest(HttpRequest request, st
6767
6868 using ( var upstreamRequest = new HttpRequestMessage ( new HttpMethod ( request . Method ) , upstreamUri ) )
6969 {
70- if ( request . ContentLength > 0 )
70+ upstreamRequest . Content = new StreamContent ( request . Body ) ;
71+ foreach ( var header in request . Headers . Where ( h => Utils . ContentRequestHeaders . Contains ( h . Key ) ) )
7172 {
72- upstreamRequest . Content = new StreamContent ( request . Body ) ;
73- foreach ( var header in request . Headers . Where ( h => Utils . ContentRequestHeaders . Contains ( h . Key ) ) )
74- {
75- upstreamRequest . Content . Headers . Add ( header . Key , values : header . Value ) ;
76- }
73+ upstreamRequest . Content . Headers . Add ( header . Key , values : header . Value ) ;
7774 }
7875
7976 foreach ( var header in request . Headers . Where ( h => ! Utils . ExcludedRequestHeaders . Contains ( h . Key ) && ! Utils . ContentRequestHeaders . Contains ( h . Key ) ) )
@@ -125,7 +122,42 @@ private async Task<MemoryStream> BufferContentAsync(HttpContent content, Cancell
125122
126123 private async Task ProxyResponse ( HttpContext context , string upstreamUri , string fault , CancellationToken cancellationToken )
127124 {
125+ switch ( fault )
126+ {
127+ case "nq" :
128+ // No request body, then wait indefinitely
129+ await Task . Delay ( Timeout . InfiniteTimeSpan , cancellationToken ) ;
130+ return ;
131+ case "nqc" :
132+ // No request body, then close (TCP FIN)
133+ Close ( context ) ;
134+ return ;
135+ case "nqa" :
136+ // No request body, then abort (TCP RST)
137+ Abort ( context ) ;
138+ return ;
139+ case "pq" :
140+ // Partial request (50% of body), then wait indefinitely
141+ await ReadPartialRequest ( context . Request , cancellationToken ) ;
142+ await Task . Delay ( Timeout . InfiniteTimeSpan , cancellationToken ) ;
143+ return ;
144+ case "pqc" :
145+ // Partial request (50% of body), then close (TCP FIN)
146+ await ReadPartialRequest ( context . Request , cancellationToken ) ;
147+ Close ( context ) ;
148+ return ;
149+ case "pqa" :
150+ // Partial request (50% of body), then abort (TCP RST)
151+ await ReadPartialRequest ( context . Request , cancellationToken ) ;
152+ Abort ( context ) ;
153+ return ;
154+ default :
155+ // Fall through and read full request body
156+ break ;
157+ }
158+
128159 UpstreamResponse upstreamResponse = await SendUpstreamRequest ( context . Request , upstreamUri , cancellationToken ) ;
160+
129161 switch ( fault )
130162 {
131163 case "f" :
@@ -139,12 +171,12 @@ private async Task ProxyResponse(HttpContext context, string upstreamUri, string
139171 return ;
140172 case "pc" :
141173 // Partial Response (full headers, 50% of body), then close (TCP FIN)
142- await SendDownstreamResponse ( context . Response , upstreamResponse , upstreamResponse . ContentLength / 2 , cancellationToken ) ;
174+ await SendDownstreamResponse ( context . Response , upstreamResponse , upstreamResponse . ContentLength / 2 , cancellationToken ) ;
143175 Close ( context ) ;
144176 return ;
145177 case "pa" :
146178 // Partial Response (full headers, 50% of body), then abort (TCP RST)
147- await SendDownstreamResponse ( context . Response , upstreamResponse , upstreamResponse . ContentLength / 2 , cancellationToken ) ;
179+ await SendDownstreamResponse ( context . Response , upstreamResponse , upstreamResponse . ContentLength / 2 , cancellationToken ) ;
148180 Abort ( context ) ;
149181 return ;
150182 case "pn" :
@@ -169,6 +201,36 @@ private async Task ProxyResponse(HttpContext context, string upstreamUri, string
169201 }
170202 }
171203
204+ private static async Task ReadPartialRequest ( HttpRequest request , CancellationToken cancellationToken )
205+ {
206+ var contentLength = request . ContentLength
207+ ?? throw new InvalidOperationException ( "Partial request options require content-length request headers" ) ;
208+ var bytesToRead = contentLength / 2 ;
209+ long totalBytesRead = 0 ;
210+ var buffer = ArrayPool < byte > . Shared . Rent ( 81920 ) ;
211+ try
212+ {
213+ while ( true )
214+ {
215+ var bytesRead = await request . Body . ReadAsync (
216+ buffer ,
217+ 0 ,
218+ ( int ) Math . Min ( buffer . Length , bytesToRead - totalBytesRead ) ,
219+ cancellationToken
220+ ) ;
221+ totalBytesRead += bytesRead ;
222+ if ( totalBytesRead >= bytesToRead || bytesRead == 0 )
223+ {
224+ break ;
225+ }
226+ }
227+ }
228+ finally
229+ {
230+ ArrayPool < byte > . Shared . Return ( buffer ) ;
231+ }
232+ }
233+
172234 private async Task SendDownstreamResponse ( HttpResponse response , UpstreamResponse upstreamResponse , long contentBytes , CancellationToken cancellationToken )
173235 {
174236 response . StatusCode = upstreamResponse . StatusCode ;
0 commit comments