github.com/influx6/npkg@v0.8.8/nhttp/response.go (about)

     1  package nhttp
     2  
     3  import (
     4  	"bufio"
     5  	"errors"
     6  	"net"
     7  	"net/http"
     8  )
     9  
    10  var (
    11  	// ErrNoPush is returned when underline connection does
    12  	// not support Push API.
    13  	ErrNoPush = errors.New("push not supported")
    14  )
    15  
    16  // Response wraps an http.ResponseWriter and implements its interface to be used
    17  // by an HTTP handler to construct an HTTP response.
    18  // See: https://golang.org/pkg/net/http/#ResponseWriter
    19  type Response struct {
    20  	beforeFuncs []func()
    21  	afterFuncs  []func()
    22  	Writer      http.ResponseWriter
    23  	Status      int
    24  	Size        int64
    25  	finished    bool
    26  }
    27  
    28  // Before adds the giving function into a response before list.
    29  // Which should be executed before any write, but if the response
    30  // was already completed then the function is called.
    31  func (r *Response) Before(fn func()) {
    32  	if r.finished {
    33  		fn()
    34  		return
    35  	}
    36  	r.beforeFuncs = append(r.beforeFuncs, fn)
    37  }
    38  
    39  // After adds the giving function into a response after list.
    40  func (r *Response) After(fn func()) {
    41  	if r.finished {
    42  		fn()
    43  		return
    44  	}
    45  	r.afterFuncs = append(r.afterFuncs, fn)
    46  }
    47  
    48  // Header returns the header map for the writer that will be sent by
    49  // WriteHeader. Changing the header after a call to WriteHeader (or Write) has
    50  // no effect unless the modified headers were declared as trailers by setting
    51  // the "Trailer" header before the call to WriteHeader (see example)
    52  // To suppress implicit response headers, set their value to nil.
    53  // Example: https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
    54  func (r *Response) Header() http.Header {
    55  	return r.Writer.Header()
    56  }
    57  
    58  // WriteHeader sends an HTTP response header with status code. If WriteHeader is
    59  // not called explicitly, the first call to Write will trigger an implicit
    60  // WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly
    61  // used to send error codes.
    62  func (r *Response) WriteHeader(code int) {
    63  	if r.finished {
    64  		return
    65  	}
    66  
    67  	for _, fn := range r.beforeFuncs {
    68  		fn()
    69  	}
    70  
    71  	r.Status = code
    72  	r.Writer.WriteHeader(code)
    73  	r.finished = true
    74  
    75  	for _, fn := range r.afterFuncs {
    76  		fn()
    77  	}
    78  }
    79  
    80  // Write writes the data to the connection as part of an HTTP reply.
    81  func (r *Response) Write(b []byte) (n int, err error) {
    82  	if !r.finished {
    83  		r.WriteHeader(http.StatusOK)
    84  	}
    85  
    86  	n, err = r.Writer.Write(b)
    87  	r.Size += int64(n)
    88  	return
    89  }
    90  
    91  // Push adds support for http.Pusher, if available and lets you push resources.
    92  func (r *Response) Push(target string, ops *http.PushOptions) error {
    93  	if pusher, ok := r.Writer.(http.Pusher); ok {
    94  		return pusher.Push(target, ops)
    95  	}
    96  	return ErrNoPush
    97  }
    98  
    99  // Sent returns true/false if giving response has being sent/written.
   100  func (r *Response) Sent() bool {
   101  	return r.finished
   102  }
   103  
   104  // Flush implements the http.Flusher interface to allow an HTTP handler to flush
   105  // buffered data to the client.
   106  // See [http.Flusher](https://golang.org/pkg/net/http/#Flusher)
   107  func (r *Response) Flush() {
   108  	r.Writer.(http.Flusher).Flush()
   109  }
   110  
   111  // Hijack implements the http.Hijacker interface to allow an HTTP handler to
   112  // take over the connection.
   113  // See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker)
   114  func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
   115  	return r.Writer.(http.Hijacker).Hijack()
   116  }
   117  
   118  // CloseNotify implements the http.CloseNotifier interface to allow detecting
   119  // when the underlying connection has gone away.
   120  // This mechanism can be used to cancel long operations on the server if the
   121  // client has disconnected before the response is ready.
   122  // See [http.CloseNotifier](https://golang.org/pkg/net/http/#CloseNotifier)
   123  func (r *Response) CloseNotify() <-chan bool {
   124  	return r.Writer.(http.CloseNotifier).CloseNotify()
   125  }
   126  
   127  func (r *Response) reset(w http.ResponseWriter) {
   128  	r.Writer = w
   129  	r.Size = 0
   130  	r.Status = http.StatusOK
   131  	r.finished = false
   132  }