@@ -22,6 +22,8 @@ import (
22
22
ot "github.com/opentracing/opentracing-go"
23
23
"github.com/prometheus/client_golang/prometheus"
24
24
log "github.com/sirupsen/logrus"
25
+ "golang.org/x/net/http2"
26
+ "golang.org/x/net/http2/h2c"
25
27
26
28
"github.com/zalando/skipper/circuit"
27
29
"github.com/zalando/skipper/dataclients/kubernetes"
@@ -42,7 +44,7 @@ import (
42
44
"github.com/zalando/skipper/loadbalancer"
43
45
"github.com/zalando/skipper/logging"
44
46
"github.com/zalando/skipper/metrics"
45
- skpnet "github.com/zalando/skipper/net"
47
+ snet "github.com/zalando/skipper/net"
46
48
pauth "github.com/zalando/skipper/predicates/auth"
47
49
"github.com/zalando/skipper/predicates/content"
48
50
"github.com/zalando/skipper/predicates/cookie"
@@ -381,6 +383,9 @@ type Options struct {
381
383
// a backend to always create a new connection.
382
384
DisableHTTPKeepalives bool
383
385
386
+ // EnableHttp2Cleartext enables HTTP/2 connections over cleartext TCP.
387
+ EnableHttp2Cleartext bool
388
+
384
389
// Flag indicating to ignore trailing slashes in paths during route
385
390
// lookup.
386
391
IgnoreTrailingSlash bool
@@ -1233,11 +1238,31 @@ func listenAndServeQuit(
1233
1238
}
1234
1239
}
1235
1240
1241
+ if o .EnableHttp2Cleartext {
1242
+ if serveTLS {
1243
+ return fmt .Errorf ("HTTP/2 connections over cleartext TCP are not supported when TLS is enabled" )
1244
+ }
1245
+
1246
+ h2srv := & http2.Server {}
1247
+ srv .Handler = h2c .NewHandler (srv .Handler , h2srv )
1248
+
1249
+ // Work around https://github.com/golang/go/issues/26682
1250
+ // http2.ConfigureServer registers unexported h2srv graceful shutdown handler on srv shutdown -
1251
+ // it calls srv.RegisterOnShutdown(h2srv.state.startGracefulShutdown).
1252
+ // h2srv graceful shutdown handler sends GOAWAY frame to all connections and closes them after predefined delay.
1253
+ //
1254
+ // srv.Shutdown() runs h2srv shutdown handler in a goroutine so a special snet.ShutdownListener
1255
+ // waits until all connections are closed.
1256
+ http2 .ConfigureServer (srv , h2srv )
1257
+ }
1258
+
1236
1259
log .Infof ("Listen on %v" , address )
1237
1260
1238
- l , err := listen ( o , address , mtr )
1239
- if err != nil {
1261
+ var listener * snet. ShutdownListener
1262
+ if l , err := listen ( o , address , mtr ); err != nil {
1240
1263
return err
1264
+ } else {
1265
+ listener = snet .NewShutdownListener (l )
1241
1266
}
1242
1267
1243
1268
// making idleConnsCH and sigs optional parameters is required to be able to tear down a server
@@ -1258,10 +1283,16 @@ func listenAndServeQuit(
1258
1283
log .Infof ("Got shutdown signal, wait %v for health check" , o .WaitForHealthcheckInterval )
1259
1284
time .Sleep (o .WaitForHealthcheckInterval )
1260
1285
1261
- log .Info ("Start shutdown" )
1286
+ log .Info ("Start server shutdown" )
1262
1287
if err := srv .Shutdown (context .Background ()); err != nil {
1263
- log .Errorf ("Failed to graceful shutdown: %v" , err )
1288
+ log .Errorf ("Failed to gracefully shutdown: %v" , err )
1289
+ }
1290
+
1291
+ log .Info ("Start listener shutdown" )
1292
+ if err := listener .Shutdown (context .Background ()); err != nil {
1293
+ log .Errorf ("Failed to gracefully shutdown listener: %v" , err )
1264
1294
}
1295
+
1265
1296
close (idleConnsCH )
1266
1297
}()
1267
1298
@@ -1281,20 +1312,21 @@ func listenAndServeQuit(
1281
1312
}()
1282
1313
}
1283
1314
1284
- if err := srv .ServeTLS (l , "" , "" ); err != http .ErrServerClosed {
1315
+ if err := srv .ServeTLS (listener , "" , "" ); err != http .ErrServerClosed {
1285
1316
log .Errorf ("ServeTLS failed: %v" , err )
1286
1317
return err
1287
1318
}
1288
1319
} else {
1289
1320
log .Infof ("TLS settings not found, defaulting to HTTP" )
1290
1321
1291
- if err := srv .Serve (l ); err != http .ErrServerClosed {
1322
+ if err := srv .Serve (listener ); err != http .ErrServerClosed {
1292
1323
log .Errorf ("Serve failed: %v" , err )
1293
1324
return err
1294
1325
}
1295
1326
}
1296
1327
1297
1328
<- idleConnsCH
1329
+
1298
1330
log .Infof ("done." )
1299
1331
return nil
1300
1332
}
@@ -1580,13 +1612,13 @@ func run(o Options, sig chan os.Signal, idleConnsCH chan struct{}) error {
1580
1612
}
1581
1613
1582
1614
var swarmer ratelimit.Swarmer
1583
- var redisOptions * skpnet .RedisOptions
1615
+ var redisOptions * snet .RedisOptions
1584
1616
log .Infof ("enable swarm: %v" , o .EnableSwarm )
1585
1617
if o .EnableSwarm {
1586
1618
if len (o .SwarmRedisURLs ) > 0 || o .KubernetesRedisServiceName != "" || o .SwarmRedisEndpointsRemoteURL != "" {
1587
1619
log .Infof ("Redis based swarm with %d shards" , len (o .SwarmRedisURLs ))
1588
1620
1589
- redisOptions = & skpnet .RedisOptions {
1621
+ redisOptions = & snet .RedisOptions {
1590
1622
Addrs : o .SwarmRedisURLs ,
1591
1623
Password : o .SwarmRedisPassword ,
1592
1624
HashAlgorithm : o .SwarmRedisHashAlgorithm ,
0 commit comments