@@ -7,7 +7,6 @@ package http
7
7
import (
8
8
"bufio"
9
9
"bytes"
10
- "compress/gzip"
11
10
"errors"
12
11
"fmt"
13
12
"io"
@@ -467,34 +466,6 @@ func suppressedHeaders(status int) []string {
467
466
return nil
468
467
}
469
468
470
- // proxyingReadCloser is a composite type that accepts and proxies
471
- // io.Read and io.Close calls to its respective Reader and Closer.
472
- //
473
- // It is composed of:
474
- // a) a top-level reader e.g. the result of decompression
475
- // b) a symbolic Closer e.g. the result of decompression, the
476
- // original body and the connection itself.
477
- type proxyingReadCloser struct {
478
- io.Reader
479
- io.Closer
480
- }
481
-
482
- // multiCloser implements io.Closer and allows a bunch of io.Closer values
483
- // to all be closed once.
484
- // Example usage is with proxyingReadCloser if we are decompressing a response
485
- // body on the fly and would like to close both *gzip.Reader and underlying body.
486
- type multiCloser []io.Closer
487
-
488
- func (mc multiCloser ) Close () error {
489
- var err error
490
- for _ , c := range mc {
491
- if err1 := c .Close (); err1 != nil && err == nil {
492
- err = err1
493
- }
494
- }
495
- return err
496
- }
497
-
498
469
// msg is *Request or *Response.
499
470
func readTransfer (msg interface {}, r * bufio.Reader ) (err error ) {
500
471
t := & transferReader {RequestMethod : "GET" }
@@ -572,7 +543,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
572
543
// Prepare body reader. ContentLength < 0 means chunked encoding
573
544
// or close connection when finished, since multipart is not supported yet
574
545
switch {
575
- case chunked (t .TransferEncoding ) || implicitlyChunked ( t . TransferEncoding ) :
546
+ case chunked (t .TransferEncoding ):
576
547
if noResponseBodyExpected (t .RequestMethod ) || ! bodyAllowedForStatus (t .StatusCode ) {
577
548
t .Body = NoBody
578
549
} else {
@@ -593,21 +564,6 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
593
564
}
594
565
}
595
566
596
- // Finally if "gzip" was one of the requested transfer-encodings,
597
- // we'll unzip the concatenated body/payload of the request.
598
- // TODO: As we support more transfer-encodings, extract
599
- // this code and apply the un-codings in reverse.
600
- if t .Body != NoBody && gzipped (t .TransferEncoding ) {
601
- zr , err := gzip .NewReader (t .Body )
602
- if err != nil {
603
- return fmt .Errorf ("http: failed to gunzip body: %v" , err )
604
- }
605
- t .Body = & proxyingReadCloser {
606
- Reader : zr ,
607
- Closer : multiCloser {zr , t .Body },
608
- }
609
- }
610
-
611
567
// Unify output
612
568
switch rr := msg .(type ) {
613
569
case * Request :
@@ -627,41 +583,8 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
627
583
return nil
628
584
}
629
585
630
- // Checks whether chunked is the last part of the encodings stack
631
- func chunked (te []string ) bool { return len (te ) > 0 && te [len (te )- 1 ] == "chunked" }
632
-
633
- // implicitlyChunked is a helper to check for implicity of chunked, because
634
- // RFC 7230 Section 3.3.1 says that the sender MUST apply chunked as the final
635
- // payload body to ensure that the message is framed for both the request
636
- // and the body. Since "identity" is incompatible with any other transformational
637
- // encoding cannot co-exist, the presence of "identity" will cause implicitlyChunked
638
- // to return false.
639
- func implicitlyChunked (te []string ) bool {
640
- if len (te ) == 0 { // No transfer-encodings passed in, so not implicitly chunked.
641
- return false
642
- }
643
- for _ , tei := range te {
644
- if tei == "identity" {
645
- return false
646
- }
647
- }
648
- return true
649
- }
650
-
651
- func isGzipTransferEncoding (tei string ) bool {
652
- // RFC 7230 4.2.3 requests that "x-gzip" SHOULD be considered the same as "gzip".
653
- return tei == "gzip" || tei == "x-gzip"
654
- }
655
-
656
- // Checks where either of "gzip" or "x-gzip" are contained in transfer encodings.
657
- func gzipped (te []string ) bool {
658
- for _ , tei := range te {
659
- if isGzipTransferEncoding (tei ) {
660
- return true
661
- }
662
- }
663
- return false
664
- }
586
+ // Checks whether chunked is part of the encodings stack
587
+ func chunked (te []string ) bool { return len (te ) > 0 && te [0 ] == "chunked" }
665
588
666
589
// Checks whether the encoding is explicitly "identity".
667
590
func isIdentity (te []string ) bool { return len (te ) == 1 && te [0 ] == "identity" }
@@ -697,47 +620,25 @@ func (t *transferReader) fixTransferEncoding() error {
697
620
698
621
encodings := strings .Split (raw [0 ], "," )
699
622
te := make ([]string , 0 , len (encodings ))
700
-
701
- // When adding new encodings, please maintain the invariant:
702
- // if chunked encoding is present, it must always
703
- // come last and it must be applied only once.
704
- // See RFC 7230 Section 3.3.1 Transfer-Encoding.
705
- for i , encoding := range encodings {
623
+ // TODO: Even though we only support "identity" and "chunked"
624
+ // encodings, the loop below is designed with foresight. One
625
+ // invariant that must be maintained is that, if present,
626
+ // chunked encoding must always come first.
627
+ for _ , encoding := range encodings {
706
628
encoding = strings .ToLower (strings .TrimSpace (encoding ))
707
-
629
+ // "identity" encoding is not recorded
708
630
if encoding == "identity" {
709
- // "identity" should not be mixed with other transfer-encodings/compressions
710
- // because it means "no compression, no transformation".
711
- if len (encodings ) != 1 {
712
- return & badStringError {`"identity" when present must be the only transfer encoding` , strings .Join (encodings , "," )}
713
- }
714
- // "identity" is not recorded.
715
631
break
716
632
}
717
-
718
- switch {
719
- case encoding == "chunked" :
720
- // "chunked" MUST ALWAYS be the last
721
- // encoding as per the loop invariant.
722
- // That is:
723
- // Invalid: [chunked, gzip]
724
- // Valid: [gzip, chunked]
725
- if i + 1 != len (encodings ) {
726
- return & badStringError {"chunked must be applied only once, as the last encoding" , strings .Join (encodings , "," )}
727
- }
728
- // Supported otherwise.
729
-
730
- case isGzipTransferEncoding (encoding ):
731
- // Supported
732
-
733
- default :
633
+ if encoding != "chunked" {
734
634
return & unsupportedTEError {fmt .Sprintf ("unsupported transfer encoding: %q" , encoding )}
735
635
}
736
-
737
636
te = te [0 : len (te )+ 1 ]
738
637
te [len (te )- 1 ] = encoding
739
638
}
740
-
639
+ if len (te ) > 1 {
640
+ return & badStringError {"too many transfer encodings" , strings .Join (te , "," )}
641
+ }
741
642
if len (te ) > 0 {
742
643
// RFC 7230 3.3.2 says "A sender MUST NOT send a
743
644
// Content-Length header field in any message that
0 commit comments