response_writer.go (2854B)
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 5 package gin 6 7 import ( 8 "bufio" 9 "io" 10 "net" 11 "net/http" 12 ) 13 14 const ( 15 noWritten = -1 16 defaultStatus = http.StatusOK 17 ) 18 19 // ResponseWriter ... 20 type ResponseWriter interface { 21 http.ResponseWriter 22 http.Hijacker 23 http.Flusher 24 http.CloseNotifier 25 26 // Status returns the HTTP response status code of the current request. 27 Status() int 28 29 // Size returns the number of bytes already written into the response http body. 30 // See Written() 31 Size() int 32 33 // WriteString writes the string into the response body. 34 WriteString(string) (int, error) 35 36 // Written returns true if the response body was already written. 37 Written() bool 38 39 // WriteHeaderNow forces to write the http header (status code + headers). 40 WriteHeaderNow() 41 42 // Pusher get the http.Pusher for server push 43 Pusher() http.Pusher 44 } 45 46 type responseWriter struct { 47 http.ResponseWriter 48 size int 49 status int 50 } 51 52 var _ ResponseWriter = (*responseWriter)(nil) 53 54 func (w *responseWriter) Unwrap() http.ResponseWriter { 55 return w.ResponseWriter 56 } 57 58 func (w *responseWriter) reset(writer http.ResponseWriter) { 59 w.ResponseWriter = writer 60 w.size = noWritten 61 w.status = defaultStatus 62 } 63 64 func (w *responseWriter) WriteHeader(code int) { 65 if code > 0 && w.status != code { 66 if w.Written() { 67 debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code) 68 return 69 } 70 w.status = code 71 } 72 } 73 74 func (w *responseWriter) WriteHeaderNow() { 75 if !w.Written() { 76 w.size = 0 77 w.ResponseWriter.WriteHeader(w.status) 78 } 79 } 80 81 func (w *responseWriter) Write(data []byte) (n int, err error) { 82 w.WriteHeaderNow() 83 n, err = w.ResponseWriter.Write(data) 84 w.size += n 85 return 86 } 87 88 func (w *responseWriter) WriteString(s string) (n int, err error) { 89 w.WriteHeaderNow() 90 n, err = io.WriteString(w.ResponseWriter, s) 91 w.size += n 92 return 93 } 94 95 func (w *responseWriter) Status() int { 96 return w.status 97 } 98 99 func (w *responseWriter) Size() int { 100 return w.size 101 } 102 103 func (w *responseWriter) Written() bool { 104 return w.size != noWritten 105 } 106 107 // Hijack implements the http.Hijacker interface. 108 func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { 109 if w.size < 0 { 110 w.size = 0 111 } 112 return w.ResponseWriter.(http.Hijacker).Hijack() 113 } 114 115 // CloseNotify implements the http.CloseNotifier interface. 116 func (w *responseWriter) CloseNotify() <-chan bool { 117 return w.ResponseWriter.(http.CloseNotifier).CloseNotify() 118 } 119 120 // Flush implements the http.Flusher interface. 121 func (w *responseWriter) Flush() { 122 w.WriteHeaderNow() 123 w.ResponseWriter.(http.Flusher).Flush() 124 } 125 126 func (w *responseWriter) Pusher() (pusher http.Pusher) { 127 if pusher, ok := w.ResponseWriter.(http.Pusher); ok { 128 return pusher 129 } 130 return nil 131 }