From a130fcc1c15aa11de840aa4fdcae06efabc30ba4 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 4 Apr 2024 11:27:10 -0700 Subject: [PATCH 1/8] quic: don't consider goroutines running when tests start as leaked Change-Id: I138e284ee74c9402402f564d25e50ab753c51e9e Reviewed-on: https://go-review.googlesource.com/c/net/+/576536 Reviewed-by: Chressie Himpel LUCI-TryBot-Result: Go LUCI --- quic/main_test.go | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/quic/main_test.go b/quic/main_test.go index ecd0b1e9f..25e0096e4 100644 --- a/quic/main_test.go +++ b/quic/main_test.go @@ -16,6 +16,20 @@ import ( ) func TestMain(m *testing.M) { + // Add all goroutines running at the start of the test to the set + // of not-leaked goroutines. This includes TestMain, and anything else + // that might have been started by test infrastructure. + skip := [][]byte{ + []byte("created by os/signal.Notify"), + []byte("gotraceback_test.go"), + } + buf := make([]byte, 2<<20) + buf = buf[:runtime.Stack(buf, true)] + for _, g := range bytes.Split(buf, []byte("\n\n")) { + id, _, _ := bytes.Cut(g, []byte("[")) + skip = append(skip, id) + } + defer os.Exit(m.Run()) // Look for leaked goroutines. @@ -34,12 +48,13 @@ func TestMain(m *testing.M) { buf = buf[:runtime.Stack(buf, true)] leaked := false for _, g := range bytes.Split(buf, []byte("\n\n")) { - if bytes.Contains(g, []byte("quic.TestMain")) || - bytes.Contains(g, []byte("created by os/signal.Notify")) || - bytes.Contains(g, []byte("gotraceback_test.go")) { - continue - } leaked = true + for _, s := range skip { + if bytes.Contains(g, s) { + leaked = false + break + } + } } if !leaked { break From b67a0f0535536b3787161ec42c08549b686a5629 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 4 Apr 2024 18:18:37 -0700 Subject: [PATCH 2/8] http2: send correct LastStreamID in stream-caused GOAWAY When closing a connection because a stream contained a request we didn't like (for example, because the request headers exceed the maximum we will accept), set the LastStreamID in the GOAWAY frame to include the offending stream. This informs the client that retrying the request is unlikely to succeed, and avoids retry loops. This change requires passing the stream ID of the offending stream from Framer.ReadFrame up to the caller. The most sensible way to do this would probably be in the error. However, ReadFrame currently returns a defined error type for connection-ending errors (ConnectionError), and that type is a uint32 with no place to put the stream ID. Rather than changing the returned errors, ReadFrame now returns an error along with a non-nil Frame containing the stream ID, when a stream is responsible for a connection-ending error. For golang/go#66668 Change-Id: Iba07ccbd70ab4939aa56903605474d01703ac6e4 Reviewed-on: https://go-review.googlesource.com/c/net/+/576756 Reviewed-by: Jonathan Amsterdam Reviewed-by: Dmitri Shuralyov Auto-Submit: Damien Neil LUCI-TryBot-Result: Go LUCI --- http2/frame.go | 13 ++++++++----- http2/server.go | 5 +++++ http2/server_test.go | 10 +++++++++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/http2/frame.go b/http2/frame.go index 43557ab7e..105c3b279 100644 --- a/http2/frame.go +++ b/http2/frame.go @@ -490,6 +490,9 @@ func terminalReadFrameError(err error) bool { // returned error is ErrFrameTooLarge. Other errors may be of type // ConnectionError, StreamError, or anything else from the underlying // reader. +// +// If ReadFrame returns an error and a non-nil Frame, the Frame's StreamID +// indicates the stream responsible for the error. func (fr *Framer) ReadFrame() (Frame, error) { fr.errDetail = nil if fr.lastFrame != nil { @@ -1521,7 +1524,7 @@ func (fr *Framer) maxHeaderStringLen() int { // readMetaFrame returns 0 or more CONTINUATION frames from fr and // merge them into the provided hf and returns a MetaHeadersFrame // with the decoded hpack values. -func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) { +func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) { if fr.AllowIllegalReads { return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders") } @@ -1592,7 +1595,7 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) { } // It would be nice to send a RST_STREAM before sending the GOAWAY, // but the structure of the server's frame writer makes this difficult. - return nil, ConnectionError(ErrCodeProtocol) + return mh, ConnectionError(ErrCodeProtocol) } // Also close the connection after any CONTINUATION frame following an @@ -1604,11 +1607,11 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) { } // It would be nice to send a RST_STREAM before sending the GOAWAY, // but the structure of the server's frame writer makes this difficult. - return nil, ConnectionError(ErrCodeProtocol) + return mh, ConnectionError(ErrCodeProtocol) } if _, err := hdec.Write(frag); err != nil { - return nil, ConnectionError(ErrCodeCompression) + return mh, ConnectionError(ErrCodeCompression) } if hc.HeadersEnded() { @@ -1625,7 +1628,7 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) { mh.HeadersFrame.invalidate() if err := hdec.Close(); err != nil { - return nil, ConnectionError(ErrCodeCompression) + return mh, ConnectionError(ErrCodeCompression) } if invalid != nil { fr.errDetail = invalid diff --git a/http2/server.go b/http2/server.go index ce2e8b40e..278add72b 100644 --- a/http2/server.go +++ b/http2/server.go @@ -1482,6 +1482,11 @@ func (sc *serverConn) processFrameFromReader(res readFrameResult) bool { sc.goAway(ErrCodeFlowControl) return true case ConnectionError: + if res.f != nil { + if id := res.f.Header().StreamID; id > sc.maxClientStreamID { + sc.maxClientStreamID = id + } + } sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev) sc.goAway(ErrCode(ev)) return true // goAway will handle shutdown diff --git a/http2/server_test.go b/http2/server_test.go index a931a06e5..61c773a54 100644 --- a/http2/server_test.go +++ b/http2/server_test.go @@ -4818,9 +4818,17 @@ func TestServerContinuationFlood(t *testing.T) { if err != nil { break } - switch f.(type) { + switch f := f.(type) { case *HeadersFrame: t.Fatalf("received HEADERS frame; want GOAWAY and a closed connection") + case *GoAwayFrame: + // We might not see the GOAWAY (see below), but if we do it should + // indicate that the server processed this request so the client doesn't + // attempt to retry it. + if got, want := f.LastStreamID, uint32(1); got != want { + t.Errorf("received GOAWAY with LastStreamId %v, want %v", got, want) + } + } } // We expect to have seen a GOAWAY before the connection closes, From ec05fdcd71141c885f3fb84c41d1c692f094ccbe Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 5 Apr 2024 08:07:32 -0700 Subject: [PATCH 3/8] http2: don't retry the first request on a connection on GOAWAY error When a server sends a GOAWAY frame, it indicates the ID of the last stream it processed. We use this to mark any requests after that stream as being safe to retry on a new connection. Change this to not retry the first request on a connection if we get a GOAWAY with an error, even if the GOAWAY has a stream ID of 0 indicating that it didn't process that request. If we're getting an error as the first result on a new connection, then there's either something wrong with the server or something wrong with our request; either way, retrying isn't likely to be productive and may be unsafe. This matches the behavior of the HTTP/1 client, which also avoids retrying the first request on a new connection. For golang/go#66668 Fixes golang/go#60636 Change-Id: I90ea7cfce2974dd413f7cd8b78541678850376a5 Reviewed-on: https://go-review.googlesource.com/c/net/+/576895 LUCI-TryBot-Result: Go LUCI Reviewed-by: Jonathan Amsterdam --- http2/transport.go | 15 ++++++- http2/transport_test.go | 94 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 3 deletions(-) diff --git a/http2/transport.go b/http2/transport.go index ce375c8c7..2fa49490c 100644 --- a/http2/transport.go +++ b/http2/transport.go @@ -936,7 +936,20 @@ func (cc *ClientConn) setGoAway(f *GoAwayFrame) { } last := f.LastStreamID for streamID, cs := range cc.streams { - if streamID > last { + if streamID <= last { + // The server's GOAWAY indicates that it received this stream. + // It will either finish processing it, or close the connection + // without doing so. Either way, leave the stream alone for now. + continue + } + if streamID == 1 && cc.goAway.ErrCode != ErrCodeNo { + // Don't retry the first stream on a connection if we get a non-NO error. + // If the server is sending an error on a new connection, + // retrying the request on a new one probably isn't going to work. + cs.abortStreamLocked(fmt.Errorf("http2: Transport received GOAWAY from server ErrCode:%v", cc.goAway.ErrCode)) + } else { + // Aborting the stream with errClentConnGotGoAway indicates that + // the request should be retried on a new connection. cs.abortStreamLocked(errClientConnGotGoAway) } } diff --git a/http2/transport_test.go b/http2/transport_test.go index 11ff67b4c..3e4297f28 100644 --- a/http2/transport_test.go +++ b/http2/transport_test.go @@ -3144,13 +3144,40 @@ func TestTransportPingWhenReadingPingDisabled(t *testing.T) { } } -func TestTransportRetryAfterGOAWAY(t *testing.T) { +func TestTransportRetryAfterGOAWAYNoRetry(t *testing.T) { tt := newTestTransport(t) req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) rt := tt.roundTrip(req) - // First attempt: Server sends a GOAWAY. + // First attempt: Server sends a GOAWAY with an error and + // a MaxStreamID less than the request ID. + // This probably indicates that there was something wrong with our request, + // so we don't retry it. + tc := tt.getConn() + tc.wantFrameType(FrameSettings) + tc.wantFrameType(FrameWindowUpdate) + tc.wantHeaders(wantHeader{ + streamID: 1, + endStream: true, + }) + tc.writeSettings() + tc.writeGoAway(0 /*max id*/, ErrCodeInternal, nil) + if rt.err() == nil { + t.Fatalf("after GOAWAY, RoundTrip is not done, want error") + } +} + +func TestTransportRetryAfterGOAWAYRetry(t *testing.T) { + tt := newTestTransport(t) + + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + rt := tt.roundTrip(req) + + // First attempt: Server sends a GOAWAY with ErrCodeNo and + // a MaxStreamID less than the request ID. + // We take the server at its word that nothing has really gone wrong, + // and retry the request. tc := tt.getConn() tc.wantFrameType(FrameSettings) tc.wantFrameType(FrameWindowUpdate) @@ -3185,6 +3212,69 @@ func TestTransportRetryAfterGOAWAY(t *testing.T) { rt.wantStatus(200) } +func TestTransportRetryAfterGOAWAYSecondRequest(t *testing.T) { + tt := newTestTransport(t) + + // First request succeeds. + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + rt1 := tt.roundTrip(req) + tc := tt.getConn() + tc.wantFrameType(FrameSettings) + tc.wantFrameType(FrameWindowUpdate) + tc.wantHeaders(wantHeader{ + streamID: 1, + endStream: true, + }) + tc.writeSettings() + tc.wantFrameType(FrameSettings) // Settings ACK + tc.writeHeaders(HeadersFrameParam{ + StreamID: 1, + EndHeaders: true, + EndStream: true, + BlockFragment: tc.makeHeaderBlockFragment( + ":status", "200", + ), + }) + rt1.wantStatus(200) + + // Second request: Server sends a GOAWAY with + // a MaxStreamID less than the request ID. + // The server says it didn't see this request, + // so we retry it on a new connection. + req, _ = http.NewRequest("GET", "https://dummy.tld/", nil) + rt2 := tt.roundTrip(req) + + // Second request, first attempt. + tc.wantHeaders(wantHeader{ + streamID: 3, + endStream: true, + }) + tc.writeSettings() + tc.writeGoAway(1 /*max id*/, ErrCodeProtocol, nil) + if rt2.done() { + t.Fatalf("after GOAWAY, RoundTrip is done; want it to be retrying") + } + + // Second request, second attempt. + tc = tt.getConn() + tc.wantFrameType(FrameSettings) + tc.wantFrameType(FrameWindowUpdate) + tc.wantHeaders(wantHeader{ + streamID: 1, + endStream: true, + }) + tc.writeSettings() + tc.writeHeaders(HeadersFrameParam{ + StreamID: 1, + EndHeaders: true, + EndStream: true, + BlockFragment: tc.makeHeaderBlockFragment( + ":status", "200", + ), + }) + rt2.wantStatus(200) +} + func TestTransportRetryAfterRefusedStream(t *testing.T) { tt := newTestTransport(t) From 0a24555f5cc06e8caf23d84a4f8b7102dcab838e Mon Sep 17 00:00:00 2001 From: Julien Cretel Date: Wed, 10 Apr 2024 23:08:43 +0000 Subject: [PATCH 4/8] http/httpguts: speed up ValidHeaderFieldName MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminate bounds checks and eschews UTF-8 decoding in ValidHeaderFieldName, thereby doubling its speed without introducing any allocations. Also eliminate bounds checks in IsTokenRune. Add tests and benchmarks for both ValidHeaderFieldName and IsTokenRune. goos: darwin goarch: amd64 pkg: golang.org/x/net/http/httpguts cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz │ before │ after │ │ sec/op │ sec/op vs base │ IsTokenRune-8 315.2n ± 0% 316.2n ± 1% ~ (p=0.245 n=20) ValidHeaderFieldName-8 62.77n ± 0% 29.16n ± 0% -53.55% (p=0.000 n=20) geomean 140.7n 96.02n -31.73% │ before │ after │ │ B/op │ B/op vs base │ IsTokenRune-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) ValidHeaderFieldName-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) geomean ² +0.00% │ before │ after │ │ allocs/op │ allocs/op vs base │ IsTokenRune-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) ValidHeaderFieldName-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) geomean ² +0.00% Fixes golang/go#66700 Change-Id: Ia3ea80e5f0d173e3a69eb7429023587fd7bc5933 GitHub-Last-Rev: 1f1d25d1ecc34dca5d573c89d673dc634520df33 GitHub-Pull-Request: golang/net#207 Reviewed-on: https://go-review.googlesource.com/c/net/+/578075 Run-TryBot: Emmanuel Odeke Reviewed-by: Damien Neil Reviewed-by: Dmitri Shuralyov TryBot-Result: Gopher Robot LUCI-TryBot-Result: Go LUCI --- http/httpguts/httplex.go | 13 +++------- http/httpguts/httplex_test.go | 49 ++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/http/httpguts/httplex.go b/http/httpguts/httplex.go index 6e071e852..9b4de9401 100644 --- a/http/httpguts/httplex.go +++ b/http/httpguts/httplex.go @@ -12,7 +12,7 @@ import ( "golang.org/x/net/idna" ) -var isTokenTable = [127]bool{ +var isTokenTable = [256]bool{ '!': true, '#': true, '$': true, @@ -93,12 +93,7 @@ var isTokenTable = [127]bool{ } func IsTokenRune(r rune) bool { - i := int(r) - return i < len(isTokenTable) && isTokenTable[i] -} - -func isNotToken(r rune) bool { - return !IsTokenRune(r) + return r < utf8.RuneSelf && isTokenTable[byte(r)] } // HeaderValuesContainsToken reports whether any string in values @@ -202,8 +197,8 @@ func ValidHeaderFieldName(v string) bool { if len(v) == 0 { return false } - for _, r := range v { - if !IsTokenRune(r) { + for i := 0; i < len(v); i++ { + if !isTokenTable[v[i]] { return false } } diff --git a/http/httpguts/httplex_test.go b/http/httpguts/httplex_test.go index a2c57f392..791440b1a 100644 --- a/http/httpguts/httplex_test.go +++ b/http/httpguts/httplex_test.go @@ -20,7 +20,7 @@ func isSeparator(c rune) bool { return false } -func TestIsToken(t *testing.T) { +func TestIsTokenRune(t *testing.T) { for i := 0; i <= 130; i++ { r := rune(i) expected := isChar(r) && !isCtl(r) && !isSeparator(r) @@ -30,6 +30,15 @@ func TestIsToken(t *testing.T) { } } +func BenchmarkIsTokenRune(b *testing.B) { + for i := 0; i < b.N; i++ { + var r rune + for ; r < 1024; r++ { + IsTokenRune(r) + } + } +} + func TestHeaderValuesContainsToken(t *testing.T) { tests := []struct { vals []string @@ -100,6 +109,44 @@ func TestHeaderValuesContainsToken(t *testing.T) { } } +func TestValidHeaderFieldName(t *testing.T) { + tests := []struct { + in string + want bool + }{ + {"", false}, + {"Accept Charset", false}, + {"Accept-Charset", true}, + {"AccepT-EncodinG", true}, + {"CONNECTION", true}, + {"résumé", false}, + } + for _, tt := range tests { + got := ValidHeaderFieldName(tt.in) + if tt.want != got { + t.Errorf("ValidHeaderFieldName(%q) = %t; want %t", tt.in, got, tt.want) + } + } +} + +func BenchmarkValidHeaderFieldName(b *testing.B) { + names := []string{ + "", + "Accept Charset", + "Accept-Charset", + "AccepT-EncodinG", + "CONNECTION", + "résumé", + } + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, name := range names { + ValidHeaderFieldName(name) + } + } +} + func TestPunycodeHostPort(t *testing.T) { tests := []struct { in, want string From f95a3b3a48597cebf9849b84a02cd240fb185b16 Mon Sep 17 00:00:00 2001 From: Eng Zer Jun Date: Thu, 18 Apr 2024 22:37:18 +0800 Subject: [PATCH 5/8] html: fix typo in package doc Change-Id: I3cacfadc0396c8ef85addd062d991bb6f5b0483a Reviewed-on: https://go-review.googlesource.com/c/net/+/580035 Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Commit-Queue: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil Reviewed-by: Damien Neil --- html/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/doc.go b/html/doc.go index 2466ae3d9..3a7e5ab17 100644 --- a/html/doc.go +++ b/html/doc.go @@ -104,7 +104,7 @@ tokenization, and tokenization and tree construction stages of the WHATWG HTML parsing specification respectively. While the tokenizer parses and normalizes individual HTML tokens, only the parser constructs the DOM tree from the tokenized HTML, as described in the tree construction stage of the -specification, dynamically modifying or extending the docuemnt's DOM tree. +specification, dynamically modifying or extending the document's DOM tree. If your use case requires semantically well-formed HTML documents, as defined by the WHATWG specification, the parser should be used rather than the tokenizer. From b20cd5933aa9ba90f6299e6c2cbb59733434636e Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 2 May 2024 13:32:03 -0400 Subject: [PATCH 6/8] quic: initiate key rotation earlier in connections The QUIC interop runner "keyrotate" test requires that the client initiate a key rotation early in the connection. With our current ack frequency, it seems that we need to rotate within the first 300-400 packets for the test to pass. Reduce the initial key rotation from 1000 to 100 packets. Rotating earlier shouldn't have any real downsides (rotation is cheap and generally done once per connection, except for very long-lived connections), and this is simpler than providing a way to tune the rotation interval in one specific test. For golang/go#67138 Change-Id: I33d47ea35ed39f0a13c171adb2b0698f8c93050e Reviewed-on: https://go-review.googlesource.com/c/net/+/582855 LUCI-TryBot-Result: Go LUCI Reviewed-by: Jonathan Amsterdam --- quic/packet_protection.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/quic/packet_protection.go b/quic/packet_protection.go index 1f939f491..fe48c14c5 100644 --- a/quic/packet_protection.go +++ b/quic/packet_protection.go @@ -351,7 +351,13 @@ func (k *updatingKeyPair) init() { // We perform the first key update early in the connection so a peer // which does not support key updates will fail rapidly, // rather than after the connection has been long established. - k.updateAfter = 1000 + // + // The QUIC interop runner "keyupdate" test requires that the client + // initiate a key rotation early in the connection. Increasing this + // value may cause interop test failures; if we do want to increase it, + // we should either skip the keyupdate test or provide a way to override + // the setting in interop tests. + k.updateAfter = 100 } func (k *updatingKeyPair) canRead() bool { From e0324fcdb510ad91eaeb1f9bd7a1b7d564f7c549 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 3 May 2024 14:12:39 +0200 Subject: [PATCH 7/8] http2: use net.ErrClosed Use errors.Is(err, net.ErrClosed) instead of checking for a known string. net.ErrClosed is available since Go 1.16, the current minimum version in go.mod is Go 1.18. For golang/go#4373 Change-Id: Id98771874434bae7d9c6d1d4d36fddb28822eb39 Reviewed-on: https://go-review.googlesource.com/c/net/+/583016 Auto-Submit: Tobias Klauser Reviewed-by: Damien Neil Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- http2/server.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/http2/server.go b/http2/server.go index 278add72b..c5d081081 100644 --- a/http2/server.go +++ b/http2/server.go @@ -732,11 +732,7 @@ func isClosedConnError(err error) bool { return false } - // TODO: remove this string search and be more like the Windows - // case below. That might involve modifying the standard library - // to return better error types. - str := err.Error() - if strings.Contains(str, "use of closed network connection") { + if errors.Is(err, net.ErrClosed) { return true } From d27919b57fa8dd03198f85ca9e675e1a09babd7d Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Mon, 6 May 2024 16:15:28 +0000 Subject: [PATCH 8/8] go.mod: update golang.org/x dependencies Update golang.org/x dependencies to their latest tagged versions. Change-Id: If4b46b8a597f56ee25582b456ee4ac5f42e3fdd4 Reviewed-on: https://go-review.googlesource.com/c/net/+/583516 Auto-Submit: Gopher Robot LUCI-TryBot-Result: Go LUCI Reviewed-by: Than McIntosh Reviewed-by: Dmitri Shuralyov --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 1446f39a4..57e8a0252 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module golang.org/x/net go 1.18 require ( - golang.org/x/crypto v0.22.0 - golang.org/x/sys v0.19.0 - golang.org/x/term v0.19.0 - golang.org/x/text v0.14.0 + golang.org/x/crypto v0.23.0 + golang.org/x/sys v0.20.0 + golang.org/x/term v0.20.0 + golang.org/x/text v0.15.0 ) diff --git a/go.sum b/go.sum index a4e7f116d..50575cf8c 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=