@@ -237,7 +237,6 @@ type conn struct {
237
237
r * connReader
238
238
239
239
// bufr reads from r.
240
- // Users of bufr must hold mu.
241
240
bufr * bufio.Reader
242
241
243
242
// bufw writes to checkConnErrorWriter{c}, which populates werr on error.
@@ -247,11 +246,11 @@ type conn struct {
247
246
// on this connection, if any.
248
247
lastMethod string
249
248
250
- // mu guards hijackedv, use of bufr, (*response).closeNotifyCh.
251
- mu sync.Mutex
252
-
253
249
curReq atomic.Value // of *response (which has a Request in it)
254
250
251
+ // mu guards hijackedv
252
+ mu sync.Mutex
253
+
255
254
// hijackedv is whether this connection has been hijacked
256
255
// by a Handler with the Hijacker interface.
257
256
// It is guarded by mu.
@@ -426,7 +425,7 @@ type response struct {
426
425
427
426
// closeNotifyCh is the channel returned by CloseNotify.
428
427
// TODO(bradfitz): this is currently (for Go 1.8) always
429
- // non-nil. Make this lazily-created again as it used to be.
428
+ // non-nil. Make this lazily-created again as it used to be?
430
429
closeNotifyCh chan bool
431
430
didCloseNotify int32 // atomic (only 0->1 winner should send)
432
431
}
@@ -847,24 +846,31 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
847
846
return nil , ErrHijacked
848
847
}
849
848
849
+ var (
850
+ wholeReqDeadline time.Time // or zero if none
851
+ hdrDeadline time.Time // or zero if none
852
+ )
853
+ t0 := time .Now ()
854
+ if d := c .server .readHeaderTimeout (); d != 0 {
855
+ hdrDeadline = t0 .Add (d )
856
+ }
850
857
if d := c .server .ReadTimeout ; d != 0 {
851
- c . rwc . SetReadDeadline ( time . Now (). Add (d ) )
858
+ wholeReqDeadline = t0 . Add (d )
852
859
}
860
+ c .rwc .SetReadDeadline (hdrDeadline )
853
861
if d := c .server .WriteTimeout ; d != 0 {
854
862
defer func () {
855
863
c .rwc .SetWriteDeadline (time .Now ().Add (d ))
856
864
}()
857
865
}
858
866
859
867
c .r .setReadLimit (c .server .initialReadLimitSize ())
860
- c .mu .Lock () // while using bufr
861
868
if c .lastMethod == "POST" {
862
869
// RFC 2616 section 4.1 tolerance for old buggy clients.
863
870
peek , _ := c .bufr .Peek (4 ) // ReadRequest will get err below
864
871
c .bufr .Discard (numLeadingCRorLF (peek ))
865
872
}
866
873
req , err := readRequest (c .bufr , keepHostHeader )
867
- c .mu .Unlock ()
868
874
if err != nil {
869
875
if c .r .hitReadLimit () {
870
876
return nil , errTooLarge
@@ -910,6 +916,11 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
910
916
body .doEarlyClose = true
911
917
}
912
918
919
+ // Adjust the read deadline if necessary.
920
+ if ! hdrDeadline .Equal (wholeReqDeadline ) {
921
+ c .rwc .SetReadDeadline (wholeReqDeadline )
922
+ }
923
+
913
924
w = & response {
914
925
conn : c ,
915
926
cancelCtx : cancelCtx ,
@@ -1710,6 +1721,14 @@ func (c *conn) serve(ctx context.Context) {
1710
1721
}
1711
1722
c .setState (c .rwc , StateIdle )
1712
1723
c .curReq .Store ((* response )(nil ))
1724
+
1725
+ if d := c .server .idleTimeout (); d != 0 {
1726
+ c .rwc .SetReadDeadline (time .Now ().Add (d ))
1727
+ if _ , err := c .bufr .Peek (4 ); err != nil {
1728
+ return
1729
+ }
1730
+ }
1731
+ c .rwc .SetReadDeadline (time.Time {})
1713
1732
}
1714
1733
}
1715
1734
@@ -2168,11 +2187,36 @@ func Serve(l net.Listener, handler Handler) error {
2168
2187
// A Server defines parameters for running an HTTP server.
2169
2188
// The zero value for Server is a valid configuration.
2170
2189
type Server struct {
2171
- Addr string // TCP address to listen on, ":http" if empty
2172
- Handler Handler // handler to invoke, http.DefaultServeMux if nil
2173
- ReadTimeout time.Duration // maximum duration before timing out read of the request
2174
- WriteTimeout time.Duration // maximum duration before timing out write of the response
2175
- TLSConfig * tls.Config // optional TLS config, used by ListenAndServeTLS
2190
+ Addr string // TCP address to listen on, ":http" if empty
2191
+ Handler Handler // handler to invoke, http.DefaultServeMux if nil
2192
+ TLSConfig * tls.Config // optional TLS config, used by ListenAndServeTLS
2193
+
2194
+ // ReadTimeout is the maximum duration for reading the entire
2195
+ // request, including the body.
2196
+ //
2197
+ // Because ReadTimeout does not let Handlers make per-request
2198
+ // decisions on each request body's acceptable deadline or
2199
+ // upload rate, most users will prefer to use
2200
+ // ReadHeaderTimeout. It is valid to use them both.
2201
+ ReadTimeout time.Duration
2202
+
2203
+ // ReadHeaderTimeout is the amount of time allowed to read
2204
+ // request headers. The connection's read deadline is reset
2205
+ // after reading the headers and the Handler can decide what
2206
+ // is considered too slow for the body.
2207
+ ReadHeaderTimeout time.Duration
2208
+
2209
+ // WriteTimeout is the maximum duration before timing out
2210
+ // writes of the response. It is reset whenever a new
2211
+ // request's header is read. Like ReadTimeout, it does not
2212
+ // let Handlers make decisions on a per-request basis.
2213
+ WriteTimeout time.Duration
2214
+
2215
+ // IdleTimeout is the maximum amount of time to wait for the
2216
+ // next request when keep-alives are enabled. If IdleTimeout
2217
+ // is zero, the value of ReadTimeout is used. If both are
2218
+ // zero, there is no timeout.
2219
+ IdleTimeout time.Duration
2176
2220
2177
2221
// MaxHeaderBytes controls the maximum number of bytes the
2178
2222
// server will read parsing the request header's keys and
@@ -2366,6 +2410,20 @@ func (srv *Server) Serve(l net.Listener) error {
2366
2410
}
2367
2411
}
2368
2412
2413
+ func (s * Server ) idleTimeout () time.Duration {
2414
+ if s .IdleTimeout != 0 {
2415
+ return s .IdleTimeout
2416
+ }
2417
+ return s .ReadTimeout
2418
+ }
2419
+
2420
+ func (s * Server ) readHeaderTimeout () time.Duration {
2421
+ if s .ReadHeaderTimeout != 0 {
2422
+ return s .ReadHeaderTimeout
2423
+ }
2424
+ return s .ReadTimeout
2425
+ }
2426
+
2369
2427
func (s * Server ) doKeepAlives () bool {
2370
2428
return atomic .LoadInt32 (& s .disableKeepAlives ) == 0
2371
2429
}
0 commit comments