@@ -636,6 +636,138 @@ private static async Task AssertResponseNotCachedAsync(HttpResponseMessage initi
636636 Assert . NotEqual ( await initialResponse . Content . ReadAsStringAsync ( ) , await subsequentResponse . Content . ReadAsStringAsync ( ) ) ;
637637 }
638638
639+ [ Fact ]
640+ public async void Serves304_IfIfModifiedSince_Satisfied ( )
641+ {
642+ var builder = CreateBuilderWithResponseCaching ( async ( context ) =>
643+ {
644+ var uniqueId = Guid . NewGuid ( ) . ToString ( ) ;
645+ var headers = context . Response . GetTypedHeaders ( ) ;
646+ headers . CacheControl = new CacheControlHeaderValue ( )
647+ {
648+ Public = true ,
649+ MaxAge = TimeSpan . FromSeconds ( 10 )
650+ } ;
651+ headers . Date = DateTimeOffset . UtcNow ;
652+ headers . Headers [ "X-Value" ] = uniqueId ;
653+ await context . Response . WriteAsync ( uniqueId ) ;
654+ } ) ;
655+
656+ using ( var server = new TestServer ( builder ) )
657+ {
658+ var client = server . CreateClient ( ) ;
659+ var initialResponse = await client . GetAsync ( "" ) ;
660+ client . DefaultRequestHeaders . IfUnmodifiedSince = DateTimeOffset . MaxValue ;
661+ var subsequentResponse = await client . GetAsync ( "" ) ;
662+
663+ initialResponse . EnsureSuccessStatusCode ( ) ;
664+ Assert . Equal ( System . Net . HttpStatusCode . NotModified , subsequentResponse . StatusCode ) ;
665+ }
666+ }
667+
668+ [ Fact ]
669+ public async void ServesCachedContent_IfIfModifiedSince_NotSatisfied ( )
670+ {
671+ var builder = CreateBuilderWithResponseCaching ( async ( context ) =>
672+ {
673+ var uniqueId = Guid . NewGuid ( ) . ToString ( ) ;
674+ var headers = context . Response . GetTypedHeaders ( ) ;
675+ headers . CacheControl = new CacheControlHeaderValue ( )
676+ {
677+ Public = true ,
678+ MaxAge = TimeSpan . FromSeconds ( 10 )
679+ } ;
680+ headers . Date = DateTimeOffset . UtcNow ;
681+ headers . Headers [ "X-Value" ] = uniqueId ;
682+ await context . Response . WriteAsync ( uniqueId ) ;
683+ } ) ;
684+
685+ using ( var server = new TestServer ( builder ) )
686+ {
687+ var client = server . CreateClient ( ) ;
688+ var initialResponse = await client . GetAsync ( "" ) ;
689+ client . DefaultRequestHeaders . IfUnmodifiedSince = DateTimeOffset . MinValue ;
690+ var subsequentResponse = await client . GetAsync ( "" ) ;
691+
692+ initialResponse . EnsureSuccessStatusCode ( ) ;
693+ subsequentResponse . EnsureSuccessStatusCode ( ) ;
694+
695+ foreach ( var header in initialResponse . Headers )
696+ {
697+ Assert . Equal ( initialResponse . Headers . GetValues ( header . Key ) , subsequentResponse . Headers . GetValues ( header . Key ) ) ;
698+ }
699+ Assert . True ( subsequentResponse . Headers . Contains ( HeaderNames . Age ) ) ;
700+ Assert . Equal ( await initialResponse . Content . ReadAsStringAsync ( ) , await subsequentResponse . Content . ReadAsStringAsync ( ) ) ;
701+ }
702+ }
703+
704+ [ Fact ]
705+ public async void Serves304_IfIfNoneMatch_Satisfied ( )
706+ {
707+ var builder = CreateBuilderWithResponseCaching ( async ( context ) =>
708+ {
709+ var uniqueId = Guid . NewGuid ( ) . ToString ( ) ;
710+ var headers = context . Response . GetTypedHeaders ( ) ;
711+ headers . CacheControl = new CacheControlHeaderValue ( )
712+ {
713+ Public = true ,
714+ MaxAge = TimeSpan . FromSeconds ( 10 )
715+ } ;
716+ headers . Date = DateTimeOffset . UtcNow ;
717+ headers . Headers [ "X-Value" ] = uniqueId ;
718+ headers . ETag = new EntityTagHeaderValue ( "\" E1\" " ) ;
719+ await context . Response . WriteAsync ( uniqueId ) ;
720+ } ) ;
721+
722+ using ( var server = new TestServer ( builder ) )
723+ {
724+ var client = server . CreateClient ( ) ;
725+ var initialResponse = await client . GetAsync ( "" ) ;
726+ client . DefaultRequestHeaders . IfNoneMatch . Add ( new System . Net . Http . Headers . EntityTagHeaderValue ( "\" E1\" " ) ) ;
727+ var subsequentResponse = await client . GetAsync ( "" ) ;
728+
729+ initialResponse . EnsureSuccessStatusCode ( ) ;
730+ Assert . Equal ( System . Net . HttpStatusCode . NotModified , subsequentResponse . StatusCode ) ;
731+ }
732+ }
733+
734+ [ Fact ]
735+ public async void ServesCachedContent_IfIfNoneMatch_NotSatisfied ( )
736+ {
737+ var builder = CreateBuilderWithResponseCaching ( async ( context ) =>
738+ {
739+ var uniqueId = Guid . NewGuid ( ) . ToString ( ) ;
740+ var headers = context . Response . GetTypedHeaders ( ) ;
741+ headers . CacheControl = new CacheControlHeaderValue ( )
742+ {
743+ Public = true ,
744+ MaxAge = TimeSpan . FromSeconds ( 10 )
745+ } ;
746+ headers . Date = DateTimeOffset . UtcNow ;
747+ headers . Headers [ "X-Value" ] = uniqueId ;
748+ headers . ETag = new EntityTagHeaderValue ( "\" E1\" " ) ;
749+ await context . Response . WriteAsync ( uniqueId ) ;
750+ } ) ;
751+
752+ using ( var server = new TestServer ( builder ) )
753+ {
754+ var client = server . CreateClient ( ) ;
755+ var initialResponse = await client . GetAsync ( "" ) ;
756+ client . DefaultRequestHeaders . IfNoneMatch . Add ( new System . Net . Http . Headers . EntityTagHeaderValue ( "\" E2\" " ) ) ;
757+ var subsequentResponse = await client . GetAsync ( "" ) ;
758+
759+ initialResponse . EnsureSuccessStatusCode ( ) ;
760+ subsequentResponse . EnsureSuccessStatusCode ( ) ;
761+
762+ foreach ( var header in initialResponse . Headers )
763+ {
764+ Assert . Equal ( initialResponse . Headers . GetValues ( header . Key ) , subsequentResponse . Headers . GetValues ( header . Key ) ) ;
765+ }
766+ Assert . True ( subsequentResponse . Headers . Contains ( HeaderNames . Age ) ) ;
767+ Assert . Equal ( await initialResponse . Content . ReadAsStringAsync ( ) , await subsequentResponse . Content . ReadAsStringAsync ( ) ) ;
768+ }
769+ }
770+
639771 private static IWebHostBuilder CreateBuilderWithResponseCaching ( RequestDelegate requestDelegate ) =>
640772 CreateBuilderWithResponseCaching ( app => { } , requestDelegate ) ;
641773
0 commit comments