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 }