response_writer.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package martini
  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. http.Hijacker
  15. // Status returns the status code of the response or 0 if the response has 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(BeforeFunc)
  24. }
  25. // BeforeFunc is a function that is called before the ResponseWriter has been written to.
  26. type BeforeFunc func(ResponseWriter)
  27. // NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
  28. func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
  29. newRw := responseWriter{rw, 0, 0, nil}
  30. if cn, ok := rw.(http.CloseNotifier); ok {
  31. return &closeNotifyResponseWriter{newRw, cn}
  32. }
  33. return &newRw
  34. }
  35. type responseWriter struct {
  36. http.ResponseWriter
  37. status int
  38. size int
  39. beforeFuncs []BeforeFunc
  40. }
  41. func (rw *responseWriter) WriteHeader(s int) {
  42. rw.callBefore()
  43. rw.ResponseWriter.WriteHeader(s)
  44. rw.status = s
  45. }
  46. func (rw *responseWriter) Write(b []byte) (int, error) {
  47. if !rw.Written() {
  48. // The status will be StatusOK if WriteHeader has not been called yet
  49. rw.WriteHeader(http.StatusOK)
  50. }
  51. size, err := rw.ResponseWriter.Write(b)
  52. rw.size += size
  53. return size, err
  54. }
  55. func (rw *responseWriter) Status() int {
  56. return rw.status
  57. }
  58. func (rw *responseWriter) Size() int {
  59. return rw.size
  60. }
  61. func (rw *responseWriter) Written() bool {
  62. return rw.status != 0
  63. }
  64. func (rw *responseWriter) Before(before BeforeFunc) {
  65. rw.beforeFuncs = append(rw.beforeFuncs, before)
  66. }
  67. func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  68. hijacker, ok := rw.ResponseWriter.(http.Hijacker)
  69. if !ok {
  70. return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
  71. }
  72. return hijacker.Hijack()
  73. }
  74. func (rw *responseWriter) callBefore() {
  75. for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
  76. rw.beforeFuncs[i](rw)
  77. }
  78. }
  79. func (rw *responseWriter) Flush() {
  80. flusher, ok := rw.ResponseWriter.(http.Flusher)
  81. if ok {
  82. flusher.Flush()
  83. }
  84. }
  85. type closeNotifyResponseWriter struct {
  86. responseWriter
  87. closeNotifier http.CloseNotifier
  88. }
  89. func (rw *closeNotifyResponseWriter) CloseNotify() <-chan bool {
  90. return rw.closeNotifier.CloseNotify()
  91. }