github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/uaa/wrapper/request_logger.go (about) 1 package wrapper 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "net/http" 7 "regexp" 8 "sort" 9 "time" 10 11 "code.cloudfoundry.org/cli/api/uaa" 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 DisplayBody(body []byte) error 19 DisplayJSONBody(body []byte) error 20 DisplayHeader(name string, value string) error 21 DisplayHost(name 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 // UAA server 32 type RequestLogger struct { 33 connection uaa.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 *http.Request, passedResponse *uaa.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 uaa.Connection) uaa.Connection { 65 logger.connection = innerconnection 66 return logger 67 } 68 69 func (logger *RequestLogger) displayRequest(request *http.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 if request.Body != nil { 94 rawRequestBody, err := ioutil.ReadAll(request.Body) 95 defer request.Body.Close() 96 if err != nil { 97 return err 98 } 99 100 request.Body = ioutil.NopCloser(bytes.NewBuffer(rawRequestBody)) 101 if request.Header.Get("Content-Type") == "application/json" { 102 err = logger.output.DisplayJSONBody(rawRequestBody) 103 } else { 104 err = logger.output.DisplayBody(rawRequestBody) 105 } 106 if err != nil { 107 return err 108 } 109 } 110 111 return nil 112 } 113 114 func (logger *RequestLogger) displayResponse(passedResponse *uaa.Response) error { 115 err := logger.output.Start() 116 if err != nil { 117 return err 118 } 119 defer logger.output.Stop() 120 121 err = logger.output.DisplayType("RESPONSE", time.Now()) 122 if err != nil { 123 return err 124 } 125 err = logger.output.DisplayResponseHeader(passedResponse.HTTPResponse.Proto, passedResponse.HTTPResponse.Status) 126 if err != nil { 127 return err 128 } 129 err = logger.displaySortedHeaders(passedResponse.HTTPResponse.Header) 130 if err != nil { 131 return err 132 } 133 return logger.output.DisplayJSONBody(passedResponse.RawResponse) 134 } 135 136 func (logger *RequestLogger) displaySortedHeaders(headers http.Header) error { 137 keys := []string{} 138 for key := range headers { 139 keys = append(keys, key) 140 } 141 sort.Strings(keys) 142 143 for _, key := range keys { 144 for _, value := range headers[key] { 145 err := logger.output.DisplayHeader(key, redactHeaders(key, value)) 146 if err != nil { 147 return err 148 } 149 } 150 } 151 return nil 152 } 153 154 func redactHeaders(key string, value string) string { 155 redactedValue := "[PRIVATE DATA HIDDEN]" 156 redactedKeys := []string{"Authorization", "Set-Cookie"} 157 for _, redactedKey := range redactedKeys { 158 if key == redactedKey { 159 return redactedValue 160 } 161 } 162 163 re := regexp.MustCompile(`([&?]code)=[A-Za-z0-9\-._~!$'()*+,;=:@/?]*`) 164 if key == "Location" { 165 value = re.ReplaceAllString(value, "$1="+redactedValue) 166 } 167 168 return value 169 }