Source file src/net/http/responsecontroller.go
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