@@ -8,6 +8,10 @@ import (
88 "net/http/httputil"
99)
1010
11+ // sensitiveLogHeaders are redacted before request and response content is
12+ // written to the debug logger.
13+ var sensitiveLogHeaders = []string {"authorization" , "api-key" , "x-api-key" , "cookie" , "set-cookie" }
14+
1115// WithDebugLog logs the HTTP request and response content.
1216// If the logger parameter is nil, it uses the default logger.
1317//
@@ -20,7 +24,7 @@ func WithDebugLog(logger *log.Logger) RequestOption {
2024 logger = log .Default ()
2125 }
2226
23- if reqBytes , err := httputil . DumpRequest (req , true ); err == nil {
27+ if reqBytes , err := dumpRedactedRequest (req ); err == nil {
2428 logger .Printf ("Request Content:\n %s\n " , reqBytes )
2529 }
2630
@@ -29,10 +33,48 @@ func WithDebugLog(logger *log.Logger) RequestOption {
2933 return resp , err
3034 }
3135
32- if respBytes , err := httputil . DumpResponse (resp , true ); err == nil {
36+ if respBytes , err := dumpRedactedResponse (resp ); err == nil {
3337 logger .Printf ("Response Content:\n %s\n " , respBytes )
3438 }
3539
3640 return resp , err
3741 })
3842}
43+
44+ // dumpRedactedRequest dumps req with sensitive headers replaced. The
45+ // original headers are restored via defer so a panic in DumpRequest cannot
46+ // leak the placeholder map into the live request sent downstream.
47+ func dumpRedactedRequest (req * http.Request ) ([]byte , error ) {
48+ origHeaders := req .Header
49+ req .Header = redactDebugHeaders (origHeaders )
50+ defer func () { req .Header = origHeaders }()
51+ return httputil .DumpRequest (req , true )
52+ }
53+
54+ func dumpRedactedResponse (resp * http.Response ) ([]byte , error ) {
55+ origHeaders := resp .Header
56+ resp .Header = redactDebugHeaders (origHeaders )
57+ defer func () { resp .Header = origHeaders }()
58+ return httputil .DumpResponse (resp , true )
59+ }
60+
61+ func redactDebugHeaders (headers http.Header ) http.Header {
62+ var redacted http.Header
63+ for _ , name := range sensitiveLogHeaders {
64+ values := headers .Values (name )
65+ if len (values ) == 0 {
66+ continue
67+ }
68+ if redacted == nil {
69+ redacted = headers .Clone ()
70+ }
71+ redacted .Del (name )
72+ for range values {
73+ redacted .Add (name , "***" )
74+ }
75+ }
76+ if redacted == nil {
77+ return headers
78+ }
79+ return redacted
80+ }
0 commit comments