Source file src/net/http/internal/http2/config.go

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package http2
     6  
     7  import (
     8  	"math"
     9  	"time"
    10  )
    11  
    12  // Config must be kept in sync with net/http.HTTP2Config.
    13  type Config struct {
    14  	MaxConcurrentStreams          int
    15  	StrictMaxConcurrentRequests   bool
    16  	MaxDecoderHeaderTableSize     int
    17  	MaxEncoderHeaderTableSize     int
    18  	MaxReadFrameSize              int
    19  	MaxReceiveBufferPerConnection int
    20  	MaxReceiveBufferPerStream     int
    21  	SendPingTimeout               time.Duration
    22  	PingTimeout                   time.Duration
    23  	WriteByteTimeout              time.Duration
    24  	PermitProhibitedCipherSuites  bool
    25  	CountError                    func(errType string)
    26  }
    27  
    28  func configFromServer(h1 ServerConfig, h2 *Server) Config {
    29  	conf := Config{
    30  		MaxConcurrentStreams:          int(h2.MaxConcurrentStreams),
    31  		MaxEncoderHeaderTableSize:     int(h2.MaxEncoderHeaderTableSize),
    32  		MaxDecoderHeaderTableSize:     int(h2.MaxDecoderHeaderTableSize),
    33  		MaxReadFrameSize:              int(h2.MaxReadFrameSize),
    34  		MaxReceiveBufferPerConnection: int(h2.MaxUploadBufferPerConnection),
    35  		MaxReceiveBufferPerStream:     int(h2.MaxUploadBufferPerStream),
    36  		SendPingTimeout:               h2.ReadIdleTimeout,
    37  		PingTimeout:                   h2.PingTimeout,
    38  		WriteByteTimeout:              h2.WriteByteTimeout,
    39  		PermitProhibitedCipherSuites:  h2.PermitProhibitedCipherSuites,
    40  		CountError:                    h2.CountError,
    41  	}
    42  	fillNetHTTPConfig(&conf, h1.HTTP2Config())
    43  	setConfigDefaults(&conf, true)
    44  	return conf
    45  }
    46  
    47  func configFromTransport(h2 *Transport) Config {
    48  	conf := Config{
    49  		MaxEncoderHeaderTableSize: int(h2.MaxEncoderHeaderTableSize),
    50  		MaxDecoderHeaderTableSize: int(h2.MaxDecoderHeaderTableSize),
    51  		MaxReadFrameSize:          int(h2.MaxReadFrameSize),
    52  		SendPingTimeout:           h2.ReadIdleTimeout,
    53  		PingTimeout:               h2.PingTimeout,
    54  		WriteByteTimeout:          h2.WriteByteTimeout,
    55  	}
    56  
    57  	// Unlike most config fields, where out-of-range values revert to the default,
    58  	// Transport.MaxReadFrameSize clips.
    59  	if conf.MaxReadFrameSize < minMaxFrameSize {
    60  		conf.MaxReadFrameSize = minMaxFrameSize
    61  	} else if conf.MaxReadFrameSize > maxFrameSize {
    62  		conf.MaxReadFrameSize = maxFrameSize
    63  	}
    64  
    65  	if h2.t1 != nil {
    66  		fillNetHTTPConfig(&conf, h2.t1.HTTP2Config())
    67  	}
    68  
    69  	setConfigDefaults(&conf, false)
    70  	return conf
    71  }
    72  
    73  func setDefault[T ~int | ~int32 | ~uint32 | ~int64](v *T, minval, maxval, defval T) {
    74  	if *v < minval || *v > maxval {
    75  		*v = defval
    76  	}
    77  }
    78  
    79  func setConfigDefaults(conf *Config, server bool) {
    80  	setDefault(&conf.MaxConcurrentStreams, 1, math.MaxInt32, defaultMaxStreams)
    81  	setDefault(&conf.MaxEncoderHeaderTableSize, 1, math.MaxInt32, initialHeaderTableSize)
    82  	setDefault(&conf.MaxDecoderHeaderTableSize, 1, math.MaxInt32, initialHeaderTableSize)
    83  	if server {
    84  		setDefault(&conf.MaxReceiveBufferPerConnection, initialWindowSize, math.MaxInt32, 1<<20)
    85  	} else {
    86  		setDefault(&conf.MaxReceiveBufferPerConnection, initialWindowSize, math.MaxInt32, transportDefaultConnFlow)
    87  	}
    88  	if server {
    89  		setDefault(&conf.MaxReceiveBufferPerStream, 1, math.MaxInt32, 1<<20)
    90  	} else {
    91  		setDefault(&conf.MaxReceiveBufferPerStream, 1, math.MaxInt32, transportDefaultStreamFlow)
    92  	}
    93  	setDefault(&conf.MaxReadFrameSize, minMaxFrameSize, maxFrameSize, defaultMaxReadFrameSize)
    94  	setDefault(&conf.PingTimeout, 1, math.MaxInt64, 15*time.Second)
    95  }
    96  
    97  // adjustHTTP1MaxHeaderSize converts a limit in bytes on the size of an HTTP/1 header
    98  // to an HTTP/2 MAX_HEADER_LIST_SIZE value.
    99  func adjustHTTP1MaxHeaderSize(n int64) int64 {
   100  	// http2's count is in a slightly different unit and includes 32 bytes per pair.
   101  	// So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
   102  	const perFieldOverhead = 32 // per http2 spec
   103  	const typicalHeaders = 10   // conservative
   104  	return n + typicalHeaders*perFieldOverhead
   105  }
   106  
   107  func fillNetHTTPConfig(conf *Config, h2 Config) {
   108  	if h2.MaxConcurrentStreams != 0 {
   109  		conf.MaxConcurrentStreams = h2.MaxConcurrentStreams
   110  	}
   111  	if h2.StrictMaxConcurrentRequests {
   112  		conf.StrictMaxConcurrentRequests = true
   113  	}
   114  	if h2.MaxEncoderHeaderTableSize != 0 {
   115  		conf.MaxEncoderHeaderTableSize = h2.MaxEncoderHeaderTableSize
   116  	}
   117  	if h2.MaxDecoderHeaderTableSize != 0 {
   118  		conf.MaxDecoderHeaderTableSize = h2.MaxDecoderHeaderTableSize
   119  	}
   120  	if h2.MaxConcurrentStreams != 0 {
   121  		conf.MaxConcurrentStreams = h2.MaxConcurrentStreams
   122  	}
   123  	if h2.MaxReadFrameSize != 0 {
   124  		conf.MaxReadFrameSize = h2.MaxReadFrameSize
   125  	}
   126  	if h2.MaxReceiveBufferPerConnection != 0 {
   127  		conf.MaxReceiveBufferPerConnection = h2.MaxReceiveBufferPerConnection
   128  	}
   129  	if h2.MaxReceiveBufferPerStream != 0 {
   130  		conf.MaxReceiveBufferPerStream = h2.MaxReceiveBufferPerStream
   131  	}
   132  	if h2.SendPingTimeout != 0 {
   133  		conf.SendPingTimeout = h2.SendPingTimeout
   134  	}
   135  	if h2.PingTimeout != 0 {
   136  		conf.PingTimeout = h2.PingTimeout
   137  	}
   138  	if h2.WriteByteTimeout != 0 {
   139  		conf.WriteByteTimeout = h2.WriteByteTimeout
   140  	}
   141  	if h2.PermitProhibitedCipherSuites {
   142  		conf.PermitProhibitedCipherSuites = true
   143  	}
   144  	if h2.CountError != nil {
   145  		conf.CountError = h2.CountError
   146  	}
   147  }
   148  

View as plain text