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 5package http 6 7import ( 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. 17type 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]. 38func NewResponseController(rw ResponseWriter) *ResponseController { 39 return &ResponseController{rw} 40} 41 42type rwUnwrapper interface { 43 Unwrap() ResponseWriter 44} 45 46// Flush flushes buffered data to the client. 47func (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. 66func (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. 85func (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. 105func (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. 129func (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. 145func errNotSupported() error { 146 return fmt.Errorf("%w", ErrNotSupported) 147} 148