@@ -311,3 +311,291 @@ def test_header_tuples_are_decoded_push_promise(self,
311
311
312
312
assert isinstance (event , h2 .events .PushedStreamReceived )
313
313
assert_header_blocks_actually_equal (headers , event .headers )
314
+
315
+
316
+ class TestSecureHeaders (object ):
317
+ """
318
+ Certain headers should always be transformed to their never-indexed form.
319
+ """
320
+ example_request_headers = [
321
+ (u':authority' , u'example.com' ),
322
+ (u':path' , u'/' ),
323
+ (u':scheme' , u'https' ),
324
+ (u':method' , u'GET' ),
325
+ ]
326
+ bytes_example_request_headers = [
327
+ (b':authority' , b'example.com' ),
328
+ (b':path' , b'/' ),
329
+ (b':scheme' , b'https' ),
330
+ (b':method' , b'GET' ),
331
+ ]
332
+ possible_auth_headers = [
333
+ (u'authorization' , u'test' ),
334
+ (u'Authorization' , u'test' ),
335
+ (u'authorization' , u'really long test' ),
336
+ HeaderTuple (u'authorization' , u'test' ),
337
+ HeaderTuple (u'Authorization' , u'test' ),
338
+ HeaderTuple (u'authorization' , u'really long test' ),
339
+ NeverIndexedHeaderTuple (u'authorization' , u'test' ),
340
+ NeverIndexedHeaderTuple (u'Authorization' , u'test' ),
341
+ NeverIndexedHeaderTuple (u'authorization' , u'really long test' ),
342
+ (b'authorization' , b'test' ),
343
+ (b'Authorization' , b'test' ),
344
+ (b'authorization' , b'really long test' ),
345
+ HeaderTuple (b'authorization' , b'test' ),
346
+ HeaderTuple (b'Authorization' , b'test' ),
347
+ HeaderTuple (b'authorization' , b'really long test' ),
348
+ NeverIndexedHeaderTuple (b'authorization' , b'test' ),
349
+ NeverIndexedHeaderTuple (b'Authorization' , b'test' ),
350
+ NeverIndexedHeaderTuple (b'authorization' , b'really long test' ),
351
+ ]
352
+ secured_cookie_headers = [
353
+ (u'cookie' , u'short' ),
354
+ (u'Cookie' , u'short' ),
355
+ (u'cookie' , u'nineteen byte cooki' ),
356
+ HeaderTuple (u'cookie' , u'short' ),
357
+ HeaderTuple (u'Cookie' , u'short' ),
358
+ HeaderTuple (u'cookie' , u'nineteen byte cooki' ),
359
+ NeverIndexedHeaderTuple (u'cookie' , u'short' ),
360
+ NeverIndexedHeaderTuple (u'Cookie' , u'short' ),
361
+ NeverIndexedHeaderTuple (u'cookie' , u'nineteen byte cooki' ),
362
+ NeverIndexedHeaderTuple (u'cookie' , u'longer manually secured cookie' ),
363
+ (b'cookie' , b'short' ),
364
+ (b'Cookie' , b'short' ),
365
+ (b'cookie' , b'nineteen byte cooki' ),
366
+ HeaderTuple (b'cookie' , b'short' ),
367
+ HeaderTuple (b'Cookie' , b'short' ),
368
+ HeaderTuple (b'cookie' , b'nineteen byte cooki' ),
369
+ NeverIndexedHeaderTuple (b'cookie' , b'short' ),
370
+ NeverIndexedHeaderTuple (b'Cookie' , b'short' ),
371
+ NeverIndexedHeaderTuple (b'cookie' , b'nineteen byte cooki' ),
372
+ NeverIndexedHeaderTuple (b'cookie' , b'longer manually secured cookie' ),
373
+ ]
374
+ unsecured_cookie_headers = [
375
+ (u'cookie' , u'twenty byte cookie!!' ),
376
+ (u'Cookie' , u'twenty byte cookie!!' ),
377
+ (u'cookie' , u'substantially longer than 20 byte cookie' ),
378
+ HeaderTuple (u'cookie' , u'twenty byte cookie!!' ),
379
+ HeaderTuple (u'cookie' , u'twenty byte cookie!!' ),
380
+ HeaderTuple (u'Cookie' , u'twenty byte cookie!!' ),
381
+ (b'cookie' , b'twenty byte cookie!!' ),
382
+ (b'Cookie' , b'twenty byte cookie!!' ),
383
+ (b'cookie' , b'substantially longer than 20 byte cookie' ),
384
+ HeaderTuple (b'cookie' , b'twenty byte cookie!!' ),
385
+ HeaderTuple (b'cookie' , b'twenty byte cookie!!' ),
386
+ HeaderTuple (b'Cookie' , b'twenty byte cookie!!' ),
387
+ ]
388
+
389
+ @pytest .mark .parametrize (
390
+ 'headers' , (example_request_headers , bytes_example_request_headers )
391
+ )
392
+ @pytest .mark .parametrize ('auth_header' , possible_auth_headers )
393
+ def test_authorization_headers_never_indexed (self ,
394
+ headers ,
395
+ auth_header ,
396
+ frame_factory ):
397
+ """
398
+ Authorization headers are always forced to be never-indexed, regardless
399
+ of their form.
400
+ """
401
+ # Regardless of what we send, we expect it to be never indexed.
402
+ send_headers = headers + [auth_header ]
403
+ expected_headers = headers + [
404
+ NeverIndexedHeaderTuple (auth_header [0 ].lower (), auth_header [1 ])
405
+ ]
406
+
407
+ c = h2 .connection .H2Connection ()
408
+ c .initiate_connection ()
409
+
410
+ # Clear the data, then send headers.
411
+ c .clear_outbound_data_buffer ()
412
+ c .send_headers (1 , send_headers )
413
+
414
+ f = frame_factory .build_headers_frame (headers = expected_headers )
415
+ assert c .data_to_send () == f .serialize ()
416
+
417
+ @pytest .mark .parametrize (
418
+ 'headers' , (example_request_headers , bytes_example_request_headers )
419
+ )
420
+ @pytest .mark .parametrize ('auth_header' , possible_auth_headers )
421
+ def test_authorization_headers_never_indexed_push (self ,
422
+ headers ,
423
+ auth_header ,
424
+ frame_factory ):
425
+ """
426
+ Authorization headers are always forced to be never-indexed, regardless
427
+ of their form, when pushed by a server.
428
+ """
429
+ # Regardless of what we send, we expect it to be never indexed.
430
+ send_headers = headers + [auth_header ]
431
+ expected_headers = headers + [
432
+ NeverIndexedHeaderTuple (auth_header [0 ].lower (), auth_header [1 ])
433
+ ]
434
+
435
+ c = h2 .connection .H2Connection (client_side = False )
436
+ c .receive_data (frame_factory .preamble ())
437
+
438
+ # We can use normal headers for the request.
439
+ f = frame_factory .build_headers_frame (
440
+ self .example_request_headers
441
+ )
442
+ c .receive_data (f .serialize ())
443
+
444
+ frame_factory .refresh_encoder ()
445
+ expected_frame = frame_factory .build_push_promise_frame (
446
+ stream_id = 1 ,
447
+ promised_stream_id = 2 ,
448
+ headers = expected_headers ,
449
+ flags = ['END_HEADERS' ],
450
+ )
451
+
452
+ c .clear_outbound_data_buffer ()
453
+ c .push_stream (
454
+ stream_id = 1 ,
455
+ promised_stream_id = 2 ,
456
+ request_headers = send_headers
457
+ )
458
+
459
+ assert c .data_to_send () == expected_frame .serialize ()
460
+
461
+ @pytest .mark .parametrize (
462
+ 'headers' , (example_request_headers , bytes_example_request_headers )
463
+ )
464
+ @pytest .mark .parametrize ('cookie_header' , secured_cookie_headers )
465
+ def test_short_cookie_headers_never_indexed (self ,
466
+ headers ,
467
+ cookie_header ,
468
+ frame_factory ):
469
+ """
470
+ Short cookie headers, and cookies provided as NeverIndexedHeaderTuple,
471
+ are never indexed.
472
+ """
473
+ # Regardless of what we send, we expect it to be never indexed.
474
+ send_headers = headers + [cookie_header ]
475
+ expected_headers = headers + [
476
+ NeverIndexedHeaderTuple (cookie_header [0 ].lower (), cookie_header [1 ])
477
+ ]
478
+
479
+ c = h2 .connection .H2Connection ()
480
+ c .initiate_connection ()
481
+
482
+ # Clear the data, then send headers.
483
+ c .clear_outbound_data_buffer ()
484
+ c .send_headers (1 , send_headers )
485
+
486
+ f = frame_factory .build_headers_frame (headers = expected_headers )
487
+ assert c .data_to_send () == f .serialize ()
488
+
489
+ @pytest .mark .parametrize (
490
+ 'headers' , (example_request_headers , bytes_example_request_headers )
491
+ )
492
+ @pytest .mark .parametrize ('cookie_header' , secured_cookie_headers )
493
+ def test_short_cookie_headers_never_indexed_push (self ,
494
+ headers ,
495
+ cookie_header ,
496
+ frame_factory ):
497
+ """
498
+ Short cookie headers, and cookies provided as NeverIndexedHeaderTuple,
499
+ are never indexed when pushed by servers.
500
+ """
501
+ # Regardless of what we send, we expect it to be never indexed.
502
+ send_headers = headers + [cookie_header ]
503
+ expected_headers = headers + [
504
+ NeverIndexedHeaderTuple (cookie_header [0 ].lower (), cookie_header [1 ])
505
+ ]
506
+
507
+ c = h2 .connection .H2Connection (client_side = False )
508
+ c .receive_data (frame_factory .preamble ())
509
+
510
+ # We can use normal headers for the request.
511
+ f = frame_factory .build_headers_frame (
512
+ self .example_request_headers
513
+ )
514
+ c .receive_data (f .serialize ())
515
+
516
+ frame_factory .refresh_encoder ()
517
+ expected_frame = frame_factory .build_push_promise_frame (
518
+ stream_id = 1 ,
519
+ promised_stream_id = 2 ,
520
+ headers = expected_headers ,
521
+ flags = ['END_HEADERS' ],
522
+ )
523
+
524
+ c .clear_outbound_data_buffer ()
525
+ c .push_stream (
526
+ stream_id = 1 ,
527
+ promised_stream_id = 2 ,
528
+ request_headers = send_headers
529
+ )
530
+
531
+ assert c .data_to_send () == expected_frame .serialize ()
532
+
533
+ @pytest .mark .parametrize (
534
+ 'headers' , (example_request_headers , bytes_example_request_headers )
535
+ )
536
+ @pytest .mark .parametrize ('cookie_header' , unsecured_cookie_headers )
537
+ def test_long_cookie_headers_can_be_indexed (self ,
538
+ headers ,
539
+ cookie_header ,
540
+ frame_factory ):
541
+ """
542
+ Longer cookie headers can be indexed.
543
+ """
544
+ # Regardless of what we send, we expect it to be indexed.
545
+ send_headers = headers + [cookie_header ]
546
+ expected_headers = headers + [
547
+ HeaderTuple (cookie_header [0 ].lower (), cookie_header [1 ])
548
+ ]
549
+
550
+ c = h2 .connection .H2Connection ()
551
+ c .initiate_connection ()
552
+
553
+ # Clear the data, then send headers.
554
+ c .clear_outbound_data_buffer ()
555
+ c .send_headers (1 , send_headers )
556
+
557
+ f = frame_factory .build_headers_frame (headers = expected_headers )
558
+ assert c .data_to_send () == f .serialize ()
559
+
560
+ @pytest .mark .parametrize (
561
+ 'headers' , (example_request_headers , bytes_example_request_headers )
562
+ )
563
+ @pytest .mark .parametrize ('cookie_header' , unsecured_cookie_headers )
564
+ def test_long_cookie_headers_can_be_indexed_push (self ,
565
+ headers ,
566
+ cookie_header ,
567
+ frame_factory ):
568
+ """
569
+ Longer cookie headers can be indexed.
570
+ """
571
+ # Regardless of what we send, we expect it to be never indexed.
572
+ send_headers = headers + [cookie_header ]
573
+ expected_headers = headers + [
574
+ HeaderTuple (cookie_header [0 ].lower (), cookie_header [1 ])
575
+ ]
576
+
577
+ c = h2 .connection .H2Connection (client_side = False )
578
+ c .receive_data (frame_factory .preamble ())
579
+
580
+ # We can use normal headers for the request.
581
+ f = frame_factory .build_headers_frame (
582
+ self .example_request_headers
583
+ )
584
+ c .receive_data (f .serialize ())
585
+
586
+ frame_factory .refresh_encoder ()
587
+ expected_frame = frame_factory .build_push_promise_frame (
588
+ stream_id = 1 ,
589
+ promised_stream_id = 2 ,
590
+ headers = expected_headers ,
591
+ flags = ['END_HEADERS' ],
592
+ )
593
+
594
+ c .clear_outbound_data_buffer ()
595
+ c .push_stream (
596
+ stream_id = 1 ,
597
+ promised_stream_id = 2 ,
598
+ request_headers = send_headers
599
+ )
600
+
601
+ assert c .data_to_send () == expected_frame .serialize ()
0 commit comments