Skip to content

Commit d0373d2

Browse files
committedMar 6, 2024
merge upstream net/http: 2024-01-30(e8b5bc)
1 parent c0a83bd commit d0373d2

10 files changed

+1404
-236
lines changed
 

‎internal/bisect/bisect.go

+794
Large diffs are not rendered by default.

‎internal/godebug/godebug.go

+230-19
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,244 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// Package godebug parses the GODEBUG environment variable.
5+
// Package godebug makes the settings in the $GODEBUG environment variable
6+
// available to other packages. These settings are often used for compatibility
7+
// tweaks, when we need to change a default behavior but want to let users
8+
// opt back in to the original. For example GODEBUG=http2server=0 disables
9+
// HTTP/2 support in the net/http server.
10+
//
11+
// In typical usage, code should declare a Setting as a global
12+
// and then call Value each time the current setting value is needed:
13+
//
14+
// var http2server = godebug.New("http2server")
15+
//
16+
// func ServeConn(c net.Conn) {
17+
// if http2server.Value() == "0" {
18+
// disallow HTTP/2
19+
// ...
20+
// }
21+
// ...
22+
// }
23+
//
24+
// Each time a non-default setting causes a change in program behavior,
25+
// code should call [Setting.IncNonDefault] to increment a counter that can
26+
// be reported by [runtime/metrics.Read].
27+
// Note that counters used with IncNonDefault must be added to
28+
// various tables in other packages. See the [Setting.IncNonDefault]
29+
// documentation for details.
630
package godebug
731

8-
import "os"
32+
// Note: Be careful about new imports here. Any package
33+
// that internal/godebug imports cannot itself import internal/godebug,
34+
// meaning it cannot introduce a GODEBUG setting of its own.
35+
// We keep imports to the absolute bare minimum.
36+
import (
37+
"sync"
38+
"sync/atomic"
39+
_ "unsafe" // go:linkname
940

10-
// Get returns the value for the provided GODEBUG key.
11-
func Get(key string) string {
12-
return get(os.Getenv("GODEBUG"), key)
41+
"github.com/imroc/req/v3/internal/bisect"
42+
"github.com/imroc/req/v3/internal/godebugs"
43+
)
44+
45+
// A Setting is a single setting in the $GODEBUG environment variable.
46+
type Setting struct {
47+
name string
48+
once sync.Once
49+
*setting
50+
}
51+
52+
type setting struct {
53+
value atomic.Pointer[value]
54+
nonDefaultOnce sync.Once
55+
nonDefault atomic.Uint64
56+
info *godebugs.Info
57+
}
58+
59+
type value struct {
60+
text string
61+
bisect *bisect.Matcher
62+
}
63+
64+
// New returns a new Setting for the $GODEBUG setting with the given name.
65+
//
66+
// GODEBUGs meant for use by end users must be listed in ../godebugs/table.go,
67+
// which is used for generating and checking various documentation.
68+
// If the name is not listed in that table, New will succeed but calling Value
69+
// on the returned Setting will panic.
70+
// To disable that panic for access to an undocumented setting,
71+
// prefix the name with a #, as in godebug.New("#gofsystrace").
72+
// The # is a signal to New but not part of the key used in $GODEBUG.
73+
func New(name string) *Setting {
74+
return &Setting{name: name}
75+
}
76+
77+
// Name returns the name of the setting.
78+
func (s *Setting) Name() string {
79+
if s.name != "" && s.name[0] == '#' {
80+
return s.name[1:]
81+
}
82+
return s.name
1383
}
1484

15-
// get returns the value part of key=value in s (a GODEBUG value).
16-
func get(s, key string) string {
17-
for i := 0; i < len(s)-len(key)-1; i++ {
18-
if i > 0 && s[i-1] != ',' {
19-
continue
85+
// Undocumented reports whether this is an undocumented setting.
86+
func (s *Setting) Undocumented() bool {
87+
return s.name != "" && s.name[0] == '#'
88+
}
89+
90+
// String returns a printable form for the setting: name=value.
91+
func (s *Setting) String() string {
92+
return s.Name() + "=" + s.Value()
93+
}
94+
95+
// IncNonDefault increments the non-default behavior counter
96+
// associated with the given setting.
97+
// This counter is exposed in the runtime/metrics value
98+
// /godebug/non-default-behavior/<name>:events.
99+
//
100+
// Note that Value must be called at least once before IncNonDefault.
101+
func (s *Setting) IncNonDefault() {
102+
s.nonDefaultOnce.Do(s.register)
103+
s.nonDefault.Add(1)
104+
}
105+
106+
func (s *Setting) register() {
107+
if s.info == nil || s.info.Opaque {
108+
panic("godebug: unexpected IncNonDefault of " + s.name)
109+
}
110+
}
111+
112+
// cache is a cache of all the GODEBUG settings,
113+
// a locked map[string]*atomic.Pointer[string].
114+
//
115+
// All Settings with the same name share a single
116+
// *atomic.Pointer[string], so that when GODEBUG
117+
// changes only that single atomic string pointer
118+
// needs to be updated.
119+
//
120+
// A name appears in the values map either if it is the
121+
// name of a Setting for which Value has been called
122+
// at least once, or if the name has ever appeared in
123+
// a name=value pair in the $GODEBUG environment variable.
124+
// Once entered into the map, the name is never removed.
125+
var cache sync.Map // name string -> value *atomic.Pointer[string]
126+
127+
var empty value
128+
129+
// Value returns the current value for the GODEBUG setting s.
130+
//
131+
// Value maintains an internal cache that is synchronized
132+
// with changes to the $GODEBUG environment variable,
133+
// making Value efficient to call as frequently as needed.
134+
// Clients should therefore typically not attempt their own
135+
// caching of Value's result.
136+
func (s *Setting) Value() string {
137+
s.once.Do(func() {
138+
s.setting = lookup(s.Name())
139+
if s.info == nil && !s.Undocumented() {
140+
panic("godebug: Value of name not listed in godebugs.All: " + s.name)
20141
}
21-
afterKey := s[i+len(key):]
22-
if afterKey[0] != '=' || s[i:i+len(key)] != key {
23-
continue
142+
})
143+
v := *s.value.Load()
144+
if v.bisect != nil && !v.bisect.Stack(&stderr) {
145+
return ""
146+
}
147+
return v.text
148+
}
149+
150+
// lookup returns the unique *setting value for the given name.
151+
func lookup(name string) *setting {
152+
if v, ok := cache.Load(name); ok {
153+
return v.(*setting)
154+
}
155+
s := new(setting)
156+
s.info = godebugs.Lookup(name)
157+
s.value.Store(&empty)
158+
if v, loaded := cache.LoadOrStore(name, s); loaded {
159+
// Lost race: someone else created it. Use theirs.
160+
return v.(*setting)
161+
}
162+
163+
return s
164+
}
165+
166+
func newIncNonDefault(name string) func() {
167+
s := New(name)
168+
s.Value()
169+
return s.IncNonDefault
170+
}
171+
172+
var updateMu sync.Mutex
173+
174+
// update records an updated GODEBUG setting.
175+
// def is the default GODEBUG setting for the running binary,
176+
// and env is the current value of the $GODEBUG environment variable.
177+
func update(def, env string) {
178+
updateMu.Lock()
179+
defer updateMu.Unlock()
180+
181+
// Update all the cached values, creating new ones as needed.
182+
// We parse the environment variable first, so that any settings it has
183+
// are already locked in place (did[name] = true) before we consider
184+
// the defaults.
185+
did := make(map[string]bool)
186+
parse(did, env)
187+
parse(did, def)
188+
189+
// Clear any cached values that are no longer present.
190+
cache.Range(func(name, s any) bool {
191+
if !did[name.(string)] {
192+
s.(*setting).value.Store(&empty)
24193
}
25-
val := afterKey[1:]
26-
for i, b := range val {
27-
if b == ',' {
28-
return val[:i]
194+
return true
195+
})
196+
}
197+
198+
// parse parses the GODEBUG setting string s,
199+
// which has the form k=v,k2=v2,k3=v3.
200+
// Later settings override earlier ones.
201+
// Parse only updates settings k=v for which did[k] = false.
202+
// It also sets did[k] = true for settings that it updates.
203+
// Each value v can also have the form v#pattern,
204+
// in which case the GODEBUG is only enabled for call stacks
205+
// matching pattern, for use with golang.org/x/tools/cmd/bisect.
206+
func parse(did map[string]bool, s string) {
207+
// Scan the string backward so that later settings are used
208+
// and earlier settings are ignored.
209+
// Note that a forward scan would cause cached values
210+
// to temporarily use the ignored value before being
211+
// updated to the "correct" one.
212+
end := len(s)
213+
eq := -1
214+
for i := end - 1; i >= -1; i-- {
215+
if i == -1 || s[i] == ',' {
216+
if eq >= 0 {
217+
name, arg := s[i+1:eq], s[eq+1:end]
218+
if !did[name] {
219+
did[name] = true
220+
v := &value{text: arg}
221+
for j := 0; j < len(arg); j++ {
222+
if arg[j] == '#' {
223+
v.text = arg[:j]
224+
v.bisect, _ = bisect.New(arg[j+1:])
225+
break
226+
}
227+
}
228+
lookup(name).value.Store(v)
229+
}
29230
}
231+
eq = -1
232+
end = i
233+
} else if s[i] == '=' {
234+
eq = i
30235
}
31-
return val
32236
}
33-
return ""
237+
}
238+
239+
type runtimeStderr struct{}
240+
241+
var stderr runtimeStderr
242+
243+
func (*runtimeStderr) Write(b []byte) (int, error) {
244+
return len(b), nil
34245
}

‎internal/godebug/godebug_test.go

-34
This file was deleted.

‎internal/godebugs/table.go

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2023 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 godebugs provides a table of known GODEBUG settings,
6+
// for use by a variety of other packages, including internal/godebug,
7+
// runtime, runtime/metrics, and cmd/go/internal/load.
8+
package godebugs
9+
10+
// An Info describes a single known GODEBUG setting.
11+
type Info struct {
12+
Name string // name of the setting ("panicnil")
13+
Package string // package that uses the setting ("runtime")
14+
Changed int // minor version when default changed, if any; 21 means Go 1.21
15+
Old string // value that restores behavior prior to Changed
16+
Opaque bool // setting does not export information to runtime/metrics using [internal/godebug.Setting.IncNonDefault]
17+
}
18+
19+
// All is the table of known settings, sorted by Name.
20+
//
21+
// Note: After adding entries to this table, run 'go generate runtime/metrics'
22+
// to update the runtime/metrics doc comment.
23+
// (Otherwise the runtime/metrics test will fail.)
24+
//
25+
// Note: After adding entries to this table, update the list in doc/godebug.md as well.
26+
// (Otherwise the test in this package will fail.)
27+
var All = []Info{
28+
{Name: "execerrdot", Package: "os/exec"},
29+
{Name: "gocachehash", Package: "cmd/go"},
30+
{Name: "gocachetest", Package: "cmd/go"},
31+
{Name: "gocacheverify", Package: "cmd/go"},
32+
{Name: "gotypesalias", Package: "go/types"},
33+
{Name: "http2client", Package: "net/http"},
34+
{Name: "http2debug", Package: "net/http", Opaque: true},
35+
{Name: "http2server", Package: "net/http"},
36+
{Name: "httplaxcontentlength", Package: "net/http", Changed: 22, Old: "1"},
37+
{Name: "httpmuxgo121", Package: "net/http", Changed: 22, Old: "1"},
38+
{Name: "installgoroot", Package: "go/build"},
39+
{Name: "jstmpllitinterp", Package: "html/template"},
40+
//{Name: "multipartfiles", Package: "mime/multipart"},
41+
{Name: "multipartmaxheaders", Package: "mime/multipart"},
42+
{Name: "multipartmaxparts", Package: "mime/multipart"},
43+
{Name: "multipathtcp", Package: "net"},
44+
{Name: "netdns", Package: "net", Opaque: true},
45+
{Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
46+
{Name: "randautoseed", Package: "math/rand"},
47+
{Name: "tarinsecurepath", Package: "archive/tar"},
48+
{Name: "tls10server", Package: "crypto/tls", Changed: 22, Old: "1"},
49+
{Name: "tlsmaxrsasize", Package: "crypto/tls"},
50+
{Name: "tlsrsakex", Package: "crypto/tls", Changed: 22, Old: "1"},
51+
{Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"},
52+
{Name: "winreadlinkvolume", Package: "os", Changed: 22, Old: "0"},
53+
{Name: "winsymlink", Package: "os", Changed: 22, Old: "0"},
54+
{Name: "x509sha1", Package: "crypto/x509"},
55+
{Name: "x509usefallbackroots", Package: "crypto/x509"},
56+
{Name: "x509usepolicies", Package: "crypto/x509"},
57+
{Name: "zipinsecurepath", Package: "archive/zip"},
58+
}
59+
60+
// Lookup returns the Info with the given name.
61+
func Lookup(name string) *Info {
62+
// binary search, avoiding import of sort.
63+
lo := 0
64+
hi := len(All)
65+
for lo < hi {
66+
m := int(uint(lo+hi) >> 1)
67+
mid := All[m].Name
68+
if name == mid {
69+
return &All[m]
70+
}
71+
if name < mid {
72+
hi = m
73+
} else {
74+
lo = m + 1
75+
}
76+
}
77+
return nil
78+
}

0 commit comments

Comments
 (0)
Please sign in to comment.