"golang.org/x/net/http/httpguts"
)
+// incomparable is a zero-width, non-comparable type. Adding it to a struct
+// makes that struct also non-comparable, and generally doesn't add
+// any size (as long as it's first).
+type incomparable [0]func()
+
// maxInt64 is the effective "infinite" value for the Server and
// Transport's byte-limiting readers.
const maxInt64 = 1<<63 - 1
}
proxy = u
}
- cm := connectMethod{proxy, tt.scheme, tt.addr, false}
+ cm := connectMethod{proxyURL: proxy, targetScheme: tt.scheme, targetAddr: tt.addr}
if got := cm.key().String(); got != tt.key {
t.Fatalf("{%q, %q, %q} cache key = %q; want %q", tt.proxy, tt.scheme, tt.addr, got, tt.key)
}
ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
)
-type badStringError struct {
- what string
- str string
-}
-
-func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
+func badStringError(what, val string) error { return fmt.Errorf("%s %q", what, val) }
// Headers that Request.Write handles itself and should be skipped.
var reqWriteExcludeHeader = map[string]bool{
var ok bool
req.Method, req.RequestURI, req.Proto, ok = parseRequestLine(s)
if !ok {
- return nil, &badStringError{"malformed HTTP request", s}
+ return nil, badStringError("malformed HTTP request", s)
}
if !validMethod(req.Method) {
- return nil, &badStringError{"invalid method", req.Method}
+ return nil, badStringError("invalid method", req.Method)
}
rawurl := req.RequestURI
if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok {
- return nil, &badStringError{"malformed HTTP version", req.Proto}
+ return nil, badStringError("malformed HTTP version", req.Proto)
}
// CONNECT requests are used two different ways, and neither uses a full URL:
return nil, err
}
if i := strings.IndexByte(line, ' '); i == -1 {
- return nil, &badStringError{"malformed HTTP response", line}
+ return nil, badStringError("malformed HTTP response", line)
} else {
resp.Proto = line[:i]
resp.Status = strings.TrimLeft(line[i+1:], " ")
statusCode = resp.Status[:i]
}
if len(statusCode) != 3 {
- return nil, &badStringError{"malformed HTTP status code", statusCode}
+ return nil, badStringError("malformed HTTP status code", statusCode)
}
resp.StatusCode, err = strconv.Atoi(statusCode)
if err != nil || resp.StatusCode < 0 {
- return nil, &badStringError{"malformed HTTP status code", statusCode}
+ return nil, badStringError("malformed HTTP status code", statusCode)
}
var ok bool
if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok {
- return nil, &badStringError{"malformed HTTP version", resp.Proto}
+ return nil, badStringError("malformed HTTP version", resp.Proto)
}
// Parse the response headers.
}
type readResult struct {
+ _ incomparable
n int
err error
b byte // byte read, if n == 1
k = CanonicalHeaderKey(k)
switch k {
case "Transfer-Encoding", "Trailer", "Content-Length":
- return &badStringError{"invalid Trailer key", k}
+ return badStringError("invalid Trailer key", k)
}
keys = append(keys, k)
}
te[len(te)-1] = encoding
}
if len(te) > 1 {
- return &badStringError{"too many transfer encodings", strings.Join(te, ",")}
+ return badStringError("too many transfer encodings", strings.Join(te, ","))
}
if len(te) > 0 {
// RFC 7230 3.3.2 says "A sender MUST NOT send a
switch key {
case "Transfer-Encoding", "Trailer", "Content-Length":
if err == nil {
- err = &badStringError{"bad trailer key", key}
+ err = badStringError("bad trailer key", key)
return
}
}
}
n, err := strconv.ParseInt(cl, 10, 64)
if err != nil || n < 0 {
- return 0, &badStringError{"bad Content-Length", cl}
+ return 0, badStringError("bad Content-Length", cl)
}
return n, nil
},
{
hdr: Header{"Transfer-Encoding": {"chunked, chunked", "identity", "chunked"}},
- wantErr: &badStringError{"too many transfer encodings", "chunked,chunked"},
+ wantErr: badStringError("too many transfer encodings", "chunked,chunked"),
},
{
hdr: Header{"Transfer-Encoding": {"chunked"}},
}
if !isHTTP {
req.closeBody()
- return nil, &badStringError{"unsupported protocol scheme", scheme}
+ return nil, badStringError("unsupported protocol scheme", scheme)
}
if req.Method != "" && !validMethod(req.Method) {
req.closeBody()
// https://proxy.com|http https to proxy, http to anywhere after that
//
type connectMethod struct {
+ _ incomparable
proxyURL *url.URL // nil for no proxy, else full proxy URL
targetScheme string // "http" or "https"
// If proxyURL specifies an http or https proxy, and targetScheme is http (not https),
// the concrete type for a Response.Body on the 101 Switching
// Protocols response, as used by WebSockets, h2c, etc.
type readWriteCloserBody struct {
+ _ incomparable
br *bufio.Reader // used until empty
io.ReadWriteCloser
}
// responseAndError is how the goroutine reading from an HTTP/1 server
// communicates with the goroutine doing the RoundTrip.
type responseAndError struct {
+ _ incomparable
res *Response // else use this response (see res method)
err error
}
type requestAndChan struct {
+ _ incomparable
req *Request
ch chan responseAndError // unbuffered; always send in select on callerGone
// gzipReader wraps a response body so it can lazily
// call gzip.NewReader on the first call to Read
type gzipReader struct {
+ _ incomparable
body *bodyEOFSignal // underlying HTTP/1 response body framing
zr *gzip.Reader // lazily-initialized gzip reader
zerr error // any error from gzip.NewReader; sticky