response_writer.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
  2. // Use of this source code is governed by a MIT style
  3. // license that can be found in the LICENSE file.
  4. package gin
  5. import (
  6. "bufio"
  7. "io"
  8. "net"
  9. "net/http"
  10. )
  11. const (
  12. noWritten = -1
  13. defaultStatus = http.StatusOK
  14. )
  15. // ResponseWriter ...
  16. type ResponseWriter interface {
  17. http.ResponseWriter
  18. http.Hijacker
  19. http.Flusher
  20. http.CloseNotifier
  21. // Returns the HTTP response status code of the current request.
  22. Status() int
  23. // Returns the number of bytes already written into the response http body.
  24. // See Written()
  25. Size() int
  26. // Writes the string into the response body.
  27. WriteString(string) (int, error)
  28. // Returns true if the response body was already written.
  29. Written() bool
  30. // Forces to write the http header (status code + headers).
  31. WriteHeaderNow()
  32. // get the http.Pusher for server push
  33. Pusher() http.Pusher
  34. }
  35. type responseWriter struct {
  36. http.ResponseWriter
  37. size int
  38. status int
  39. }
  40. var _ ResponseWriter = &responseWriter{}
  41. func (w *responseWriter) reset(writer http.ResponseWriter) {
  42. w.ResponseWriter = writer
  43. w.size = noWritten
  44. w.status = defaultStatus
  45. }
  46. func (w *responseWriter) WriteHeader(code int) {
  47. if code > 0 && w.status != code {
  48. if w.Written() {
  49. debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code)
  50. }
  51. w.status = code
  52. }
  53. }
  54. func (w *responseWriter) WriteHeaderNow() {
  55. if !w.Written() {
  56. w.size = 0
  57. w.ResponseWriter.WriteHeader(w.status)
  58. }
  59. }
  60. func (w *responseWriter) Write(data []byte) (n int, err error) {
  61. w.WriteHeaderNow()
  62. n, err = w.ResponseWriter.Write(data)
  63. w.size += n
  64. return
  65. }
  66. func (w *responseWriter) WriteString(s string) (n int, err error) {
  67. w.WriteHeaderNow()
  68. n, err = io.WriteString(w.ResponseWriter, s)
  69. w.size += n
  70. return
  71. }
  72. func (w *responseWriter) Status() int {
  73. return w.status
  74. }
  75. func (w *responseWriter) Size() int {
  76. return w.size
  77. }
  78. func (w *responseWriter) Written() bool {
  79. return w.size != noWritten
  80. }
  81. // Hijack implements the http.Hijacker interface.
  82. func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  83. if w.size < 0 {
  84. w.size = 0
  85. }
  86. return w.ResponseWriter.(http.Hijacker).Hijack()
  87. }
  88. // CloseNotify implements the http.CloseNotify interface.
  89. func (w *responseWriter) CloseNotify() <-chan bool {
  90. return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
  91. }
  92. // Flush implements the http.Flush interface.
  93. func (w *responseWriter) Flush() {
  94. w.WriteHeaderNow()
  95. w.ResponseWriter.(http.Flusher).Flush()
  96. }
  97. func (w *responseWriter) Pusher() (pusher http.Pusher) {
  98. if pusher, ok := w.ResponseWriter.(http.Pusher); ok {
  99. return pusher
  100. }
  101. return nil
  102. }