blob: bf28083eefc494e447e9949785c727de8077c413 [file] [edit]
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package http2
import (
"context"
"fmt"
"net"
"net/http"
"net/textproto"
"sync"
"testing"
"time"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/internal/httpcommon"
)
const (
DefaultMaxReadFrameSize = defaultMaxReadFrameSize
DefaultMaxStreams = defaultMaxStreams
InflowMinRefresh = inflowMinRefresh
InitialHeaderTableSize = initialHeaderTableSize
InitialMaxConcurrentStreams = initialMaxConcurrentStreams
InitialWindowSize = initialWindowSize
MaxFrameSize = maxFrameSize
MaxQueuedControlFrames = maxQueuedControlFrames
MinMaxFrameSize = minMaxFrameSize
)
type (
ServerConn = serverConn
Stream = stream
StreamState = streamState
PseudoHeaderError = pseudoHeaderError
HeaderFieldNameError = headerFieldNameError
HeaderFieldValueError = headerFieldValueError
)
const (
StateIdle = stateIdle
StateOpen = stateOpen
StateHalfClosedLocal = stateHalfClosedLocal
StateHalfClosedRemote = stateHalfClosedRemote
StateClosed = stateClosed
)
var (
ErrClientConnForceClosed = errClientConnForceClosed
ErrClientConnNotEstablished = errClientConnNotEstablished
ErrClientConnUnusable = errClientConnUnusable
ErrExtendedConnectNotSupported = errExtendedConnectNotSupported
ErrReqBodyTooLong = errReqBodyTooLong
ErrRequestHeaderListSize = errRequestHeaderListSize
ErrResponseHeaderListSize = errResponseHeaderListSize
)
func (s *Server) TestServeConn(c net.Conn, opts *ServeConnOpts, newf func(*serverConn)) {
s.serveConn(c, opts, newf)
}
func (sc *serverConn) TestFlowControlConsumed() (consumed int32) {
conf := configFromServer(sc.hs, sc.srv)
donec := make(chan struct{})
sc.sendServeMsg(func(sc *serverConn) {
defer close(donec)
initial := conf.MaxUploadBufferPerConnection
avail := sc.inflow.avail + sc.inflow.unsent
consumed = initial - avail
})
<-donec
return consumed
}
func (sc *serverConn) TestStreamExists(id uint32) bool {
ch := make(chan bool, 1)
sc.serveMsgCh <- func(int) {
ch <- (sc.streams[id] != nil)
}
return <-ch
}
func (sc *serverConn) TestStreamState(id uint32) streamState {
ch := make(chan streamState, 1)
sc.serveMsgCh <- func(int) {
state, _ := sc.state(id)
ch <- state
}
return <-ch
}
func (sc *serverConn) StartGracefulShutdown() { sc.startGracefulShutdown() }
func (sc *serverConn) TestHPACKEncoder() *hpack.Encoder {
return sc.hpackEncoder
}
func (sc *serverConn) TestFramerMaxHeaderStringLen() int {
return sc.framer.maxHeaderStringLen()
}
func (t *Transport) DialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {
return t.dialClientConn(ctx, addr, singleUse)
}
func (t *Transport) TestNewClientConn(c net.Conn, singleUse bool, internalStateHook func()) (*ClientConn, error) {
return t.newClientConn(c, singleUse, internalStateHook)
}
func (t *Transport) TestSetNewClientConnHook(f func(*ClientConn)) {
t.transportTestHooks = &transportTestHooks{
newclientconn: f,
}
}
func (t *Transport) TestTransport() *http.Transport {
if t.t1 == nil {
t.t1 = &http.Transport{}
}
return t.t1
}
func (cc *ClientConn) TestNetConn() net.Conn { return cc.tconn }
func (cc *ClientConn) TestSetNetConn(c net.Conn) { cc.tconn = c }
func (cc *ClientConn) TestRoundTrip(req *http.Request, f func(stremaID uint32)) (*http.Response, error) {
return cc.roundTrip(req, func(cs *clientStream) {
f(cs.ID)
})
}
func (cc *ClientConn) TestHPACKEncoder() *hpack.Encoder {
return cc.henc
}
func (cc *ClientConn) TestPeerMaxHeaderTableSize() uint32 {
cc.mu.Lock()
defer cc.mu.Unlock()
return cc.peerMaxHeaderTableSize
}
func (cc *ClientConn) TestInflowWindow(streamID uint32) (int32, error) {
cc.mu.Lock()
defer cc.mu.Unlock()
if streamID == 0 {
return cc.inflow.avail + cc.inflow.unsent, nil
}
cs := cc.streams[streamID]
if cs == nil {
return -1, fmt.Errorf("no stream with id %v", streamID)
}
return cs.inflow.avail + cs.inflow.unsent, nil
}
func (fr *Framer) TestSetDebugReadLoggerf(f func(string, ...any)) {
fr.logReads = true
fr.debugReadLoggerf = f
}
func (fr *Framer) TestSetDebugWriteLoggerf(f func(string, ...any)) {
fr.logWrites = true
fr.debugWriteLoggerf = f
}
func SummarizeFrame(f Frame) string {
return summarizeFrame(f)
}
func SetTestHookGetServerConn(t testing.TB, f func(*serverConn)) {
SetForTest(t, &testHookGetServerConn, f)
}
func init() {
testHookOnPanicMu = new(sync.Mutex)
}
func SetTestHookOnPanic(t testing.TB, f func(sc *serverConn, panicVal interface{}) (rePanic bool)) {
testHookOnPanicMu.Lock()
defer testHookOnPanicMu.Unlock()
old := testHookOnPanic
testHookOnPanic = f
t.Cleanup(func() {
testHookOnPanicMu.Lock()
defer testHookOnPanicMu.Unlock()
testHookOnPanic = old
})
}
func SetTestHookGot1xx(t testing.TB, f func(int, textproto.MIMEHeader) error) {
SetForTest(t, &got1xxFuncForTests, f)
}
func SetDisableExtendedConnectProtocol(t testing.TB, v bool) {
SetForTest(t, &disableExtendedConnectProtocol, v)
}
func LogFrameReads() bool { return logFrameReads }
func LogFrameWrites() bool { return logFrameWrites }
const GoAwayTimeout = 25 * time.Millisecond
func init() {
goAwayTimeout = GoAwayTimeout
}
func EncodeHeaderRaw(t testing.TB, headers ...string) []byte {
return encodeHeaderRaw(t, headers...)
}
func NewPriorityWriteSchedulerRFC7540(cfg *PriorityWriteSchedulerConfig) WriteScheduler {
return newPriorityWriteSchedulerRFC7540(cfg)
}
func NewPriorityWriteSchedulerRFC9218() WriteScheduler {
return newPriorityWriteSchedulerRFC9218()
}
func NewRoundRobinWriteScheduler() WriteScheduler {
return newRoundRobinWriteScheduler()
}
func DisableGoroutineTracking(t testing.TB) {
disableDebugGoroutines.Store(true)
t.Cleanup(func() {
disableDebugGoroutines.Store(false)
})
}
func InvalidHTTP1LookingFrameHeader() FrameHeader {
return invalidHTTP1LookingFrameHeader()
}
func NewNoDialClientConnPool() ClientConnPool {
return noDialClientConnPool{new(clientConnPool)}
}
func EncodeRequestHeaders(req *http.Request, addGzipHeader bool, peerMaxHeaderListSize uint64, headerf func(name, value string)) (httpcommon.EncodeHeadersResult, error) {
return encodeRequestHeaders(req, addGzipHeader, peerMaxHeaderListSize, headerf)
}