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  }