response_writer.go 2.41 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"bufio"
	"io"
	"net"
	"net/http"
)

const (
	noWritten     = -1
16
	defaultStatus = http.StatusOK
17 18
)

19 20 21 22 23
type responseWriterBase interface {
	http.ResponseWriter
	http.Hijacker
	http.Flusher
	http.CloseNotifier
24

25 26
	// Returns the HTTP response status code of the current request.
	Status() int
27

28 29 30
	// Returns the number of bytes already written into the response http body.
	// See Written()
	Size() int
31

32 33
	// Writes the string into the response body.
	WriteString(string) (int, error)
34

35 36
	// Returns true if the response body was already written.
	Written() bool
37

38 39 40
	// Forces to write the http header (status code + headers).
	WriteHeaderNow()
}
41

42 43 44 45 46
type responseWriter struct {
	http.ResponseWriter
	size   int
	status int
}
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

var _ ResponseWriter = &responseWriter{}

func (w *responseWriter) reset(writer http.ResponseWriter) {
	w.ResponseWriter = writer
	w.size = noWritten
	w.status = defaultStatus
}

func (w *responseWriter) WriteHeader(code int) {
	if code > 0 && w.status != code {
		if w.Written() {
			debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code)
		}
		w.status = code
	}
}

func (w *responseWriter) WriteHeaderNow() {
	if !w.Written() {
		w.size = 0
		w.ResponseWriter.WriteHeader(w.status)
	}
}

func (w *responseWriter) Write(data []byte) (n int, err error) {
	w.WriteHeaderNow()
	n, err = w.ResponseWriter.Write(data)
	w.size += n
	return
}

func (w *responseWriter) WriteString(s string) (n int, err error) {
	w.WriteHeaderNow()
	n, err = io.WriteString(w.ResponseWriter, s)
	w.size += n
	return
}

func (w *responseWriter) Status() int {
	return w.status
}

func (w *responseWriter) Size() int {
	return w.size
}

func (w *responseWriter) Written() bool {
	return w.size != noWritten
}

98
// Hijack implements the http.Hijacker interface.
99 100 101 102 103 104 105
func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	if w.size < 0 {
		w.size = 0
	}
	return w.ResponseWriter.(http.Hijacker).Hijack()
}

106
// CloseNotify implements the http.CloseNotify interface.
107 108 109 110
func (w *responseWriter) CloseNotify() <-chan bool {
	return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

111
// Flush implements the http.Flush interface.
112
func (w *responseWriter) Flush() {
113
	w.WriteHeaderNow()
114 115
	w.ResponseWriter.(http.Flusher).Flush()
}