@@ -102,14 +102,24 @@ def silence_request
102102 @silence_request
103103 end
104104
105+ # Filter sensitive HTTP headers (such as "Authorization: Bearer secret_token")
106+ #
107+ # Filtered HTTP header values will be sent to Better Stack as "[FILTERED]"
108+ #
109+ # @example
110+ # Logtail::Integrations::Rack::HTTPEvents.http_header_filters = ["Authorization"]
105111 def http_header_filters = ( value )
106- @http_header_filters = value
112+ @http_header_filters = value . map { | header_name | normalize_header_name ( header_name ) }
107113 end
108114
109115 # Accessor method for {#http_header_filters=}
110116 def http_header_filters
111117 @http_header_filters
112118 end
119+
120+ def normalize_header_name ( name )
121+ name . to_s . downcase . gsub ( "-" , "_" )
122+ end
113123 end
114124
115125 CONTENT_LENGTH_KEY = 'Content-Length' . freeze
@@ -138,12 +148,11 @@ def call(env)
138148
139149 http_response = HTTPResponse . new (
140150 content_length : content_length ,
141- headers : headers ,
151+ headers : filter_http_headers ( headers ) ,
142152 http_context : http_context ,
143153 request_id : request . request_id ,
144154 status : status ,
145155 duration_ms : duration_ms ,
146- headers_to_sanitize : self . class . http_header_filters ,
147156 )
148157
149158 {
@@ -169,15 +178,14 @@ def call(env)
169178 http_request = HTTPRequest . new (
170179 body : event_body ,
171180 content_length : safe_to_i ( request . content_length ) ,
172- headers : request . headers ,
181+ headers : filter_http_headers ( request . headers ) ,
173182 host : force_encoding ( request . host ) ,
174183 method : request . request_method ,
175184 path : request . path ,
176185 port : request . port ,
177186 query_string : force_encoding ( request . query_string ) ,
178187 request_id : request . request_id ,
179188 scheme : force_encoding ( request . scheme ) ,
180- headers_to_sanitize : self . class . http_header_filters ,
181189 )
182190
183191 {
@@ -212,11 +220,10 @@ def call(env)
212220 http_response = HTTPResponse . new (
213221 body : event_body ,
214222 content_length : content_length ,
215- headers : headers ,
223+ headers : filter_http_headers ( headers ) ,
216224 request_id : request . request_id ,
217225 status : status ,
218226 duration_ms : duration_ms ,
219- headers_to_sanitize : self . class . http_header_filters ,
220227 )
221228
222229 {
@@ -260,6 +267,13 @@ def silenced?(env, request)
260267 end
261268 end
262269
270+ def filter_http_headers ( headers )
271+ headers . each do |name , _ |
272+ normalized_header_name = self . class . normalize_header_name ( name )
273+ headers [ name ] = "[FILTERED]" if self . class . http_header_filters &.include? ( normalized_header_name )
274+ end
275+ end
276+
263277 def safe_to_i ( val )
264278 val . nil? ? nil : val . to_i
265279 end
0 commit comments