diff options
Diffstat (limited to 'libgo/go/net/http/h2_bundle.go')
-rw-r--r-- | libgo/go/net/http/h2_bundle.go | 75 |
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 |