responsecontroller.mx raw

   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