1 // Copyright 2022 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package http
6 7 import (
8 "bufio"
9 "fmt"
10 "net"
11 "time"
12 )
13 14 // A ResponseController is used by an HTTP handler to control the response.
15 //
16 // A ResponseController may not be used after the [Handler.ServeHTTP] method has returned.
17 type ResponseController struct {
18 rw ResponseWriter
19 }
20 21 // NewResponseController creates a [ResponseController] for a request.
22 //
23 // The ResponseWriter should be the original value passed to the [Handler.ServeHTTP] method,
24 // or have an Unwrap method returning the original ResponseWriter.
25 //
26 // If the ResponseWriter implements any of the following methods, the ResponseController
27 // will call them as appropriate:
28 //
29 // Flush()
30 // FlushError() error // alternative Flush returning an error
31 // Hijack() (net.Conn, *bufio.ReadWriter, error)
32 // SetReadDeadline(deadline time.Time) error
33 // SetWriteDeadline(deadline time.Time) error
34 // EnableFullDuplex() error
35 //
36 // If the ResponseWriter does not support a method, ResponseController returns
37 // an error matching [ErrNotSupported].
38 func NewResponseController(rw ResponseWriter) *ResponseController {
39 return &ResponseController{rw}
40 }
41 42 type rwUnwrapper interface {
43 Unwrap() ResponseWriter
44 }
45 46 // Flush flushes buffered data to the client.
47 func (c *ResponseController) Flush() error {
48 rw := c.rw
49 for {
50 switch t := rw.(type) {
51 case interface{ FlushError() error }:
52 return t.FlushError()
53 case Flusher:
54 t.Flush()
55 return nil
56 case rwUnwrapper:
57 rw = t.Unwrap()
58 default:
59 return errNotSupported()
60 }
61 }
62 }
63 64 // Hijack lets the caller take over the connection.
65 // See the [Hijacker] interface for details.
66 func (c *ResponseController) Hijack() (net.Conn, *bufio.ReadWriter, error) {
67 rw := c.rw
68 for {
69 switch t := rw.(type) {
70 case Hijacker:
71 return t.Hijack()
72 case rwUnwrapper:
73 rw = t.Unwrap()
74 default:
75 return nil, nil, errNotSupported()
76 }
77 }
78 }
79 80 // SetReadDeadline sets the deadline for reading the entire request, including the body.
81 // Reads from the request body after the deadline has been exceeded will return an error.
82 // A zero value means no deadline.
83 //
84 // Setting the read deadline after it has been exceeded will not extend it.
85 func (c *ResponseController) SetReadDeadline(deadline time.Time) error {
86 rw := c.rw
87 for {
88 switch t := rw.(type) {
89 case interface{ SetReadDeadline(time.Time) error }:
90 return t.SetReadDeadline(deadline)
91 case rwUnwrapper:
92 rw = t.Unwrap()
93 default:
94 return errNotSupported()
95 }
96 }
97 }
98 99 // SetWriteDeadline sets the deadline for writing the response.
100 // Writes to the response body after the deadline has been exceeded will not block,
101 // but may succeed if the data has been buffered.
102 // A zero value means no deadline.
103 //
104 // Setting the write deadline after it has been exceeded will not extend it.
105 func (c *ResponseController) SetWriteDeadline(deadline time.Time) error {
106 rw := c.rw
107 for {
108 switch t := rw.(type) {
109 case interface{ SetWriteDeadline(time.Time) error }:
110 return t.SetWriteDeadline(deadline)
111 case rwUnwrapper:
112 rw = t.Unwrap()
113 default:
114 return errNotSupported()
115 }
116 }
117 }
118 119 // EnableFullDuplex indicates that the request handler will interleave reads from [Request.Body]
120 // with writes to the [ResponseWriter].
121 //
122 // For HTTP/1 requests, the Go HTTP server by default consumes any unread portion of
123 // the request body before beginning to write the response, preventing handlers from
124 // concurrently reading from the request and writing the response.
125 // Calling EnableFullDuplex disables this behavior and permits handlers to continue to read
126 // from the request while concurrently writing the response.
127 //
128 // For HTTP/2 requests, the Go HTTP server always permits concurrent reads and responses.
129 func (c *ResponseController) EnableFullDuplex() error {
130 rw := c.rw
131 for {
132 switch t := rw.(type) {
133 case interface{ EnableFullDuplex() error }:
134 return t.EnableFullDuplex()
135 case rwUnwrapper:
136 rw = t.Unwrap()
137 default:
138 return errNotSupported()
139 }
140 }
141 }
142 143 // errNotSupported returns an error that Is ErrNotSupported,
144 // but is not == to it.
145 func errNotSupported() error {
146 return fmt.Errorf("%w", ErrNotSupported)
147 }
148