summaryrefslogtreecommitdiff
path: root/libgo/go/net/http/h2_bundle.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/http/h2_bundle.go')
-rw-r--r--libgo/go/net/http/h2_bundle.go75
1 files changed, 40 insertions, 35 deletions
diff --git a/libgo/go/net/http/h2_bundle.go b/libgo/go/net/http/h2_bundle.go
index f03dbba729b..779da4fdfdf 100644
--- a/libgo/go/net/http/h2_bundle.go
+++ b/libgo/go/net/http/h2_bundle.go
@@ -783,6 +783,7 @@ func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMis
// dialCall is an in-flight Transport dial call to a host.
type http2dialCall struct {
+ _ http2incomparable
p *http2clientConnPool
done chan struct{} // closed when done
res *http2ClientConn // valid after done is closed
@@ -856,6 +857,7 @@ func (p *http2clientConnPool) addConnIfNeeded(key string, t *http2Transport, c *
}
type http2addConnCall struct {
+ _ http2incomparable
p *http2clientConnPool
done chan struct{} // closed when done
err error
@@ -876,12 +878,6 @@ func (c *http2addConnCall) run(t *http2Transport, key string, tc *tls.Conn) {
close(c.done)
}
-func (p *http2clientConnPool) addConn(key string, cc *http2ClientConn) {
- p.mu.Lock()
- p.addConnLocked(key, cc)
- p.mu.Unlock()
-}
-
// p.mu must be held
func (p *http2clientConnPool) addConnLocked(key string, cc *http2ClientConn) {
for _, v := range p.conns[key] {
@@ -1219,6 +1215,8 @@ var (
// flow is the flow control window's size.
type http2flow struct {
+ _ http2incomparable
+
// n is the number of DATA bytes we're allowed to send.
// A flow is kept both on a conn and a per-stream.
n int32
@@ -3245,11 +3243,6 @@ func (s http2SettingID) String() string {
return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
}
-var (
- http2errInvalidHeaderFieldName = errors.New("http2: invalid header field name")
- http2errInvalidHeaderFieldValue = errors.New("http2: invalid header field value")
-)
-
// validWireHeaderFieldName reports whether v is a valid header field
// name (key). See httpguts.ValidHeaderName for the base rules.
//
@@ -3320,6 +3313,7 @@ func (cw http2closeWaiter) Wait() {
// Its buffered writer is lazily allocated as needed, to minimize
// idle memory usage with many connections.
type http2bufferedWriter struct {
+ _ http2incomparable
w io.Writer // immutable
bw *bufio.Writer // non-nil when data is buffered
}
@@ -3392,6 +3386,7 @@ func http2bodyAllowedForStatus(status int) bool {
}
type http2httpError struct {
+ _ http2incomparable
msg string
timeout bool
}
@@ -3460,6 +3455,11 @@ func http2validPseudoPath(v string) bool {
return (len(v) > 0 && v[0] == '/') || v == "*"
}
+// 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 http2incomparable [0]func()
+
// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
// io.Pipe except there are no PipeReader/PipeWriter halves, and the
// underlying buffer is an interface. (io.Pipe is always unbuffered)
@@ -4147,13 +4147,10 @@ type http2stream struct {
cancelCtx func()
// owned by serverConn's serve loop:
- bodyBytes int64 // body bytes seen so far
- declBodyBytes int64 // or -1 if undeclared
- flow http2flow // limits writing from Handler to client
- inflow http2flow // what the client is allowed to POST/etc to us
- parent *http2stream // or nil
- numTrailerValues int64
- weight uint8
+ bodyBytes int64 // body bytes seen so far
+ declBodyBytes int64 // or -1 if undeclared
+ flow http2flow // limits writing from Handler to client
+ inflow http2flow // what the client is allowed to POST/etc to us
state http2streamState
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
gotTrailerHeader bool // HEADER frame for trailers was seen
@@ -4333,6 +4330,7 @@ func (sc *http2serverConn) readFrames() {
// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
type http2frameWriteResult struct {
+ _ http2incomparable
wr http2FrameWriteRequest // what was written (or attempted)
err error // result of the writeFrame call
}
@@ -4343,7 +4341,7 @@ type http2frameWriteResult struct {
// serverConn.
func (sc *http2serverConn) writeFrameAsync(wr http2FrameWriteRequest) {
err := wr.write.writeFrame(sc)
- sc.wroteFrameCh <- http2frameWriteResult{wr, err}
+ sc.wroteFrameCh <- http2frameWriteResult{wr: wr, err: err}
}
func (sc *http2serverConn) closeAllStreamsOnConnClose() {
@@ -4735,7 +4733,7 @@ func (sc *http2serverConn) startFrameWrite(wr http2FrameWriteRequest) {
if wr.write.staysWithinBuffer(sc.bw.Available()) {
sc.writingFrameAsync = false
err := wr.write.writeFrame(sc)
- sc.wroteFrame(http2frameWriteResult{wr, err})
+ sc.wroteFrame(http2frameWriteResult{wr: wr, err: err})
} else {
sc.writingFrameAsync = true
go sc.writeFrameAsync(wr)
@@ -5849,6 +5847,7 @@ func (sc *http2serverConn) sendWindowUpdate32(st *http2stream, n int32) {
// requestBody is the Handler's Request.Body type.
// Read and Close may be called concurrently.
type http2requestBody struct {
+ _ http2incomparable
stream *http2stream
conn *http2serverConn
closed bool // for use by Close only
@@ -6592,7 +6591,7 @@ type http2Transport struct {
// send in the initial settings frame. It is how many bytes
// of response headers are allowed. Unlike the http2 spec, zero here
// means to use a default limit (currently 10MB). If you actually
- // want to advertise an ulimited value to the peer, Transport
+ // want to advertise an unlimited value to the peer, Transport
// interprets the highest possible value here (0xffffffff or 1<<32-1)
// to mean no limit.
MaxHeaderListSize uint32
@@ -7416,7 +7415,7 @@ func http2commaSeparatedTrailers(req *Request) (string, error) {
k = CanonicalHeaderKey(k)
switch k {
case "Transfer-Encoding", "Trailer", "Content-Length":
- return "", &http2badStringError{"invalid Trailer key", k}
+ return "", fmt.Errorf("invalid Trailer key %q", k)
}
keys = append(keys, k)
}
@@ -7909,13 +7908,6 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err er
}
}
-type http2badStringError struct {
- what string
- str string
-}
-
-func (e *http2badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
-
// requires cc.mu be held.
func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) {
cc.hbuf.Reset()
@@ -8131,6 +8123,7 @@ func (cc *http2ClientConn) writeHeader(name, value string) {
}
type http2resAndError struct {
+ _ http2incomparable
res *Response
err error
}
@@ -8178,6 +8171,7 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr
// clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
type http2clientConnReadLoop struct {
+ _ http2incomparable
cc *http2ClientConn
closeWhenIdle bool
}
@@ -8407,7 +8401,9 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header")
}
- header := make(Header)
+ regularFields := f.RegularFields()
+ strs := make([]string, len(regularFields))
+ header := make(Header, len(regularFields))
res := &Response{
Proto: "HTTP/2.0",
ProtoMajor: 2,
@@ -8415,7 +8411,7 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
StatusCode: statusCode,
Status: status + " " + StatusText(statusCode),
}
- for _, hf := range f.RegularFields() {
+ for _, hf := range regularFields {
key := CanonicalHeaderKey(hf.Name)
if key == "Trailer" {
t := res.Trailer
@@ -8427,7 +8423,18 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
t[CanonicalHeaderKey(v)] = nil
})
} else {
- header[key] = append(header[key], hf.Value)
+ vv := header[key]
+ if vv == nil && len(strs) > 0 {
+ // More than likely this will be a single-element key.
+ // Most headers aren't multi-valued.
+ // Set the capacity on strs[0] to 1, so any future append
+ // won't extend the slice into the other strings.
+ vv, strs = strs[:1:1], strs[1:]
+ vv[0] = hf.Value
+ header[key] = vv
+ } else {
+ header[key] = append(vv, hf.Value)
+ }
}
}
@@ -8713,8 +8720,6 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
return nil
}
-var http2errInvalidTrailers = errors.New("http2: invalid trailers")
-
func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) {
// TODO: check that any declared content-length matches, like
// server.go's (*stream).endStream method.
@@ -8945,7 +8950,6 @@ func (cc *http2ClientConn) writeStreamReset(streamID uint32, code http2ErrCode,
var (
http2errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit")
http2errRequestHeaderListSize = errors.New("http2: request header list larger than peer's advertised limit")
- http2errPseudoTrailers = errors.New("http2: invalid pseudo header in trailers")
)
func (cc *http2ClientConn) logf(format string, args ...interface{}) {
@@ -8984,6 +8988,7 @@ func (rt http2erringRoundTripper) RoundTrip(*Request) (*Response, error) { retur
// gzipReader wraps a response body so it can lazily
// call gzip.NewReader on the first call to Read
type http2gzipReader struct {
+ _ http2incomparable
body io.ReadCloser // underlying Response.Body
zr *gzip.Reader // lazily-initialized gzip reader
zerr error // sticky error