gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }