github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/router/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/router" 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 router.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 *router.Request, passedResponse *router.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 router.Connection) router.Connection { 65 logger.connection = innerconnection 66 return logger 67 } 68 69 func (logger *RequestLogger) displayRequest(request *router.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 *router.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 return logger.output.DisplayJSONBody(passedResponse.RawResponse) 141 } 142 143 func (logger *RequestLogger) displaySortedHeaders(headers http.Header) error { 144 keys := []string{} 145 for key := range headers { 146 keys = append(keys, key) 147 } 148 sort.Strings(keys) 149 150 for _, key := range keys { 151 for _, value := range headers[key] { 152 err := logger.output.DisplayHeader(key, redactHeaders(key, value)) 153 if err != nil { 154 return err 155 } 156 } 157 } 158 return nil 159 } 160 161 func redactHeaders(key string, value string) string { 162 redactedKeys := []string{"Authorization", "Set-Cookie"} 163 for _, redactedKey := range redactedKeys { 164 if key == redactedKey { 165 return "[PRIVATE DATA HIDDEN]" 166 } 167 } 168 169 return value 170 }