github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/cloudcontroller/wrapper/request_logger.go (about)

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