github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/pkg/authorization/response.go (about)

     1  package authorization
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/json"
     7  	"fmt"
     8  	"net"
     9  	"net/http"
    10  )
    11  
    12  // ResponseModifier allows authorization plugins to read and modify the content of the http.response
    13  type ResponseModifier interface {
    14  	http.ResponseWriter
    15  
    16  	// RawBody returns the current http content
    17  	RawBody() []byte
    18  
    19  	// RawHeaders returns the current content of the http headers
    20  	RawHeaders() ([]byte, error)
    21  
    22  	// StatusCode returns the current status code
    23  	StatusCode() int
    24  
    25  	// OverrideBody replace the body of the HTTP reply
    26  	OverrideBody(b []byte)
    27  
    28  	// OverrideHeader replace the headers of the HTTP reply
    29  	OverrideHeader(b []byte) error
    30  
    31  	// OverrideStatusCode replaces the status code of the HTTP reply
    32  	OverrideStatusCode(statusCode int)
    33  
    34  	// Flush flushes all data to the HTTP response
    35  	Flush() error
    36  }
    37  
    38  // NewResponseModifier creates a wrapper to an http.ResponseWriter to allow inspecting and modifying the content
    39  func NewResponseModifier(rw http.ResponseWriter) ResponseModifier {
    40  	return &responseModifier{rw: rw, header: make(http.Header)}
    41  }
    42  
    43  // responseModifier is used as an adapter to http.ResponseWriter in order to manipulate and explore
    44  // the http request/response from docker daemon
    45  type responseModifier struct {
    46  	// The original response writer
    47  	rw     http.ResponseWriter
    48  	status int
    49  	// body holds the response body
    50  	body []byte
    51  	// header holds the response header
    52  	header http.Header
    53  	// statusCode holds the response status code
    54  	statusCode int
    55  }
    56  
    57  // WriterHeader stores the http status code
    58  func (rm *responseModifier) WriteHeader(s int) {
    59  	rm.statusCode = s
    60  }
    61  
    62  // Header returns the internal http header
    63  func (rm *responseModifier) Header() http.Header {
    64  	return rm.header
    65  }
    66  
    67  // Header returns the internal http header
    68  func (rm *responseModifier) StatusCode() int {
    69  	return rm.statusCode
    70  }
    71  
    72  // Override replace the body of the HTTP reply
    73  func (rm *responseModifier) OverrideBody(b []byte) {
    74  	rm.body = b
    75  }
    76  
    77  func (rm *responseModifier) OverrideStatusCode(statusCode int) {
    78  	rm.statusCode = statusCode
    79  }
    80  
    81  // Override replace the headers of the HTTP reply
    82  func (rm *responseModifier) OverrideHeader(b []byte) error {
    83  	header := http.Header{}
    84  	if err := json.Unmarshal(b, &header); err != nil {
    85  		return err
    86  	}
    87  	rm.header = header
    88  	return nil
    89  }
    90  
    91  // Write stores the byte array inside content
    92  func (rm *responseModifier) Write(b []byte) (int, error) {
    93  	rm.body = append(rm.body, b...)
    94  	return len(b), nil
    95  }
    96  
    97  // Body returns the response body
    98  func (rm *responseModifier) RawBody() []byte {
    99  	return rm.body
   100  }
   101  
   102  func (rm *responseModifier) RawHeaders() ([]byte, error) {
   103  	var b bytes.Buffer
   104  	if err := rm.header.Write(&b); err != nil {
   105  		return nil, err
   106  	}
   107  	return b.Bytes(), nil
   108  }
   109  
   110  // Hijack returns the internal connection of the wrapped http.ResponseWriter
   111  func (rm *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
   112  	hijacker, ok := rm.rw.(http.Hijacker)
   113  	if !ok {
   114  		return nil, nil, fmt.Errorf("Internal reponse writer doesn't support the Hijacker interface")
   115  	}
   116  	return hijacker.Hijack()
   117  }
   118  
   119  // Flush flushes all data to the HTTP response
   120  func (rm *responseModifier) Flush() error {
   121  	// Copy the status code
   122  	if rm.statusCode > 0 {
   123  		rm.rw.WriteHeader(rm.statusCode)
   124  	}
   125  
   126  	// Copy the header
   127  	for k, vv := range rm.header {
   128  		for _, v := range vv {
   129  			rm.rw.Header().Add(k, v)
   130  		}
   131  	}
   132  
   133  	// Write body
   134  	_, err := rm.rw.Write(rm.body)
   135  	return err
   136  }