const MaxConns = 128
-var GracefulTime = 10 * time.Second
+var (
+ GracefulTime = 10 * time.Second
+ RWTimeout = 30 * time.Second
+)
func main() {
bind := flag.String("bind", "[::]:80", "Address to bind and listen on")
shutdown := make(chan os.Signal)
signal.Notify(shutdown, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP)
exitErr := make(chan error)
- l, err := net.Listen("tcp", *bind)
+ l, err := godlighty.DeadlinedListen("tcp", *bind, RWTimeout, RWTimeout)
if err != nil {
log.Fatalln(err)
}
}
}()
- srv := http.Server{Handler: godlighty.MainHandler}
+ srv := http.Server{
+ Handler: godlighty.MainHandler,
+ ReadHeaderTimeout: RWTimeout,
+ IdleTimeout: time.Minute,
+ }
go func() {
<-shutdown
log.Println("shutting down")
--- /dev/null
+// Deadlined socket read/write. https://github.com/golang/go/issues/16100
+
+package godlighty
+
+import (
+ "net"
+ "time"
+)
+
+type DeadlinedConn struct {
+ net.Conn
+ ReadTimeout time.Duration
+ WriteTimeout time.Duration
+ ReadThreshold int64
+ WriteThreshold int64
+ BytesReadFromDeadline int64
+ BytesWrittenFromDeadline int64
+}
+
+func (c *DeadlinedConn) Read(b []byte) (n int, err error) {
+ if c.BytesReadFromDeadline > c.ReadThreshold {
+ c.BytesReadFromDeadline = 0
+ err = c.Conn.SetDeadline(time.Now().Add(c.ReadTimeout))
+ if err != nil {
+ return
+ }
+ }
+ n, err = c.Conn.Read(b)
+ c.BytesReadFromDeadline += int64(n)
+ return
+}
+
+func (c *DeadlinedConn) Write(b []byte) (n int, err error) {
+ if c.BytesWrittenFromDeadline > c.WriteThreshold {
+ c.BytesWrittenFromDeadline = 0
+ err = c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
+ if err != nil {
+ return
+ }
+ }
+ n, err = c.Conn.Write(b)
+ c.BytesWrittenFromDeadline += int64(n)
+ return
+}
+
+type DeadlinedListener struct {
+ net.Listener
+ ReadTimeout time.Duration
+ WriteTimeout time.Duration
+}
+
+func (l *DeadlinedListener) Accept() (net.Conn, error) {
+ c, err := l.Listener.Accept()
+ if err != nil {
+ return nil, err
+ }
+ return &DeadlinedConn{
+ Conn: c,
+ ReadTimeout: l.ReadTimeout,
+ WriteTimeout: l.WriteTimeout,
+ ReadThreshold: int64((l.ReadTimeout * 1024) / time.Second),
+ WriteThreshold: int64((l.WriteTimeout * 1024) / time.Second),
+ }, nil
+}
+
+func DeadlinedListen(
+ network, addr string,
+ readTimeout, writeTimeout time.Duration,
+) (net.Listener, error) {
+ l, err := net.Listen(network, addr)
+ if err != nil {
+ return nil, err
+ }
+ return &DeadlinedListener{
+ Listener: l,
+ ReadTimeout: readTimeout,
+ WriteTimeout: writeTimeout,
+ }, nil
+}