@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 675 lines 22 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package caddyhttp
16
17 import (
18 "context"
19 "errors"
20 "io"
21 "math"
22 "math/bits"
23 "net/http"
24 "os"
25 "sync"
26 "time"
27
28 "go.uber.org/zap"
29 "go.uber.org/zap/zapcore"
30
31 "github.com/caddyserver/caddy/v2"
32 )
33
34 // DefaultMaxWriteChunk is used by IdleTimeoutWriter when MaxChunk is zero.
35 // See IdleTimeoutWriter for why a limit is needed at all; nginx's
36 // analogous sendfile_max_chunk defaults to 2 MiB and is admin-tunable
37 // for the same reason this is exposed as a field rather than a constant.
38 const DefaultMaxWriteChunk = 64 * 1024
39
40 // IdleDeadline computes the next read/write deadline for the idle-reset
41 // mechanism shared by IdleTimeoutReader and IdleTimeoutWriter.
42 //
43 // With MinRate == 0, the deadline is simply pushed forward on every
44 // call (now+Timeout): a slow but steadily-progressing transfer is never
45 // killed, while a connection that stalls (no bytes for the duration of
46 // Timeout) is. This alone doesn't bound a transfer that trickles just
47 // enough data to never go idle.
48 //
49 // With MinRate > 0, the allowance instead grows from a fixed Start
50 // based on bytes transferred so far (1/MinRate seconds of extra
51 // allowance per byte), matching Apache mod_reqtimeout's MinRate: a
52 // trickle that doesn't sustain MinRate bytes/sec falls behind real
53 // time and gets cut, even though no single call ever stalls.
54 //
55 // HardDeadline, if non-zero, caps the result either way, so this can't
56 // silently defeat an explicitly configured ReadTimeout/WriteTimeout
57 // ceiling.
58 type IdleDeadline struct {
59 Start time.Time
60 Timeout time.Duration
61 MinRate int64
62 HardDeadline time.Time
63
64 transferred int64
65 }
66
67 func (d *IdleDeadline) next() (deadline time.Time) {
68 if d.MinRate > 0 {
69 allowance := d.Timeout + rateCredit(d.transferred, d.MinRate)
70 if allowance < d.Timeout { // the sum overflowed
71 allowance = math.MaxInt64
72 }
73 deadline = d.Start.Add(allowance)
74 } else {
75 deadline = time.Now().Add(d.Timeout)
76 }
77 if !d.HardDeadline.IsZero() && deadline.After(d.HardDeadline) {
78 deadline = d.HardDeadline
79 }
80
81 return
82 }
83
84 // rateCredit returns how long transferring n bytes may take at rate
85 // bytes/second, saturating instead of overflowing: n * time.Second exceeds
86 // int64 once n passes about 9.2 GB, which would turn the credit negative
87 // and abort large transfers that easily sustain the rate.
88 func rateCredit(n, rate int64) time.Duration {
89 if n <= 0 {
90 return 0
91 }
92 hi, lo := bits.Mul64(uint64(n), uint64(time.Second))
93 if hi >= uint64(rate) {
94 return math.MaxInt64
95 }
96 q, _ := bits.Div64(hi, lo, uint64(rate))
97 if q > math.MaxInt64 {
98 return math.MaxInt64
99 }
100 return time.Duration(q)
101 }
102
103 // idleOverride holds what restore needs to undo an override.
104 type idleOverride struct {
105 prev IdleDeadline
106 at time.Time
107 }
108
109 // override replaces the timeout and minimum rate, counting the MinRate
110 // allowance from now, and returns what restore needs to put the
111 // previous settings back. HardDeadline is kept.
112 func (d *IdleDeadline) override(timeout time.Duration, minRate int64) idleOverride {
113 o := idleOverride{prev: *d, at: time.Now()}
114 d.Start = o.at
115 d.Timeout = timeout
116 d.MinRate = minRate
117 d.transferred = 0
118 return o
119 }
120
121 // restore puts back the settings replaced by override. The previous
122 // MinRate window is suspended while overridden: its start moves forward
123 // by the time spent overridden, and bytes transferred in the meantime
124 // don't count towards it, so the restored deadline can't already have
125 // expired because of time the override allowed.
126 func (d *IdleDeadline) restore(o idleOverride) {
127 prev := o.prev
128 prev.Start = prev.Start.Add(time.Since(o.at))
129 *d = prev
130 }
131
132 // IdleTimeoutReader wraps a request body with IdleDeadline, resetting
133 // the read deadline before every Read call instead of bounding the
134 // whole body transfer with a single hard deadline.
135 // The deadline is cleared after a non-timeout error (most likely io.EOF) is
136 // encountered when reading the body to prevent context canceled errors for h1
137 // requests. An expired deadline is kept when DrainDeadline is set to bound
138 // net/http's post-handler drain.
139 // see: https://github.com/caddyserver/caddy/issues/8103
140 //
141 // A read deadline set by a handler through http.ResponseController
142 // reaches SetReadDeadline and caps every idle reset, so a handler can
143 // tighten the idle timeout but can't loosen it.
144 type IdleTimeoutReader struct {
145 io.ReadCloser
146 Ctrl *http.ResponseController
147 Deadline IdleDeadline
148 Logger *zap.Logger
149
150 // DrainDeadline makes HandlerDone arm a final idle deadline if
151 // the body is unfinished, bounding net/http's post-handler drain.
152 // Only HTTP/1 drains a request body on the connection after the
153 // handler returns, so it is pointless (and costs a timer on
154 // HTTP/2) for other protocols or requests without a body.
155 DrainDeadline bool
156
157 // ClearBetweenReads makes the reader put back the earliest of
158 // HardDeadline and the deadline set by the handler (no deadline if
159 // there is neither) after every successful read, so the idle
160 // deadline only bounds reads in flight. It is required for HTTP/2,
161 // where the read deadline is a timer that fails the body when it
162 // fires, even with no read in flight: otherwise a handler that stops
163 // reading for longer than the timeout (e.g. while an upstream is
164 // slow to accept the body) loses the body, although the client is
165 // only held back by flow control. Other protocols only check the
166 // deadline during a read.
167 ClearBetweenReads bool
168
169 mu sync.Mutex
170 unsupported bool
171 armed armedDeadline
172 installed time.Time // Last deadline successfully installed through Ctrl.
173 reading bool
174 finished bool
175 terminalErr error
176
177 handlerDeadline time.Time
178 }
179
180 // armedDeadline is which read deadline IdleTimeoutReader has armed.
181 type armedDeadline uint8
182
183 const (
184 // deadlineNone means no deadline is armed.
185 deadlineNone armedDeadline = iota
186 // deadlineIdle means the idle deadline from IdleDeadline.next is
187 // armed.
188 deadlineIdle
189 // deadlineHard means only the ceiling (HardDeadline or the
190 // deadline set by the handler) is armed, as put back between reads
191 // with ClearBetweenReads or set by the handler.
192 deadlineHard
193 )
194
195 // SetReadDeadline sets the read deadline on behalf of a handler and
196 // keeps it as a ceiling for the idle deadline, until the handler sets
197 // another one. A zero deadline removes the ceiling. HardDeadline still
198 // applies, and so does the idle deadline of a read in flight or the
199 // expired one bounding the drain of a timed-out body.
200 func (r *IdleTimeoutReader) SetReadDeadline(deadline time.Time) error {
201 r.mu.Lock()
202 defer r.mu.Unlock()
203
204 prev := r.handlerDeadline
205 r.handlerDeadline = deadline
206 install := r.ceilingLocked()
207 pinned := (r.reading && r.armed == deadlineIdle) || r.keepExpiredLocked()
208 if pinned && (install.IsZero() || r.installed.Before(install)) {
209 install = r.installed
210 }
211 if err := r.Ctrl.SetReadDeadline(install); err != nil {
212 r.handlerDeadline = prev
213 return err
214 }
215 r.installed = install
216 if pinned {
217 return nil
218 }
219 if install.IsZero() {
220 r.armed = deadlineNone
221 } else {
222 r.armed = deadlineHard
223 }
224 return nil
225 }
226
227 // ceilingLocked returns the earliest of HardDeadline and the deadline
228 // set by the handler, or zero if there is neither.
229 func (r *IdleTimeoutReader) ceilingLocked() time.Time {
230 hard := r.Deadline.HardDeadline
231 if r.handlerDeadline.IsZero() || (!hard.IsZero() && hard.Before(r.handlerDeadline)) {
232 return hard
233 }
234 return r.handlerDeadline
235 }
236
237 func (r *IdleTimeoutReader) Read(p []byte) (int, error) {
238 r.mu.Lock()
239 if r.terminalErr != nil {
240 err := r.terminalErr
241 r.mu.Unlock()
242 return 0, err
243 }
244 if !r.finished && !r.unsupported {
245 r.setDeadlineLocked("could not set read deadline")
246 }
247 r.reading = true
248 r.mu.Unlock()
249
250 n, err := r.ReadCloser.Read(p)
251
252 r.mu.Lock()
253 r.reading = false
254 r.Deadline.transferred += int64(n)
255 if err != nil {
256 r.terminalErr = err
257 if !r.finished {
258 r.clearDeadlineLocked()
259 }
260 } else if r.ClearBetweenReads && !r.finished {
261 r.releaseDeadlineLocked()
262 }
263 r.mu.Unlock()
264
265 return n, err
266 }
267
268 // HandlerDone prevents later body reads from using the response controller.
269 // If the body is not finished and DrainDeadline is set, it leaves an idle
270 // deadline armed for net/http's post-handler drain. Otherwise, it clears a
271 // deadline left from a finished body, put back between reads or set by the
272 // handler, unless the body timed out with an expired drain deadline. It must
273 // be called before the installing handler returns.
274 func (r *IdleTimeoutReader) HandlerDone() {
275 r.mu.Lock()
276 defer r.mu.Unlock()
277
278 if r.finished {
279 return
280 }
281 switch {
282 case r.terminalErr != nil:
283 r.clearDeadlineLocked()
284 case r.DrainDeadline && r.armed != deadlineIdle && !r.unsupported:
285 r.setDeadlineLocked("could not set final read deadline")
286 case r.armed == deadlineHard:
287 r.clearDeadlineLocked()
288 }
289 r.finished = true
290 }
291
292 // Override makes the reader use timeout and minRate instead of its own
293 // settings until the returned function is called, which puts them back.
294 // The MinRate allowance is counted from the call, and HardDeadline still
295 // applies. This lets a more specific scope, like the timeouts handler,
296 // take precedence over the settings the reader was created with. A
297 // deadline already armed is moved to the new settings both times, since
298 // on HTTP/2 it is a timer that fails the body when it fires, even with
299 // no read in flight.
300 func (r *IdleTimeoutReader) Override(timeout time.Duration, minRate int64) (restore func()) {
301 r.mu.Lock()
302 o := r.Deadline.override(timeout, minRate)
303 r.rearmLocked()
304 r.mu.Unlock()
305
306 return func() {
307 r.mu.Lock()
308 r.Deadline.restore(o)
309 r.rearmLocked()
310 r.mu.Unlock()
311 }
312 }
313
314 // rearmLocked moves an armed deadline to what the current settings give.
315 func (r *IdleTimeoutReader) rearmLocked() {
316 if r.armed == deadlineIdle && !r.finished && !r.unsupported && r.terminalErr == nil {
317 r.setDeadlineLocked("could not set read deadline")
318 }
319 }
320
321 func (r *IdleTimeoutReader) setDeadlineLocked(logMessage string) {
322 deadline := r.Deadline.next()
323 if !r.handlerDeadline.IsZero() && deadline.After(r.handlerDeadline) {
324 deadline = r.handlerDeadline
325 }
326
327 if r.setReadDeadlineLocked(deadline, logMessage) {
328 r.armed = deadlineIdle
329 }
330 }
331
332 // setReadDeadlineLocked always sets the requested deadline: another handler
333 // may have changed it through its own response controller since our last call.
334 // It reports whether the deadline was set successfully.
335 func (r *IdleTimeoutReader) setReadDeadlineLocked(deadline time.Time, logMessage string) bool {
336 if err := r.Ctrl.SetReadDeadline(deadline); err != nil {
337 r.unsupported = true
338 if c := r.Logger.Check(zapcore.DebugLevel, logMessage); c != nil {
339 c.Write(zap.Error(err))
340 }
341 return false
342 }
343 r.installed = deadline
344 return true
345 }
346
347 // releaseDeadlineLocked replaces the idle deadline with the earliest of
348 // HardDeadline and the deadline set by the handler.
349 func (r *IdleTimeoutReader) releaseDeadlineLocked() {
350 if r.armed != deadlineIdle || r.unsupported {
351 return
352 }
353
354 // once the ceiling has passed, the deadline set before the read
355 // (capped to it) has already expired; keep it
356 ceiling := r.ceilingLocked()
357 if !ceiling.IsZero() && !time.Now().Before(ceiling) {
358 return
359 }
360
361 if !r.setReadDeadlineLocked(ceiling, "could not release read deadline") {
362 return
363 }
364 if ceiling.IsZero() {
365 r.armed = deadlineNone
366 } else {
367 r.armed = deadlineHard
368 }
369 }
370
371 func (r *IdleTimeoutReader) clearDeadlineLocked() {
372 if r.armed == deadlineNone {
373 return
374 }
375 if r.keepExpiredLocked() {
376 return
377 }
378 if !r.setReadDeadlineLocked(time.Time{}, "could not clear read deadline") {
379 return
380 }
381 r.armed = deadlineNone
382 }
383
384 // keepExpiredLocked reports whether the installed deadline expired with
385 // the body and must be kept. HTTP/1 drains a small unread body before
386 // writing the response. Clearing its expired deadline would let a
387 // stalled client block that drain, and therefore the error response,
388 // indefinitely.
389 func (r *IdleTimeoutReader) keepExpiredLocked() bool {
390 return r.DrainDeadline && !r.installed.IsZero() && !time.Now().Before(r.installed) &&
391 errors.Is(r.terminalErr, os.ErrDeadlineExceeded)
392 }
393
394 // IdleTimeoutWriter wraps a ResponseWriter with IdleDeadline, resetting
395 // the write deadline before every Write, ReadFrom and Flush call, the same
396 // way IdleTimeoutReader does for reads. With MinRate == 0, the deadline
397 // only bounds the write or flush actually in flight, so a handler that
398 // pauses between writes (e.g. streaming or SSE) is unaffected.
399 //
400 // That relies on a deadline left armed between writes being harmless,
401 // which holds for HTTP/1 and HTTP/3, where it is only checked by the
402 // next write on the connection or stream. On HTTP/2 the write deadline
403 // is a timer that resets the stream when it fires, even with no write
404 // in flight, so ClearBetweenWrites must be set for HTTP/2 requests
405 // (see #8118).
406 //
407 // MaxChunk bounds how much a single underlying Write/ReadFrom call is
408 // allowed to cover; zero uses DefaultMaxWriteChunk. SetWriteDeadline
409 // bounds the whole call it precedes, not just a stall within it:
410 // net.Conn.Write loops internally until the entire buffer is sent
411 // (unlike Read, which returns after one syscall), and
412 // ResponseWriter.ReadFrom hands the entire remaining source to the
413 // connection in one call, be it via sendfile or an internal buffered
414 // copy loop. Without chunking, a single large Write or a large body
415 // copied via io.Copy would have its whole transfer bounded by one
416 // deadline, silently truncating a slow-but-healthy transfer exactly
417 // like a hard WriteTimeout would. A 64 KiB default still preserves
418 // most of the sendfile fast path's benefit (net/sendfile.go
419 // special-cases *io.LimitedReader to keep using sendfile per chunk).
420 //
421 // A write deadline set by a handler through http.ResponseController
422 // reaches SetWriteDeadline and caps every idle reset, so a handler can
423 // tighten the idle timeout (e.g. to drop a slow SSE subscriber) but
424 // can't loosen it.
425 type IdleTimeoutWriter struct {
426 *ResponseWriterWrapper
427 Ctrl *http.ResponseController
428 Deadline IdleDeadline
429 MaxChunk int
430 Logger *zap.Logger
431
432 // ClearBetweenWrites makes the writer clear its idle deadline after
433 // every successful write or flush, putting back HardDeadline or the
434 // deadline set by the handler if any, and arm a final one in
435 // HandlerDone if written data may still be buffered. It is required
436 // for HTTP/2 and unnecessary (and costs a deadline update per write)
437 // for other protocols.
438 ClearBetweenWrites bool
439
440 unsupported bool
441 // deadlineSet is whether the idle deadline is armed. clearDeadline
442 // leaves HardDeadline armed, if any, which nothing needs to undo.
443 deadlineSet bool
444 unflushed bool
445 handlerDeadline time.Time
446 }
447
448 // SetWriteDeadline sets the write deadline on behalf of a handler and
449 // keeps it as a ceiling for the idle deadline, until the handler sets
450 // another one. A zero deadline removes the ceiling.
451 func (w *IdleTimeoutWriter) SetWriteDeadline(deadline time.Time) error {
452 if err := w.Ctrl.SetWriteDeadline(deadline); err != nil {
453 return err
454 }
455 w.handlerDeadline = deadline
456 return nil
457 }
458
459 // ceiling returns the earliest of HardDeadline and the deadline set by
460 // the handler, or zero if there is neither.
461 func (w *IdleTimeoutWriter) ceiling() time.Time {
462 hard := w.Deadline.HardDeadline
463 if w.handlerDeadline.IsZero() || (!hard.IsZero() && hard.Before(w.handlerDeadline)) {
464 return hard
465 }
466 return w.handlerDeadline
467 }
468
469 func (w *IdleTimeoutWriter) resetDeadline() {
470 if w.unsupported {
471 return
472 }
473
474 deadline := w.Deadline.next()
475 if !w.handlerDeadline.IsZero() && deadline.After(w.handlerDeadline) {
476 deadline = w.handlerDeadline
477 }
478
479 if w.setWriteDeadline(deadline, "could not set write deadline") {
480 w.deadlineSet = true
481 }
482 }
483
484 // setWriteDeadline always sets the requested deadline: another handler may
485 // have changed it through its own response controller since our last call.
486 // It reports whether the deadline was set successfully.
487 func (w *IdleTimeoutWriter) setWriteDeadline(deadline time.Time, logMessage string) bool {
488 if err := w.Ctrl.SetWriteDeadline(deadline); err != nil {
489 w.unsupported = true
490 if c := w.Logger.Check(zapcore.DebugLevel, logMessage); c != nil {
491 c.Write(zap.Error(err))
492 }
493 return false
494 }
495 return true
496 }
497
498 // clearDeadline replaces the idle deadline set by resetDeadline with
499 // the earliest of HardDeadline and the deadline set by the handler,
500 // which is zero (no deadline) if there is neither. It does nothing
501 // unless ClearBetweenWrites is set.
502 func (w *IdleTimeoutWriter) clearDeadline() {
503 if !w.ClearBetweenWrites || !w.deadlineSet || w.unsupported {
504 return
505 }
506
507 // once the ceiling has passed, the deadline set by resetDeadline
508 // (capped to it) has already expired; keep it
509 ceiling := w.ceiling()
510 if !ceiling.IsZero() && !time.Now().Before(ceiling) {
511 return
512 }
513
514 if !w.setWriteDeadline(ceiling, "could not clear write deadline") {
515 return
516 }
517 w.deadlineSet = false
518 }
519
520 // HandlerDone arms a final idle deadline if ClearBetweenWrites is set
521 // and data written since the last flush may still be buffered, so that
522 // the flush net/http does after the handler returns is bounded too. It
523 // must be called before the installing handler returns, since the
524 // response controller can't be used after that.
525 func (w *IdleTimeoutWriter) HandlerDone() {
526 if w.ClearBetweenWrites && w.unflushed && !w.deadlineSet {
527 w.resetDeadline()
528 }
529 }
530
531 // Override makes the writer use timeout, minRate and, if positive,
532 // maxChunk instead of its own settings until the returned function is
533 // called, which puts them back. The MinRate allowance is counted from
534 // the call, and HardDeadline still applies. This lets a more specific
535 // scope, like the timeouts handler, take precedence over the settings
536 // the writer was created with. A deadline already armed is moved to the
537 // new settings both times, since on HTTP/2 it is a timer that resets
538 // the stream when it fires.
539 func (w *IdleTimeoutWriter) Override(timeout time.Duration, minRate int64, maxChunk int) (restore func()) {
540 o := w.Deadline.override(timeout, minRate)
541 prevMaxChunk := w.MaxChunk
542 if maxChunk > 0 {
543 w.MaxChunk = maxChunk
544 }
545 w.rearm()
546
547 return func() {
548 w.Deadline.restore(o)
549 w.MaxChunk = prevMaxChunk
550 w.rearm()
551 }
552 }
553
554 // rearm moves an armed deadline to what the current settings give.
555 func (w *IdleTimeoutWriter) rearm() {
556 if w.deadlineSet {
557 w.resetDeadline()
558 }
559 }
560
561 func (w *IdleTimeoutWriter) maxChunk() int {
562 if w.MaxChunk > 0 {
563 return w.MaxChunk
564 }
565 return DefaultMaxWriteChunk
566 }
567
568 func (w *IdleTimeoutWriter) Write(p []byte) (int, error) {
569 maxChunk := w.maxChunk()
570 var total int
571 for len(p) > 0 {
572 chunk := p
573 if len(chunk) > maxChunk {
574 chunk = chunk[:maxChunk]
575 }
576 w.resetDeadline()
577 n, err := w.ResponseWriterWrapper.Write(chunk)
578 total += n
579 w.Deadline.transferred += int64(n)
580 p = p[n:]
581 if n > 0 {
582 w.unflushed = true
583 }
584 if err != nil {
585 return total, err
586 }
587 }
588 w.clearDeadline()
589 return total, nil
590 }
591
592 func (w *IdleTimeoutWriter) ReadFrom(r io.Reader) (int64, error) {
593 maxChunk := w.maxChunk()
594 var total int64
595 for {
596 w.resetDeadline()
597 n, err := w.ResponseWriterWrapper.ReadFrom(io.LimitReader(r, int64(maxChunk)))
598 total += n
599 w.Deadline.transferred += n
600 if n > 0 {
601 w.unflushed = true
602 }
603 if err != nil {
604 // the error may come from r rather than the client, in
605 // which case the response can still be written to
606 w.clearDeadline()
607 return total, err
608 }
609 if n < int64(maxChunk) {
610 w.clearDeadline()
611 return total, nil
612 }
613 }
614 }
615
616 // FlushError flushes the underlying writer under the idle deadline. A
617 // small write may only fill a buffer, leaving the flush as the call
618 // that actually blocks on a client that stopped reading.
619 func (w *IdleTimeoutWriter) FlushError() error {
620 w.resetDeadline()
621 err := http.NewResponseController(w.ResponseWriter).Flush()
622 if err != nil {
623 return err
624 }
625 w.unflushed = false
626 w.clearDeadline()
627 return nil
628 }
629
630 // readDeadlineWriter routes read deadlines set by handlers through
631 // http.ResponseController to the IdleTimeoutReader of the request,
632 // which would otherwise replace them before the next read.
633 type readDeadlineWriter struct {
634 ResponseWriterWrapper
635 reader *IdleTimeoutReader
636 }
637
638 func (w *readDeadlineWriter) SetReadDeadline(deadline time.Time) error {
639 return w.reader.SetReadDeadline(deadline)
640 }
641
642 // idleTimeouts holds the wrappers applying a request's idle timeouts.
643 type idleTimeouts struct {
644 reader *IdleTimeoutReader
645 writer *IdleTimeoutWriter
646 }
647
648 // idleTimeoutsCtxKey is the context key for idleTimeouts.
649 const idleTimeoutsCtxKey caddy.CtxKey = "idle_timeouts"
650
651 // IdleTimeoutsFromContext returns the IdleTimeoutReader and
652 // IdleTimeoutWriter that apply the idle timeouts of the request with
653 // context ctx. Either is nil if no idle timeout is applied that way. A
654 // handler with its own idle timeouts should Override these instead of
655 // wrapping the body or response writer again, since the wrapper closest
656 // to the connection sets the deadline last, and so would win.
657 func IdleTimeoutsFromContext(ctx context.Context) (*IdleTimeoutReader, *IdleTimeoutWriter) {
658 it, _ := ctx.Value(idleTimeoutsCtxKey).(idleTimeouts)
659 return it.reader, it.writer
660 }
661
662 // ContextWithIdleTimeouts returns a copy of ctx in which
663 // IdleTimeoutsFromContext returns reader and writer.
664 func ContextWithIdleTimeouts(ctx context.Context, reader *IdleTimeoutReader, writer *IdleTimeoutWriter) context.Context {
665 return context.WithValue(ctx, idleTimeoutsCtxKey, idleTimeouts{reader: reader, writer: writer})
666 }
667
668 // Interface guards
669 var (
670 _ io.ReadCloser = (*IdleTimeoutReader)(nil)
671 _ http.ResponseWriter = (*readDeadlineWriter)(nil)
672 _ http.ResponseWriter = (*IdleTimeoutWriter)(nil)
673 _ io.ReaderFrom = (*IdleTimeoutWriter)(nil)
674 _ interface{ FlushError() error } = (*IdleTimeoutWriter)(nil)
675 )