14 func TestResponseControllerFlush(t *testing.T) { run(t, testResponseControllerFlush) }
15 func testResponseControllerFlush(t *testing.T, mode testMode) {
16 continuec := make(chan struct{})
17 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
18 ctl := NewResponseController(w)
19 w.Write([]byte("one"))
20 if err := ctl.Flush(); err != nil {
21 t.Errorf("ctl.Flush() = %v, want nil", err)
25 w.Write([]byte("two"))
28 res, err := cst.c.Get(cst.ts.URL)
30 t.Fatalf("unexpected connection error: %v", err)
32 defer res.Body.Close()
34 buf := make([]byte, 16)
35 n, err := res.Body.Read(buf)
37 if err != nil || string(buf[:n]) != "one" {
38 t.Fatalf("Body.Read = %q, %v, want %q, nil", string(buf[:n]), err, "one")
41 got, err := io.ReadAll(res.Body)
42 if err != nil || string(got) != "two" {
43 t.Fatalf("Body.Read = %q, %v, want %q, nil", string(got), err, "two")
47 func TestResponseControllerHijack(t *testing.T) { run(t, testResponseControllerHijack) }
48 func testResponseControllerHijack(t *testing.T, mode testMode) {
49 const header = "X-Header"
51 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
52 ctl := NewResponseController(w)
53 c, _, err := ctl.Hijack()
54 if mode == http2Mode {
56 t.Errorf("ctl.Hijack = nil, want error")
58 w.Header().Set(header, value)
62 t.Errorf("ctl.Hijack = _, _, %v, want _, _, nil", err)
65 fmt.Fprintf(c, "HTTP/1.0 200 OK\r\n%v: %v\r\nContent-Length: 0\r\n\r\n", header, value)
67 res, err := cst.c.Get(cst.ts.URL)
71 if got, want := res.Header.Get(header), value; got != want {
72 t.Errorf("response header %q = %q, want %q", header, got, want)
76 func TestResponseControllerSetPastWriteDeadline(t *testing.T) {
77 run(t, testResponseControllerSetPastWriteDeadline)
79 func testResponseControllerSetPastWriteDeadline(t *testing.T, mode testMode) {
80 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
81 ctl := NewResponseController(w)
82 w.Write([]byte("one"))
83 if err := ctl.Flush(); err != nil {
84 t.Errorf("before setting deadline: ctl.Flush() = %v, want nil", err)
86 if err := ctl.SetWriteDeadline(time.Now().Add(-10 * time.Second)); err != nil {
87 t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
90 w.Write([]byte("two"))
91 if err := ctl.Flush(); err == nil {
92 t.Errorf("after setting deadline: ctl.Flush() = nil, want non-nil")
94 // Connection errors are sticky, so resetting the deadline does not permit
95 // making more progress. We might want to change this in the future, but verify
96 // the current behavior for now. If we do change this, we'll want to make sure
97 // to do so only for writing the response body, not headers.
98 if err := ctl.SetWriteDeadline(time.Now().Add(1 * time.Hour)); err != nil {
99 t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
101 w.Write([]byte("three"))
102 if err := ctl.Flush(); err == nil {
103 t.Errorf("after resetting deadline: ctl.Flush() = nil, want non-nil")
107 res, err := cst.c.Get(cst.ts.URL)
109 t.Fatalf("unexpected connection error: %v", err)
111 defer res.Body.Close()
112 b, _ := io.ReadAll(res.Body)
113 if string(b) != "one" {
114 t.Errorf("unexpected body: %q", string(b))
118 func TestResponseControllerSetFutureWriteDeadline(t *testing.T) {
119 run(t, testResponseControllerSetFutureWriteDeadline)
121 func testResponseControllerSetFutureWriteDeadline(t *testing.T, mode testMode) {
122 errc := make(chan error, 1)
123 startwritec := make(chan struct{})
124 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
125 ctl := NewResponseController(w)
127 if err := ctl.Flush(); err != nil {
128 t.Errorf("ctl.Flush() = %v, want nil", err)
130 <-startwritec // don't set the deadline until the client reads response headers
131 if err := ctl.SetWriteDeadline(time.Now().Add(1 * time.Millisecond)); err != nil {
132 t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
134 _, err := io.Copy(w, neverEnding('a'))
138 res, err := cst.c.Get(cst.ts.URL)
141 t.Fatalf("unexpected connection error: %v", err)
143 defer res.Body.Close()
144 _, err = io.Copy(io.Discard, res.Body)
146 t.Errorf("client reading from truncated request body: got nil error, want non-nil")
148 err = <-errc // io.Copy error
149 if !errors.Is(err, os.ErrDeadlineExceeded) {
150 t.Errorf("server timed out writing request body: got err %v; want os.ErrDeadlineExceeded", err)
154 func TestResponseControllerSetPastReadDeadline(t *testing.T) {
155 run(t, testResponseControllerSetPastReadDeadline)
157 func testResponseControllerSetPastReadDeadline(t *testing.T, mode testMode) {
158 readc := make(chan struct{})
159 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
160 ctl := NewResponseController(w)
162 n, err := io.ReadFull(r.Body, b)
164 if err != nil || string(b) != "one" {
165 t.Errorf("before setting read deadline: Read = %v, %q, want nil, %q", err, string(b), "one")
168 if err := ctl.SetReadDeadline(time.Now()); err != nil {
169 t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
172 b, err = io.ReadAll(r.Body)
173 if err == nil || string(b) != "" {
174 t.Errorf("after setting read deadline: Read = %q, nil, want error", string(b))
177 // Connection errors are sticky, so resetting the deadline does not permit
178 // making more progress. We might want to change this in the future, but verify
179 // the current behavior for now.
180 if err := ctl.SetReadDeadline(time.Time{}); err != nil {
181 t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
184 b, err = io.ReadAll(r.Body)
186 t.Errorf("after resetting read deadline: Read = %q, nil, want error", string(b))
191 var wg sync.WaitGroup
195 pw.Write([]byte("one"))
197 pw.Write([]byte("two"))
201 res, err := cst.c.Post(cst.ts.URL, "text/foo", pr)
203 defer res.Body.Close()
207 func TestResponseControllerSetFutureReadDeadline(t *testing.T) {
208 run(t, testResponseControllerSetFutureReadDeadline)
210 func testResponseControllerSetFutureReadDeadline(t *testing.T, mode testMode) {
211 respBody := "response body"
212 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, req *Request) {
213 ctl := NewResponseController(w)
214 if err := ctl.SetReadDeadline(time.Now().Add(1 * time.Millisecond)); err != nil {
215 t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
217 _, err := io.Copy(io.Discard, req.Body)
218 if !errors.Is(err, os.ErrDeadlineExceeded) {
219 t.Errorf("server timed out reading request body: got err %v; want os.ErrDeadlineExceeded", err)
221 w.Write([]byte(respBody))
224 res, err := cst.c.Post(cst.ts.URL, "text/apocryphal", pr)
228 defer res.Body.Close()
229 got, err := io.ReadAll(res.Body)
230 if string(got) != respBody || err != nil {
231 t.Errorf("client read response body: %q, %v; want %q, nil", string(got), err, respBody)
236 type wrapWriter struct {
240 func (w wrapWriter) Unwrap() ResponseWriter {
241 return w.ResponseWriter
244 func TestWrappedResponseController(t *testing.T) { run(t, testWrappedResponseController) }
245 func testWrappedResponseController(t *testing.T, mode testMode) {
246 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
248 ctl := NewResponseController(w)
249 if err := ctl.Flush(); err != nil {
250 t.Errorf("ctl.Flush() = %v, want nil", err)
252 if err := ctl.SetReadDeadline(time.Time{}); err != nil {
253 t.Errorf("ctl.SetReadDeadline() = %v, want nil", err)
255 if err := ctl.SetWriteDeadline(time.Time{}); err != nil {
256 t.Errorf("ctl.SetWriteDeadline() = %v, want nil", err)
259 res, err := cst.c.Get(cst.ts.URL)
261 t.Fatalf("unexpected connection error: %v", err)
263 io.Copy(io.Discard, res.Body)
264 defer res.Body.Close()