|
|
@@ -28,7 +28,7 @@ import (
|
|
|
"time"
|
|
|
|
|
|
"camlistore.org/pkg/googlestorage"
|
|
|
- "camlistore.org/pkg/singleflight"
|
|
|
+ "go4.org/syncutil/singleflight"
|
|
|
"golang.org/x/net/http2"
|
|
|
)
|
|
|
|
|
|
@@ -79,7 +79,7 @@ is used transparently by the Go standard library from Go 1.6 and later.
|
|
|
</p>
|
|
|
|
|
|
<p>Contact info: <i>bradfitz@golang.org</i>, or <a
|
|
|
-href="https://golang.org/issues">file a bug</a>.</p>
|
|
|
+href="https://golang.org/s/http2bug">file a bug</a>.</p>
|
|
|
|
|
|
<h2>Handlers for testing</h2>
|
|
|
<ul>
|
|
|
@@ -440,11 +440,43 @@ func serveProd() error {
|
|
|
return <-errc
|
|
|
}
|
|
|
|
|
|
+const idleTimeout = 5 * time.Minute
|
|
|
+const activeTimeout = 10 * time.Minute
|
|
|
+
|
|
|
+// TODO: put this into the standard library and actually send
|
|
|
+// PING frames and GOAWAY, etc: golang.org/issue/14204
|
|
|
+func idleTimeoutHook() func(net.Conn, http.ConnState) {
|
|
|
+ var mu sync.Mutex
|
|
|
+ m := map[net.Conn]*time.Timer{}
|
|
|
+ return func(c net.Conn, cs http.ConnState) {
|
|
|
+ mu.Lock()
|
|
|
+ defer mu.Unlock()
|
|
|
+ if t, ok := m[c]; ok {
|
|
|
+ delete(m, c)
|
|
|
+ t.Stop()
|
|
|
+ }
|
|
|
+ var d time.Duration
|
|
|
+ switch cs {
|
|
|
+ case http.StateNew, http.StateIdle:
|
|
|
+ d = idleTimeout
|
|
|
+ case http.StateActive:
|
|
|
+ d = activeTimeout
|
|
|
+ default:
|
|
|
+ return
|
|
|
+ }
|
|
|
+ m[c] = time.AfterFunc(d, func() {
|
|
|
+ log.Printf("closing idle conn %v after %v", c.RemoteAddr(), d)
|
|
|
+ go c.Close()
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
func main() {
|
|
|
var srv http.Server
|
|
|
flag.BoolVar(&http2.VerboseLogs, "verbose", false, "Verbose HTTP/2 debugging.")
|
|
|
flag.Parse()
|
|
|
srv.Addr = *httpsAddr
|
|
|
+ srv.ConnState = idleTimeoutHook()
|
|
|
|
|
|
registerHandlers()
|
|
|
|