github.com/Psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/quic/gquic-go/h2quic/response.go (about) 1 package h2quic 2 3 import ( 4 "bytes" 5 "errors" 6 "io/ioutil" 7 "net/http" 8 "net/textproto" 9 "strconv" 10 "strings" 11 12 "golang.org/x/net/http2" 13 ) 14 15 // copied from net/http2/transport.go 16 17 var errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit") 18 var noBody = ioutil.NopCloser(bytes.NewReader(nil)) 19 20 // from the handleResponse function 21 func responseFromHeaders(f *http2.MetaHeadersFrame) (*http.Response, error) { 22 if f.Truncated { 23 return nil, errResponseHeaderListSize 24 } 25 26 status := f.PseudoValue("status") 27 if status == "" { 28 return nil, errors.New("missing status pseudo header") 29 } 30 statusCode, err := strconv.Atoi(status) 31 if err != nil { 32 return nil, errors.New("malformed non-numeric status pseudo header") 33 } 34 35 // TODO: handle statusCode == 100 36 37 header := make(http.Header) 38 res := &http.Response{ 39 Proto: "HTTP/2.0", 40 ProtoMajor: 2, 41 Header: header, 42 StatusCode: statusCode, 43 Status: status + " " + http.StatusText(statusCode), 44 } 45 for _, hf := range f.RegularFields() { 46 key := http.CanonicalHeaderKey(hf.Name) 47 if key == "Trailer" { 48 t := res.Trailer 49 if t == nil { 50 t = make(http.Header) 51 res.Trailer = t 52 } 53 foreachHeaderElement(hf.Value, func(v string) { 54 t[http.CanonicalHeaderKey(v)] = nil 55 }) 56 } else { 57 header[key] = append(header[key], hf.Value) 58 } 59 } 60 61 return res, nil 62 } 63 64 // continuation of the handleResponse function 65 func setLength(res *http.Response, isHead, streamEnded bool) *http.Response { 66 if !streamEnded || isHead { 67 res.ContentLength = -1 68 if clens := res.Header["Content-Length"]; len(clens) == 1 { 69 if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil { 70 res.ContentLength = clen64 71 } 72 } 73 } 74 return res 75 } 76 77 // copied from net/http/server.go 78 79 // foreachHeaderElement splits v according to the "#rule" construction 80 // in RFC 2616 section 2.1 and calls fn for each non-empty element. 81 func foreachHeaderElement(v string, fn func(string)) { 82 v = textproto.TrimString(v) 83 if v == "" { 84 return 85 } 86 if !strings.Contains(v, ",") { 87 fn(v) 88 return 89 } 90 for _, f := range strings.Split(v, ",") { 91 if f = textproto.TrimString(f); f != "" { 92 fn(f) 93 } 94 } 95 }