Skip to content

Commit 2d0ab7a

Browse files
authored
Use std http.Protocols for http config (#4011)
1 parent 0f230da commit 2d0ab7a

File tree

7 files changed

+60
-77
lines changed

7 files changed

+60
-77
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ require (
4242
go.uber.org/zap v1.27.0
4343
golang.org/x/crypto v0.42.0
4444
golang.org/x/mod v0.28.0
45-
golang.org/x/net v0.44.0
4645
golang.org/x/sync v0.17.0
4746
golang.org/x/term v0.35.0
4847
golang.org/x/tools v0.37.0
@@ -101,7 +100,8 @@ require (
101100
go.opentelemetry.io/proto/otlp v1.8.0 // indirect
102101
go.uber.org/mock v0.6.0 // indirect
103102
go.uber.org/multierr v1.11.0 // indirect
104-
golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
103+
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
104+
golang.org/x/net v0.44.0 // indirect
105105
golang.org/x/sys v0.36.0 // indirect
106106
golang.org/x/text v0.29.0 // indirect
107107
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
206206
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
207207
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
208208
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
209-
golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
210-
golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
209+
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
210+
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
211211
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
212212
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
213213
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=

private/buf/bufstudioagent/bufstudioagent_test.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ import (
3535
"github.com/bufbuild/buf/private/pkg/slogtestext"
3636
"github.com/stretchr/testify/assert"
3737
"github.com/stretchr/testify/require"
38-
"golang.org/x/net/http2"
39-
"golang.org/x/net/http2/h2c"
4038
"google.golang.org/protobuf/proto"
4139
)
4240

@@ -275,16 +273,25 @@ func newTestConnectServer(t *testing.T, tls bool) *httptest.Server {
275273
},
276274
connect.WithCodec(&bufferCodec{name: "proto"}),
277275
))
276+
protocols := new(http.Protocols)
277+
protocols.SetHTTP1(true)
278+
server := httptest.NewUnstartedServer(mux)
279+
server.Config.Protocols = protocols
278280
if tls {
279-
upstreamServerTLS := httptest.NewUnstartedServer(mux)
280-
upstreamServerTLS.EnableHTTP2 = true
281-
upstreamServerTLS.StartTLS()
281+
protocols.SetHTTP2(true)
282+
// Enable HTTP/2 for TLS configuration.
283+
server.EnableHTTP2 = true
284+
server.StartTLS()
285+
// Add the server's certificate to its own trusted CA pool.
286+
// This is needed because the server TSL config is used to configure clients.
282287
certpool := x509.NewCertPool()
283-
certpool.AddCert(upstreamServerTLS.Certificate())
284-
upstreamServerTLS.TLS.RootCAs = certpool
285-
return upstreamServerTLS
288+
certpool.AddCert(server.Certificate())
289+
server.TLS.RootCAs = certpool
290+
} else {
291+
protocols.SetUnencryptedHTTP2(true)
292+
server.Start()
286293
}
287-
return httptest.NewServer(h2c.NewHandler(mux, &http2.Server{}))
294+
return server
288295
}
289296

290297
func protoMarshalBase64(t *testing.T, message proto.Message) []byte {

private/buf/bufstudioagent/plain_post_handler.go

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"fmt"
2323
"io"
2424
"log/slog"
25-
"net"
2625
"net/http"
2726
"net/textproto"
2827
"net/url"
@@ -31,7 +30,6 @@ import (
3130
"connectrpc.com/connect"
3231
studiov1alpha1 "github.com/bufbuild/buf/private/gen/proto/go/buf/alpha/studio/v1alpha1"
3332
"github.com/bufbuild/buf/private/pkg/protoencoding"
34-
"golang.org/x/net/http2"
3533
"google.golang.org/protobuf/proto"
3634
)
3735

@@ -54,8 +52,7 @@ type plainPostHandler struct {
5452
Logger *slog.Logger
5553
MaxMessageSizeBytes int64
5654
B64Encoding *base64.Encoding
57-
TLSClient *http.Client
58-
H2CClient *http.Client
55+
Client *http.Client
5956
DisallowedHeaders map[string]struct{}
6057
ForwardHeaders map[string]string
6158
}
@@ -74,25 +71,23 @@ func newPlainPostHandler(
7471
for k, v := range forwardHeaders {
7572
canonicalForwardHeaders[textproto.CanonicalMIMEHeaderKey(k)] = v
7673
}
74+
protocols := new(http.Protocols)
75+
protocols.SetHTTP1(true)
76+
protocols.SetHTTP2(true)
77+
protocols.SetUnencryptedHTTP2(true)
78+
transport := &http.Transport{
79+
TLSClientConfig: tlsClientConfig,
80+
Protocols: protocols,
81+
}
7782
return &plainPostHandler{
7883
B64Encoding: base64.StdEncoding,
7984
DisallowedHeaders: canonicalDisallowedHeaders,
8085
ForwardHeaders: canonicalForwardHeaders,
81-
H2CClient: &http.Client{
82-
Transport: &http2.Transport{
83-
AllowHTTP: true,
84-
DialTLS: func(netw, addr string, config *tls.Config) (net.Conn, error) {
85-
return net.Dial(netw, addr)
86-
},
87-
},
86+
Client: &http.Client{
87+
Transport: transport,
8888
},
8989
Logger: logger,
9090
MaxMessageSizeBytes: MaxMessageSizeBytesDefault,
91-
TLSClient: &http.Client{
92-
Transport: &http2.Transport{
93-
TLSClientConfig: tlsClientConfig,
94-
},
95-
},
9691
}
9792
}
9893

@@ -150,10 +145,8 @@ func (i *plainPostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
150145
}
151146
var httpClient *http.Client
152147
switch targetURL.Scheme {
153-
case "http":
154-
httpClient = i.H2CClient
155-
case "https":
156-
httpClient = i.TLSClient
148+
case "http", "https":
149+
httpClient = i.Client
157150
default:
158151
http.Error(w, fmt.Sprintf("must specify http or https url scheme, got %q", targetURL.Scheme), http.StatusBadRequest)
159152
return

private/buf/cmd/buf/command/curl/curl.go

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ import (
4444
"github.com/quic-go/quic-go"
4545
"github.com/quic-go/quic-go/http3"
4646
"github.com/spf13/pflag"
47-
"golang.org/x/net/http2"
4847
"google.golang.org/protobuf/reflect/protoreflect"
4948
)
5049

@@ -1131,32 +1130,18 @@ func makeHTTPRoundTripper(f *flags, isSecure bool, authority string, printer ver
11311130
return tlsConn, nil
11321131
}
11331132
}
1134-
1135-
var transport http.RoundTripper
1136-
switch {
1137-
case f.HTTP2PriorKnowledge && isSecure:
1138-
transport = &http2.Transport{
1139-
DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) {
1140-
return dialTLSFunc(ctx, network, addr)
1141-
},
1142-
}
1143-
case f.HTTP2PriorKnowledge:
1144-
transport = &http2.Transport{
1145-
AllowHTTP: true,
1146-
DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) {
1147-
return dialFunc(ctx, network, addr)
1148-
},
1149-
}
1150-
default:
1151-
transport = &http.Transport{
1152-
Proxy: http.ProxyFromEnvironment,
1153-
DialContext: dialFunc,
1154-
DialTLSContext: dialTLSFunc,
1155-
ForceAttemptHTTP2: true,
1156-
MaxIdleConns: 1,
1157-
}
1158-
}
1159-
return transport, nil
1133+
protocols := new(http.Protocols)
1134+
protocols.SetHTTP1(true)
1135+
protocols.SetHTTP2(f.HTTP2PriorKnowledge)
1136+
protocols.SetUnencryptedHTTP2(f.HTTP2PriorKnowledge && !isSecure)
1137+
return &http.Transport{
1138+
Proxy: http.ProxyFromEnvironment,
1139+
DialContext: dialFunc,
1140+
DialTLSContext: dialTLSFunc,
1141+
ForceAttemptHTTP2: true,
1142+
MaxIdleConns: 1,
1143+
Protocols: protocols,
1144+
}, nil
11601145
}
11611146

11621147
func makeHTTP3RoundTripper(f *flags, authority string, printer verbose.Printer) (http.RoundTripper, error) {

private/bufpkg/bufremoteplugin/bufremoteplugindocker/docker_test.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ import (
4343
"github.com/docker/docker/pkg/stringid"
4444
"github.com/stretchr/testify/assert"
4545
"github.com/stretchr/testify/require"
46-
"golang.org/x/net/http2"
47-
"golang.org/x/net/http2/h2c"
4846
)
4947

5048
const (
@@ -181,8 +179,6 @@ func buildDockerPlugin(t testing.TB, dockerfilePath string, pluginIdentity strin
181179
// dockerServer allows testing some failure flows by simulating the responses to Docker CLI commands.
182180
type dockerServer struct {
183181
httpServer *httptest.Server
184-
h2Server *http2.Server
185-
h2Handler http.Handler
186182
t testing.TB
187183
versionPrefix string
188184
pushErr error
@@ -211,11 +207,14 @@ func newDockerServer(t testing.TB, version string) *dockerServer {
211207
t.Fatalf("failed to encode response: %v", err)
212208
}
213209
})
214-
dockerServer.h2Server = &http2.Server{}
215-
dockerServer.h2Handler = h2c.NewHandler(mux, dockerServer.h2Server)
216-
dockerServer.httpServer = httptest.NewUnstartedServer(dockerServer.h2Handler)
217-
dockerServer.httpServer.Start()
218-
t.Cleanup(dockerServer.httpServer.Close)
210+
protocols := new(http.Protocols)
211+
protocols.SetHTTP1(true)
212+
protocols.SetUnencryptedHTTP2(true)
213+
server := httptest.NewUnstartedServer(mux)
214+
server.Config.Protocols = protocols
215+
server.Start()
216+
dockerServer.httpServer = server
217+
t.Cleanup(server.Close)
219218
return dockerServer
220219
}
221220

private/pkg/transport/http/httpserver/httpserver.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ import (
2323
"time"
2424

2525
"github.com/go-chi/chi/v5"
26-
"golang.org/x/net/http2"
27-
"golang.org/x/net/http2/h2c"
2826
"golang.org/x/sync/errgroup"
2927
)
3028

@@ -33,7 +31,7 @@ const (
3331
DefaultShutdownTimeout = 10 * time.Second
3432
// DefaultReadHeaderTimeout is the default read header timeout.
3533
DefaultReadHeaderTimeout = 30 * time.Second
36-
// DefaultIdleTimeout is the amount of time an HTTP/2 connection can be idle.
34+
// DefaultIdleTimeout is the amount of time a connection can be idle.
3735
DefaultIdleTimeout = 3 * time.Minute
3836
)
3937

@@ -115,16 +113,17 @@ func Run(
115113
for _, option := range options {
116114
option(s)
117115
}
116+
protocols := new(http.Protocols)
117+
protocols.SetHTTP1(true)
118+
protocols.SetHTTP2(true)
119+
protocols.SetUnencryptedHTTP2(!s.disableH2C)
118120
httpServer := &http.Server{
119121
Handler: handler,
120122
ReadHeaderTimeout: s.readHeaderTimeout,
121123
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
122124
TLSConfig: s.tlsConfig,
123-
}
124-
if s.tlsConfig == nil && !s.disableH2C {
125-
httpServer.Handler = h2c.NewHandler(handler, &http2.Server{
126-
IdleTimeout: DefaultIdleTimeout,
127-
})
125+
Protocols: protocols,
126+
IdleTimeout: DefaultIdleTimeout,
128127
}
129128
if s.walkFunc != nil {
130129
routes, ok := handler.(chi.Routes)

0 commit comments

Comments
 (0)