@@ -275,6 +275,115 @@ public void Decode_Mix_DifferentHeaderOrder()
275275 Assert . Equal ( "longervalue" , testHandler . Headers [ "longerheader" ] ) ;
276276 }
277277
278+ [ Fact ]
279+ public void Decode_ETag ( )
280+ {
281+ // 0, 0 - prefix, 0x07 - ETag, 0x40 - field line and name reference, 0x10 - static table, 0x01 - length, 0x61 - 'a'
282+ byte [ ] data = [ 0x00 , 0x00 , 0x07 + 0x40 + 0x10 , 0x01 , 0x61 ] ;
283+ for ( int i = 1 ; i < data . Length - 1 ; i ++ )
284+ {
285+ QPackDecoder decoder = new ( ) ;
286+ TestQPackHeaderHandler testHandler = new ( ) ;
287+ var success = decoder . DecodeHeader ( new ReadOnlySequence < byte > ( data . AsMemory ( 0 , i ) ) , testHandler , out long consumed ) ;
288+ success = decoder . DecodeHeader ( new ReadOnlySequence < byte > ( data . AsMemory ( checked ( ( int ) consumed ) ) ) , testHandler , out long finalConsumed ) ;
289+ Assert . True ( success ) ;
290+ Assert . Equal ( data . Length , consumed + finalConsumed ) ;
291+ Assert . Single ( testHandler . Headers ) ;
292+ Assert . Equal ( "a" , testHandler . Headers [ HeaderNames . ETag ] ) ;
293+ }
294+ }
295+
296+ [ Theory ]
297+ [ MemberData ( nameof ( KnownAspNetHeaders ) ) ]
298+ public void Decode_AspNetHeaders ( string headerName , byte staticTableIndex )
299+ {
300+ // 0, 0 - prefix, table index, 0x40 - field line and name reference, 0x10 - static table, 0x01 - length, 0x61 - 'a'
301+ Span < byte > encodedIndex = new byte [ 8 ] ;
302+ int length = QPackIntegerEncoder . Encode ( encodedIndex , staticTableIndex , 4 ) ;
303+ encodedIndex [ 0 ] += 0x40 + 0x10 ;
304+
305+ byte [ ] data = [ 0x00 , 0x00 , .. encodedIndex [ ..length ] , 0x01 , 0x61 ] ;
306+ QPackDecoder decoder = new ( ) ;
307+ TestQPackHeaderHandler testHandler = new ( ) ;
308+ var success = decoder . DecodeHeader ( new ReadOnlySequence < byte > ( data ) , testHandler , out long consumed ) ;
309+ Assert . True ( success ) ;
310+ Assert . Single ( testHandler . Headers ) ;
311+ Assert . Equal ( "a" , testHandler . Headers [ headerName ] ) ;
312+ }
313+
314+ public static IEnumerable < TheoryDataRow < string , byte > > KnownAspNetHeaders =>
315+ [
316+ new ( HeaderNames . Age , 2 ) ,
317+ new ( HeaderNames . ContentDisposition , 3 ) ,
318+ new ( HeaderNames . ContentLength , 4 ) ,
319+ new ( HeaderNames . Cookie , 5 ) ,
320+ new ( HeaderNames . Date , 6 ) ,
321+ new ( HeaderNames . ETag , 7 ) ,
322+ new ( HeaderNames . IfModifiedSince , 8 ) ,
323+ new ( HeaderNames . IfNoneMatch , 9 ) ,
324+ new ( HeaderNames . LastModified , 10 ) ,
325+ new ( HeaderNames . Link , 11 ) ,
326+ new ( HeaderNames . Location , 12 ) ,
327+ new ( HeaderNames . Referer , 13 ) ,
328+ new ( HeaderNames . SetCookie , 14 ) ,
329+ new ( HeaderNames . Accept , 29 ) ,
330+ new ( HeaderNames . Accept , 30 ) ,
331+ new ( HeaderNames . AcceptEncoding , 31 ) ,
332+ new ( HeaderNames . AcceptRanges , 32 ) ,
333+ new ( HeaderNames . AccessControlAllowHeaders , 33 ) ,
334+ new ( HeaderNames . AccessControlAllowHeaders , 34 ) ,
335+ new ( HeaderNames . AccessControlAllowOrigin , 35 ) ,
336+ new ( HeaderNames . CacheControl , 36 ) ,
337+ new ( HeaderNames . CacheControl , 37 ) ,
338+ new ( HeaderNames . CacheControl , 38 ) ,
339+ new ( HeaderNames . CacheControl , 39 ) ,
340+ new ( HeaderNames . CacheControl , 40 ) ,
341+ new ( HeaderNames . CacheControl , 41 ) ,
342+ new ( HeaderNames . ContentEncoding , 42 ) ,
343+ new ( HeaderNames . ContentEncoding , 43 ) ,
344+ new ( HeaderNames . ContentType , 44 ) ,
345+ new ( HeaderNames . ContentType , 45 ) ,
346+ new ( HeaderNames . ContentType , 46 ) ,
347+ new ( HeaderNames . ContentType , 47 ) ,
348+ new ( HeaderNames . ContentType , 48 ) ,
349+ new ( HeaderNames . ContentType , 49 ) ,
350+ new ( HeaderNames . ContentType , 50 ) ,
351+ new ( HeaderNames . ContentType , 51 ) ,
352+ new ( HeaderNames . ContentType , 52 ) ,
353+ new ( HeaderNames . ContentType , 53 ) ,
354+ new ( HeaderNames . ContentType , 54 ) ,
355+ new ( HeaderNames . Range , 55 ) ,
356+ new ( HeaderNames . StrictTransportSecurity , 56 ) ,
357+ new ( HeaderNames . StrictTransportSecurity , 57 ) ,
358+ new ( HeaderNames . StrictTransportSecurity , 58 ) ,
359+ new ( HeaderNames . Vary , 59 ) ,
360+ new ( HeaderNames . Vary , 60 ) ,
361+ new ( HeaderNames . XContentTypeOptions , 61 ) ,
362+ new ( HeaderNames . XXSSProtection , 62 ) ,
363+ new ( HeaderNames . AcceptLanguage , 72 ) ,
364+ new ( HeaderNames . AccessControlAllowCredentials , 73 ) ,
365+ new ( HeaderNames . AccessControlAllowCredentials , 74 ) ,
366+ new ( HeaderNames . AccessControlAllowHeaders , 75 ) ,
367+ new ( HeaderNames . AccessControlAllowMethods , 76 ) ,
368+ new ( HeaderNames . AccessControlAllowMethods , 77 ) ,
369+ new ( HeaderNames . AccessControlAllowMethods , 78 ) ,
370+ new ( HeaderNames . AccessControlExposeHeaders , 79 ) ,
371+ new ( HeaderNames . AccessControlRequestHeaders , 80 ) ,
372+ new ( HeaderNames . AccessControlRequestMethod , 81 ) ,
373+ new ( HeaderNames . AccessControlRequestMethod , 82 ) ,
374+ new ( HeaderNames . AltSvc , 83 ) ,
375+ new ( HeaderNames . Authorization , 84 ) ,
376+ new ( HeaderNames . ContentSecurityPolicy , 85 ) ,
377+ new ( HeaderNames . IfRange , 89 ) ,
378+ new ( HeaderNames . Origin , 90 ) ,
379+ new ( HeaderNames . Server , 92 ) ,
380+ new ( HeaderNames . UpgradeInsecureRequests , 94 ) ,
381+ new ( HeaderNames . UserAgent , 95 ) ,
382+ new ( HeaderNames . XFrameOptions , 97 ) ,
383+ new ( HeaderNames . XFrameOptions , 98 ) ,
384+ ] ;
385+
386+
278387 private class TestQPackHeaderHandler : IQPackHeaderHandler
279388 {
280389 internal Dictionary < string , string > Headers { get ; } = new ( ) ;
0 commit comments