github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/quic/gquic-go/h2quic/request.go (about) 1 package h2quic 2 3 import ( 4 "crypto/tls" 5 "errors" 6 "net/http" 7 "net/url" 8 "strconv" 9 "strings" 10 11 "golang.org/x/net/http2/hpack" 12 ) 13 14 func requestFromHeaders(headers []hpack.HeaderField) (*http.Request, error) { 15 var path, authority, method, contentLengthStr string 16 httpHeaders := http.Header{} 17 18 for _, h := range headers { 19 switch h.Name { 20 case ":path": 21 path = h.Value 22 case ":method": 23 method = h.Value 24 case ":authority": 25 authority = h.Value 26 case "content-length": 27 contentLengthStr = h.Value 28 default: 29 if !h.IsPseudo() { 30 httpHeaders.Add(h.Name, h.Value) 31 } 32 } 33 } 34 35 // concatenate cookie headers, see https://tools.ietf.org/html/rfc6265#section-5.4 36 if len(httpHeaders["Cookie"]) > 0 { 37 httpHeaders.Set("Cookie", strings.Join(httpHeaders["Cookie"], "; ")) 38 } 39 40 if len(path) == 0 || len(authority) == 0 || len(method) == 0 { 41 return nil, errors.New(":path, :authority and :method must not be empty") 42 } 43 44 u, err := url.ParseRequestURI(path) 45 if err != nil { 46 return nil, err 47 } 48 49 var contentLength int64 50 if len(contentLengthStr) > 0 { 51 contentLength, err = strconv.ParseInt(contentLengthStr, 10, 64) 52 if err != nil { 53 return nil, err 54 } 55 } 56 57 return &http.Request{ 58 Method: method, 59 URL: u, 60 Proto: "HTTP/2.0", 61 ProtoMajor: 2, 62 ProtoMinor: 0, 63 Header: httpHeaders, 64 Body: nil, 65 ContentLength: contentLength, 66 Host: authority, 67 RequestURI: path, 68 TLS: &tls.ConnectionState{}, 69 }, nil 70 } 71 72 func hostnameFromRequest(req *http.Request) string { 73 if req.URL != nil { 74 return req.URL.Host 75 } 76 return "" 77 }