Skip to content

Commit 6465188

Browse files
neildgopherbot
authored andcommitted
http2: add wrapped Server
Implement Server in terms of net/http. For #78508 Change-Id: Iad2b592b8c4f32d66126eb52d8881e8e6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/net/+/771220 Reviewed-by: Nicholas Husin <nsh@golang.org> Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Nicholas Husin <husin@google.com>
1 parent 72f419a commit 6465188

6 files changed

Lines changed: 147 additions & 9 deletions

File tree

http2/export_common_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ const (
1111
InitialWindowSize = initialWindowSize
1212
)
1313

14+
type (
15+
ServerConn = serverConn
16+
)
17+
1418
func SummarizeFrame(f Frame) string {
1519
return summarizeFrame(f)
1620
}

http2/export_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ const (
3030
)
3131

3232
type (
33-
ServerConn = serverConn
3433
Stream = stream
3534
StreamState = streamState
3635

http2/export_wrap_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,3 @@ func (t *Transport) TestTransport() *http.Transport {
1616
func (s *Server) TestSetNewConnFunc(f func(*ServerConn)) {
1717
panic("ServerConns are not available with http2wrap")
1818
}
19-
20-
type ServerConn struct{}

http2/server_common_test.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,10 @@ func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}
122122
h1server := &http.Server{}
123123
h2server := &Server{}
124124
tlsState := tls.ConnectionState{
125-
Version: tls.VersionTLS13,
126-
ServerName: "go.dev",
127-
CipherSuite: tls.TLS_AES_128_GCM_SHA256,
125+
Version: tls.VersionTLS13,
126+
ServerName: "go.dev",
127+
CipherSuite: tls.TLS_AES_128_GCM_SHA256,
128+
NegotiatedProtocol: "h2",
128129
}
129130
noConn := false
130131
for _, opt := range opts {
@@ -151,6 +152,10 @@ func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}
151152
cli, srv := synctestNetPipe()
152153
cli.SetReadDeadline(time.Now())
153154
cli.autoWait = true
155+
t.Cleanup(func() {
156+
cli.Close()
157+
srv.Close()
158+
})
154159

155160
st := &serverTester{
156161
t: t,

http2/server_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,16 @@ func newServerTesterWithRealConn(t testing.TB, handler http.HandlerFunc, opts ..
169169
}
170170

171171
func (st *serverTester) streamExists(id uint32) bool {
172+
if st.sc == nil {
173+
st.t.Fatalf("serverTester has no ServerConn")
174+
}
172175
return st.sc.TestStreamExists(id)
173176
}
174177

175178
func (st *serverTester) streamState(id uint32) StreamState {
179+
if st.sc == nil {
180+
st.t.Fatalf("serverTester has no ServerConn")
181+
}
176182
return st.sc.TestStreamState(id)
177183
}
178184

http2/server_wrap.go

Lines changed: 129 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,146 @@
99
package http2
1010

1111
import (
12+
"context"
1213
"errors"
1314
"net"
1415
"net/http"
16+
"sync"
17+
"time"
1518
)
1619

1720
type serverInternalState struct {
21+
s1 *http.Server
22+
initOnce sync.Once
23+
serveConnFunc func(context.Context, net.Conn, http.Handler, bool, *http.Request, []byte)
1824
}
1925

2026
func configureServer(s *http.Server, conf *Server) error {
21-
return errors.New("TODO")
27+
if s == nil {
28+
panic("nil *http.Server")
29+
}
30+
if conf == nil {
31+
conf = new(Server)
32+
}
33+
if conf.state != nil {
34+
// This isn't a panic in the pre-wrapping implementation,
35+
// but calling ConfigureServer twice with the same http2.Server
36+
// overwrites internal state on the server.
37+
// Make the error explicit and early here.
38+
panic("ConfigureServer may be called only once per Server")
39+
}
40+
if h1, h2 := s, conf; h2.IdleTimeout == 0 {
41+
if h1.IdleTimeout != 0 {
42+
h2.IdleTimeout = h1.IdleTimeout
43+
} else {
44+
h2.IdleTimeout = h1.ReadTimeout
45+
}
46+
}
47+
conf.state = &serverInternalState{
48+
s1: s,
49+
}
50+
sconfig := &serverConfig{s: conf}
51+
if err := s.Serve(sconfig); err != nil || sconfig.serveConnFunc == nil {
52+
panic("http2: net/http does not support this version of x/net/http2")
53+
}
54+
conf.state.serveConnFunc = sconfig.serveConnFunc
55+
return nil
2256
}
2357

24-
func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*ServerConn)) {
25-
c.Close() // TODO
58+
type serverConfig struct {
59+
s *Server
60+
serveConnFunc func(context.Context, net.Conn, http.Handler, bool, *http.Request, []byte)
61+
}
62+
63+
func (*serverConfig) Accept() (net.Conn, error) {
64+
return nil, errors.New("unexpected call to Accept")
65+
}
66+
func (*serverConfig) Close() error {
67+
return nil
68+
}
69+
func (*serverConfig) Addr() net.Addr {
70+
return nil
71+
}
72+
73+
func (s *serverConfig) ServeConnFunc(f func(context.Context, net.Conn, http.Handler, bool, *http.Request, []byte)) {
74+
s.serveConnFunc = f
75+
}
76+
77+
func (s *serverConfig) HTTP2Config() http.HTTP2Config {
78+
return http.HTTP2Config{
79+
MaxConcurrentStreams: int(s.s.MaxConcurrentStreams),
80+
MaxDecoderHeaderTableSize: int(s.s.MaxDecoderHeaderTableSize),
81+
MaxEncoderHeaderTableSize: int(s.s.MaxEncoderHeaderTableSize),
82+
MaxReadFrameSize: int(s.s.MaxReadFrameSize),
83+
PermitProhibitedCipherSuites: s.s.PermitProhibitedCipherSuites,
84+
MaxReceiveBufferPerConnection: int(s.s.MaxUploadBufferPerConnection),
85+
MaxReceiveBufferPerStream: int(s.s.MaxUploadBufferPerStream),
86+
SendPingTimeout: s.s.ReadIdleTimeout,
87+
PingTimeout: s.s.PingTimeout,
88+
WriteByteTimeout: s.s.WriteByteTimeout,
89+
CountError: s.s.CountError,
90+
}
91+
}
92+
93+
func (s *serverConfig) IdleTimeout() time.Duration {
94+
return s.s.IdleTimeout
95+
}
96+
97+
type serverConn struct{}
98+
99+
func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, _ func(*serverConn)) {
100+
var serveConnFunc func(context.Context, net.Conn, http.Handler, bool, *http.Request, []byte)
101+
switch {
102+
case opts.BaseConfig != nil:
103+
// The user has provided us with an http.Server to take configuration from.
104+
//
105+
// We can't send our request to opts.BaseConfig, because an http.Server can
106+
// only be associated with a single http2.Server and the user might
107+
// use this one with several http.Servers.
108+
//
109+
// We can't send our request to s.state.s1, because it doesn't contain
110+
// the right configuration.
111+
//
112+
// So create a one-off copy of opts.BaseConfig and use it.
113+
h1 := &http.Server{
114+
TLSConfig: opts.BaseConfig.TLSConfig,
115+
ReadTimeout: opts.BaseConfig.ReadTimeout,
116+
ReadHeaderTimeout: opts.BaseConfig.ReadHeaderTimeout,
117+
WriteTimeout: opts.BaseConfig.WriteTimeout,
118+
IdleTimeout: opts.BaseConfig.IdleTimeout,
119+
MaxHeaderBytes: opts.BaseConfig.MaxHeaderBytes,
120+
ConnState: opts.BaseConfig.ConnState,
121+
ErrorLog: opts.BaseConfig.ErrorLog,
122+
BaseContext: opts.BaseConfig.BaseContext,
123+
ConnContext: opts.BaseConfig.ConnContext,
124+
HTTP2: opts.BaseConfig.HTTP2,
125+
}
126+
sconfig := &serverConfig{s: s}
127+
if err := h1.Serve(sconfig); err != nil || sconfig.serveConnFunc == nil {
128+
panic("http2: net/http does not support this version of x/net/http2")
129+
}
130+
serveConnFunc = sconfig.serveConnFunc
131+
case s.state != nil:
132+
serveConnFunc = s.state.serveConnFunc
133+
default:
134+
// Strange-but-true: Server has no concurrency-safe way to initialize
135+
// its internal state, so historically ServeConn just doesn't use any
136+
// persistent state if you don't call ConfigureServer first.
137+
//
138+
// If ConfigureServer hasn't been called, create a one-off http.Server
139+
// for the connection, since we don't have any way to keep one around for reuse.
140+
h1 := &http.Server{}
141+
sconfig := &serverConfig{s: s}
142+
if err := h1.Serve(sconfig); err != nil || sconfig.serveConnFunc == nil {
143+
panic("http2: net/http does not support this version of x/net/http2")
144+
}
145+
serveConnFunc = sconfig.serveConnFunc
146+
}
147+
148+
ctx, cancel := serverConnBaseContext(c, opts)
149+
defer cancel()
150+
serveConnFunc(ctx, c, opts.handler(), opts.SawClientPreface, opts.UpgradeRequest, opts.Settings)
151+
26152
}
27153

28154
// FrameWriteRequest is a request to write a frame.

0 commit comments

Comments
 (0)