github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/plugin/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/plugin" 11 ) 12 13 //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . RequestLoggerOutput 14 15 // RequestLoggerOutput is the interface for displaying logs 16 type RequestLoggerOutput interface { 17 DisplayDump(dump string) error 18 DisplayHeader(name string, value string) error 19 DisplayHost(name string) error 20 DisplayJSONBody(body []byte) 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 30 // a plugin repository 31 type RequestLogger struct { 32 connection plugin.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 // Make records the request and the response to UI 44 func (logger *RequestLogger) Make(request *http.Request, passedResponse *plugin.Response, proxyReader plugin.ProxyReader) error { 45 err := logger.displayRequest(request) 46 if err != nil { 47 logger.output.HandleInternalError(err) 48 } 49 50 err = logger.connection.Make(request, passedResponse, proxyReader) 51 52 if passedResponse.HTTPResponse != nil { 53 displayErr := logger.displayResponse(passedResponse) 54 if displayErr != nil { 55 logger.output.HandleInternalError(displayErr) 56 } 57 } 58 59 return err 60 } 61 62 // Wrap sets the connection on the RequestLogger and returns itself 63 func (logger *RequestLogger) Wrap(innerconnection plugin.Connection) plugin.Connection { 64 logger.connection = innerconnection 65 return logger 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 && request.Header.Get("Content-Type") == "application/json" { 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 err = logger.output.DisplayJSONBody(rawRequestBody) 101 if err != nil { 102 return err 103 } 104 } 105 106 return nil 107 } 108 109 func (logger *RequestLogger) displayResponse(passedResponse *plugin.Response) error { 110 err := logger.output.Start() 111 if err != nil { 112 return err 113 } 114 defer logger.output.Stop() 115 116 err = logger.output.DisplayType("RESPONSE", time.Now()) 117 if err != nil { 118 return err 119 } 120 err = logger.output.DisplayResponseHeader(passedResponse.HTTPResponse.Proto, passedResponse.HTTPResponse.Status) 121 if err != nil { 122 return err 123 } 124 err = logger.displaySortedHeaders(passedResponse.HTTPResponse.Header) 125 if err != nil { 126 return err 127 } 128 129 if passedResponse.HTTPResponse.Body == nil { 130 return nil 131 } 132 if passedResponse.HTTPResponse.Header.Get("Content-Type") != "application/json" { 133 return logger.output.DisplayDump("[NON-JSON BODY CONTENT HIDDEN]") 134 } 135 136 return logger.output.DisplayJSONBody(passedResponse.RawResponse) 137 } 138 139 func (logger *RequestLogger) displaySortedHeaders(headers http.Header) error { 140 keys := []string{} 141 for key := range headers { 142 keys = append(keys, key) 143 } 144 sort.Strings(keys) 145 146 for _, key := range keys { 147 for _, value := range headers[key] { 148 err := logger.output.DisplayHeader(key, redactHeaders(key, value)) 149 if err != nil { 150 return err 151 } 152 } 153 } 154 return nil 155 } 156 157 func redactHeaders(key string, value string) string { 158 redactedKeys := []string{"Authorization", "Set-Cookie"} 159 for _, redactedKey := range redactedKeys { 160 if key == redactedKey { 161 return "[PRIVATE DATA HIDDEN]" 162 } 163 } 164 165 return value 166 }