github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/api/uaa/wrapper/request_logger.go (about)

     1  package wrapper
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"sort"
     8  	"time"
     9  
    10  	"code.cloudfoundry.org/cli/api/uaa"
    11  )
    12  
    13  //go:generate counterfeiter . RequestLoggerOutput
    14  
    15  // RequestLoggerOutput is the interface for displaying logs
    16  type RequestLoggerOutput interface {
    17  	DisplayBody(body []byte) error
    18  	DisplayJSONBody(body []byte) error
    19  	DisplayHeader(name string, value string) error
    20  	DisplayHost(name string) error
    21  	DisplayRequestHeader(method string, uri string, httpProtocol string) error
    22  	DisplayResponseHeader(httpProtocol string, status string) error
    23  	DisplayType(name string, requestDate time.Time) error
    24  	HandleInternalError(err error)
    25  	Start() error
    26  	Stop() error
    27  }
    28  
    29  // RequestLogger is the wrapper that logs requests to and responses from the
    30  // UAA server
    31  type RequestLogger struct {
    32  	connection uaa.Connection
    33  	output     RequestLoggerOutput
    34  }
    35  
    36  // NewRequestLogger returns a pointer to a RequestLogger wrapper
    37  func NewRequestLogger(output RequestLoggerOutput) *RequestLogger {
    38  	return &RequestLogger{
    39  		output: output,
    40  	}
    41  }
    42  
    43  // Wrap sets the connection on the RequestLogger and returns itself
    44  func (logger *RequestLogger) Wrap(innerconnection uaa.Connection) uaa.Connection {
    45  	logger.connection = innerconnection
    46  	return logger
    47  }
    48  
    49  // Make records the request and the response to UI
    50  func (logger *RequestLogger) Make(request *http.Request, passedResponse *uaa.Response) error {
    51  	err := logger.displayRequest(request)
    52  	if err != nil {
    53  		logger.output.HandleInternalError(err)
    54  	}
    55  
    56  	err = logger.connection.Make(request, passedResponse)
    57  
    58  	if passedResponse.HTTPResponse != nil {
    59  		displayErr := logger.displayResponse(passedResponse)
    60  		if displayErr != nil {
    61  			logger.output.HandleInternalError(displayErr)
    62  		}
    63  	}
    64  
    65  	return err
    66  }
    67  
    68  func (logger *RequestLogger) displayRequest(request *http.Request) error {
    69  	err := logger.output.Start()
    70  	if err != nil {
    71  		return err
    72  	}
    73  	defer logger.output.Stop()
    74  
    75  	err = logger.output.DisplayType("REQUEST", time.Now())
    76  	if err != nil {
    77  		return err
    78  	}
    79  	err = logger.output.DisplayRequestHeader(request.Method, request.URL.RequestURI(), request.Proto)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	err = logger.output.DisplayHost(request.URL.Host)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	err = logger.displaySortedHeaders(request.Header)
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	if request.Body != nil {
    93  		rawRequestBody, err := ioutil.ReadAll(request.Body)
    94  		defer request.Body.Close()
    95  		if err != nil {
    96  			return err
    97  		}
    98  
    99  		request.Body = ioutil.NopCloser(bytes.NewBuffer(rawRequestBody))
   100  		if request.Header.Get("Content-Type") == "application/json" {
   101  			err = logger.output.DisplayJSONBody(rawRequestBody)
   102  		} else {
   103  			err = logger.output.DisplayBody(rawRequestBody)
   104  		}
   105  		if err != nil {
   106  			return err
   107  		}
   108  	}
   109  
   110  	return nil
   111  }
   112  
   113  func (logger *RequestLogger) displayResponse(passedResponse *uaa.Response) error {
   114  	err := logger.output.Start()
   115  	if err != nil {
   116  		return err
   117  	}
   118  	defer logger.output.Stop()
   119  
   120  	err = logger.output.DisplayType("RESPONSE", time.Now())
   121  	if err != nil {
   122  		return err
   123  	}
   124  	err = logger.output.DisplayResponseHeader(passedResponse.HTTPResponse.Proto, passedResponse.HTTPResponse.Status)
   125  	if err != nil {
   126  		return err
   127  	}
   128  	err = logger.displaySortedHeaders(passedResponse.HTTPResponse.Header)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	return logger.output.DisplayJSONBody(passedResponse.RawResponse)
   133  }
   134  
   135  func (logger *RequestLogger) displaySortedHeaders(headers http.Header) error {
   136  	keys := []string{}
   137  	for key, _ := range headers {
   138  		keys = append(keys, key)
   139  	}
   140  	sort.Strings(keys)
   141  
   142  	for _, key := range keys {
   143  		for _, value := range headers[key] {
   144  			err := logger.output.DisplayHeader(key, redactHeaders(key, value))
   145  			if err != nil {
   146  				return err
   147  			}
   148  		}
   149  	}
   150  	return nil
   151  }
   152  
   153  func redactHeaders(key string, value string) string {
   154  	if key == "Authorization" {
   155  		return "[PRIVATE DATA HIDDEN]"
   156  	}
   157  	return value
   158  }