1- using System . Threading . Tasks ;
2- using System . Threading ;
3- using Microsoft . Extensions . Logging ;
41using System ;
5- using Microsoft . AspNetCore . Connections . Features ;
6- using Microsoft . AspNetCore . Http ;
7- using Microsoft . Extensions . Primitives ;
2+ using System . Buffers ;
83using System . Collections . Generic ;
4+ using System . Diagnostics ;
5+ using System . IO ;
6+ using System . Linq ;
97using System . Net . Http ;
108using System . Net . Sockets ;
119using System . Reflection ;
12- using System . Linq ;
13- using System . IO ;
14- using System . Buffers ;
15- using System . Diagnostics ;
10+ using System . Threading ;
11+ using System . Threading . Tasks ;
12+ using Microsoft . AspNetCore . Connections . Features ;
13+ using Microsoft . AspNetCore . Http ;
14+ using Microsoft . Extensions . Logging ;
15+ using Microsoft . Extensions . Primitives ;
1616
1717namespace Azure . Sdk . Tools . HttpFaultInjector
1818{
@@ -122,7 +122,42 @@ private async Task<MemoryStream> BufferContentAsync(HttpContent content, Cancell
122122
123123 private async Task ProxyResponse ( HttpContext context , string upstreamUri , string fault , CancellationToken cancellationToken )
124124 {
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+
125159 UpstreamResponse upstreamResponse = await SendUpstreamRequest ( context . Request , upstreamUri , cancellationToken ) ;
160+
126161 switch ( fault )
127162 {
128163 case "f" :
@@ -136,12 +171,12 @@ private async Task ProxyResponse(HttpContext context, string upstreamUri, string
136171 return ;
137172 case "pc" :
138173 // Partial Response (full headers, 50% of body), then close (TCP FIN)
139- await SendDownstreamResponse ( context . Response , upstreamResponse , upstreamResponse . ContentLength / 2 , cancellationToken ) ;
174+ await SendDownstreamResponse ( context . Response , upstreamResponse , upstreamResponse . ContentLength / 2 , cancellationToken ) ;
140175 Close ( context ) ;
141176 return ;
142177 case "pa" :
143178 // Partial Response (full headers, 50% of body), then abort (TCP RST)
144- await SendDownstreamResponse ( context . Response , upstreamResponse , upstreamResponse . ContentLength / 2 , cancellationToken ) ;
179+ await SendDownstreamResponse ( context . Response , upstreamResponse , upstreamResponse . ContentLength / 2 , cancellationToken ) ;
145180 Abort ( context ) ;
146181 return ;
147182 case "pn" :
@@ -166,6 +201,36 @@ private async Task ProxyResponse(HttpContext context, string upstreamUri, string
166201 }
167202 }
168203
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+
169234 private async Task SendDownstreamResponse ( HttpResponse response , UpstreamResponse upstreamResponse , long contentBytes , CancellationToken cancellationToken )
170235 {
171236 response . StatusCode = upstreamResponse . StatusCode ;
0 commit comments