@@ -246,6 +246,8 @@ public async Task BrowserHttpHandler_Streaming()
246
246
247
247
int readOffset = 0 ;
248
248
req . Content = new StreamContent ( new DelegateStream (
249
+ canReadFunc : ( ) => true ,
250
+ readFunc : ( buffer , offset , count ) => throw new FormatException ( ) ,
249
251
readAsyncFunc : async ( buffer , offset , count , cancellationToken ) =>
250
252
{
251
253
await Task . Delay ( 1 ) ;
@@ -295,8 +297,12 @@ public async Task BrowserHttpHandler_StreamingRequest()
295
297
req . Options . Set ( WebAssemblyEnableStreamingRequestKey , true ) ;
296
298
297
299
int size = 1500 * 1024 * 1024 ;
300
+ int multipartOverhead = 125 + 4 /* "test" */ ;
298
301
int remaining = size ;
299
- req . Content = new StreamContent ( new DelegateStream (
302
+ var content = new MultipartFormDataContent ( ) ;
303
+ content . Add ( new StreamContent ( new DelegateStream (
304
+ canReadFunc : ( ) => true ,
305
+ readFunc : ( buffer , offset , count ) => throw new FormatException ( ) ,
300
306
readAsyncFunc : ( buffer , offset , count , cancellationToken ) =>
301
307
{
302
308
if ( remaining > 0 )
@@ -307,15 +313,16 @@ public async Task BrowserHttpHandler_StreamingRequest()
307
313
return Task . FromResult ( send ) ;
308
314
}
309
315
return Task . FromResult ( 0 ) ;
310
- } ) ) ;
316
+ } ) ) , "test" ) ;
317
+ req . Content = content ;
311
318
312
319
req . Content . Headers . Add ( "Content-MD5-Skip" , "browser" ) ;
313
320
314
321
using ( HttpClient client = CreateHttpClientForRemoteServer ( Configuration . Http . RemoteHttp2Server ) )
315
322
using ( HttpResponseMessage response = await client . SendAsync ( req ) )
316
323
{
317
324
Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
318
- Assert . Equal ( size . ToString ( ) , Assert . Single ( response . Headers . GetValues ( "X-HttpRequest-Body-Length" ) ) ) ;
325
+ Assert . Equal ( ( size + multipartOverhead ) . ToString ( ) , Assert . Single ( response . Headers . GetValues ( "X-HttpRequest-Body-Length" ) ) ) ;
319
326
// Streaming requests can't set Content-Length
320
327
Assert . False ( response . Headers . Contains ( "X-HttpRequest-Headers-ContentLength" ) ) ;
321
328
}
@@ -335,22 +342,101 @@ public async Task BrowserHttpHandler_StreamingRequest_ThrowFromContentCopy_Reque
335
342
req . Options . Set ( WebAssemblyEnableStreamingRequestKey , true ) ;
336
343
337
344
Exception error = new FormatException ( ) ;
338
- var content = new StreamContent ( new DelegateStream (
345
+ req . Content = new StreamContent ( new DelegateStream (
339
346
canSeekFunc : ( ) => true ,
340
347
lengthFunc : ( ) => 12345678 ,
341
348
positionGetFunc : ( ) => 0 ,
342
349
canReadFunc : ( ) => true ,
343
- readFunc : ( buffer , offset , count ) => throw error ,
350
+ readFunc : ( buffer , offset , count ) => throw new FormatException ( ) ,
344
351
readAsyncFunc : ( buffer , offset , count , cancellationToken ) => syncFailure ? throw error : Task . Delay ( 1 ) . ContinueWith < int > ( _ => throw error ) ) ) ;
345
352
346
- req . Content = content ;
347
-
348
353
using ( HttpClient client = CreateHttpClientForRemoteServer ( Configuration . Http . RemoteHttp2Server ) )
349
354
{
350
355
Assert . Same ( error , await Assert . ThrowsAsync < FormatException > ( ( ) => client . SendAsync ( req ) ) ) ;
351
356
}
352
357
}
353
358
359
+ public static TheoryData CancelRequestReadFunctions
360
+ => new TheoryData < bool , Func < Task < int > > >
361
+ {
362
+ { false , ( ) => Task . FromResult ( 0 ) } ,
363
+ { true , ( ) => Task . FromResult ( 0 ) } ,
364
+ { false , ( ) => Task . FromResult ( 1 ) } ,
365
+ { true , ( ) => Task . FromResult ( 1 ) } ,
366
+ { false , ( ) => throw new FormatException ( ) } ,
367
+ { true , ( ) => throw new FormatException ( ) } ,
368
+ } ;
369
+
370
+ [ OuterLoop ]
371
+ [ ConditionalTheory ( typeof ( PlatformDetection ) , nameof ( PlatformDetection . IsBrowser ) ) ]
372
+ [ MemberData ( nameof ( CancelRequestReadFunctions ) ) ]
373
+ public async Task BrowserHttpHandler_StreamingRequest_CancelRequest ( bool cancelAsync , Func < Task < int > > readFunc )
374
+ {
375
+ var WebAssemblyEnableStreamingRequestKey = new HttpRequestOptionsKey < bool > ( "WebAssemblyEnableStreamingRequest" ) ;
376
+
377
+ var req = new HttpRequestMessage ( HttpMethod . Post , Configuration . Http . Http2RemoteEchoServer ) ;
378
+
379
+ req . Options . Set ( WebAssemblyEnableStreamingRequestKey , true ) ;
380
+
381
+ using var cts = new CancellationTokenSource ( ) ;
382
+ var token = cts . Token ;
383
+ int readNotCancelledCount = 0 , readCancelledCount = 0 ;
384
+ req . Content = new StreamContent ( new DelegateStream (
385
+ canReadFunc : ( ) => true ,
386
+ readFunc : ( buffer , offset , count ) => throw new FormatException ( ) ,
387
+ readAsyncFunc : async ( buffer , offset , count , cancellationToken ) =>
388
+ {
389
+ if ( cancelAsync ) await Task . Delay ( 1 ) ;
390
+ Assert . Equal ( token . IsCancellationRequested , cancellationToken . IsCancellationRequested ) ;
391
+ if ( ! token . IsCancellationRequested )
392
+ {
393
+ readNotCancelledCount ++ ;
394
+ cts . Cancel ( ) ;
395
+ }
396
+ else
397
+ {
398
+ readCancelledCount ++ ;
399
+ }
400
+ return await readFunc ( ) ;
401
+ } ) ) ;
402
+
403
+ using ( HttpClient client = CreateHttpClientForRemoteServer ( Configuration . Http . RemoteHttp2Server ) )
404
+ {
405
+ TaskCanceledException ex = await Assert . ThrowsAsync < TaskCanceledException > ( ( ) => client . SendAsync ( req , token ) ) ;
406
+ Assert . Equal ( token , ex . CancellationToken ) ;
407
+ Assert . Equal ( 1 , readNotCancelledCount ) ;
408
+ Assert . Equal ( 0 , readCancelledCount ) ;
409
+ }
410
+ }
411
+
412
+ [ OuterLoop ]
413
+ [ ConditionalFact ( typeof ( PlatformDetection ) , nameof ( PlatformDetection . IsBrowser ) ) ]
414
+ public async Task BrowserHttpHandler_StreamingRequest_Http1Fails ( )
415
+ {
416
+ var WebAssemblyEnableStreamingRequestKey = new HttpRequestOptionsKey < bool > ( "WebAssemblyEnableStreamingRequest" ) ;
417
+
418
+ var req = new HttpRequestMessage ( HttpMethod . Post , Configuration . Http . RemoteHttp11Server . BaseUri ) ;
419
+
420
+ req . Options . Set ( WebAssemblyEnableStreamingRequestKey , true ) ;
421
+
422
+ int readCount = 0 ;
423
+ req . Content = new StreamContent ( new DelegateStream (
424
+ canReadFunc : ( ) => true ,
425
+ readFunc : ( buffer , offset , count ) => throw new FormatException ( ) ,
426
+ readAsyncFunc : ( buffer , offset , count , cancellationToken ) =>
427
+ {
428
+ readCount ++ ;
429
+ return Task . FromResult ( 1 ) ;
430
+ } ) ) ;
431
+
432
+ using ( HttpClient client = CreateHttpClientForRemoteServer ( Configuration . Http . RemoteHttp11Server ) )
433
+ {
434
+ HttpRequestException ex = await Assert . ThrowsAsync < HttpRequestException > ( ( ) => client . SendAsync ( req ) ) ;
435
+ Assert . Equal ( "TypeError: Failed to fetch" , ex . Message ) ;
436
+ Assert . Equal ( 1 , readCount ) ;
437
+ }
438
+ }
439
+
354
440
[ OuterLoop ]
355
441
[ ConditionalFact ( typeof ( PlatformDetection ) , nameof ( PlatformDetection . IsBrowser ) ) ]
356
442
public async Task BrowserHttpHandler_StreamingResponse ( )
0 commit comments