response_writer.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package negroni
  2. import (
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "net/http"
  7. )
  8. // ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about
  9. // the response. It is recommended that middleware handlers use this construct to wrap a responsewriter
  10. // if the functionality calls for it.
  11. type ResponseWriter interface {
  12. http.ResponseWriter
  13. http.Flusher
  14. // Status returns the status code of the response or 0 if the response has
  15. // not been written
  16. Status() int
  17. // Written returns whether or not the ResponseWriter has been written.
  18. Written() bool
  19. // Size returns the size of the response body.
  20. Size() int
  21. // Before allows for a function to be called before the ResponseWriter has been written to. This is
  22. // useful for setting headers or any other operations that must happen before a response has been written.
  23. Before(func(ResponseWriter))
  24. }
  25. type beforeFunc func(ResponseWriter)
  26. // NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
  27. func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
  28. nrw := &responseWriter{
  29. ResponseWriter: rw,
  30. }
  31. if _, ok := rw.(http.CloseNotifier); ok {
  32. return &responseWriterCloseNotifer{nrw}
  33. }
  34. return nrw
  35. }
  36. type responseWriter struct {
  37. http.ResponseWriter
  38. status int
  39. size int
  40. beforeFuncs []beforeFunc
  41. }
  42. func (rw *responseWriter) WriteHeader(s int) {
  43. rw.status = s
  44. rw.callBefore()
  45. rw.ResponseWriter.WriteHeader(s)
  46. }
  47. func (rw *responseWriter) Write(b []byte) (int, error) {
  48. if !rw.Written() {
  49. // The status will be StatusOK if WriteHeader has not been called yet
  50. rw.WriteHeader(http.StatusOK)
  51. }
  52. size, err := rw.ResponseWriter.Write(b)
  53. rw.size += size
  54. return size, err
  55. }
  56. func (rw *responseWriter) Status() int {
  57. return rw.status
  58. }
  59. func (rw *responseWriter) Size() int {
  60. return rw.size
  61. }
  62. func (rw *responseWriter) Written() bool {
  63. return rw.status != 0
  64. }
  65. func (rw *responseWriter) Before(before func(ResponseWriter)) {
  66. rw.beforeFuncs = append(rw.beforeFuncs, before)
  67. }
  68. func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  69. hijacker, ok := rw.ResponseWriter.(http.Hijacker)
  70. if !ok {
  71. return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
  72. }
  73. return hijacker.Hijack()
  74. }
  75. func (rw *responseWriter) callBefore() {
  76. for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
  77. rw.beforeFuncs[i](rw)
  78. }
  79. }
  80. func (rw *responseWriter) Flush() {
  81. flusher, ok := rw.ResponseWriter.(http.Flusher)
  82. if ok {
  83. if !rw.Written() {
  84. // The status will be StatusOK if WriteHeader has not been called yet
  85. rw.WriteHeader(http.StatusOK)
  86. }
  87. flusher.Flush()
  88. }
  89. }
  90. type responseWriterCloseNotifer struct {
  91. *responseWriter
  92. }
  93. func (rw *responseWriterCloseNotifer) CloseNotify() <-chan bool {
  94. return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
  95. }