github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/quic-go/http3/request.go (about) 1 package http3 2 3 import ( 4 "crypto/tls" 5 "errors" 6 "net/http" 7 "net/url" 8 "strconv" 9 "strings" 10 11 "github.com/marten-seemann/qpack" 12 ) 13 14 func requestFromHeaders(headers []qpack.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 isConnect := method == http.MethodConnect 41 if isConnect { 42 if path != "" || authority == "" { 43 return nil, errors.New(":path must be empty and :authority must not be empty") 44 } 45 } else if len(path) == 0 || len(authority) == 0 || len(method) == 0 { 46 return nil, errors.New(":path, :authority and :method must not be empty") 47 } 48 49 var u *url.URL 50 var requestURI string 51 var err error 52 53 if isConnect { 54 u = &url.URL{Host: authority} 55 requestURI = authority 56 } else { 57 u, err = url.ParseRequestURI(path) 58 if err != nil { 59 return nil, err 60 } 61 requestURI = path 62 } 63 64 var contentLength int64 65 if len(contentLengthStr) > 0 { 66 contentLength, err = strconv.ParseInt(contentLengthStr, 10, 64) 67 if err != nil { 68 return nil, err 69 } 70 } 71 72 return &http.Request{ 73 Method: method, 74 URL: u, 75 Proto: "HTTP/3", 76 ProtoMajor: 3, 77 ProtoMinor: 0, 78 Header: httpHeaders, 79 Body: nil, 80 ContentLength: contentLength, 81 Host: authority, 82 RequestURI: requestURI, 83 TLS: &tls.ConnectionState{}, 84 }, nil 85 } 86 87 func hostnameFromRequest(req *http.Request) string { 88 if req.URL != nil { 89 return req.URL.Host 90 } 91 return "" 92 }