httplog 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9395e3bb51404b12d1d3504e928ae722793de10c
4
- data.tar.gz: a365c1134ff32ec56eb14f0fd26ac9b971269e1e
2
+ SHA256:
3
+ metadata.gz: bd063a60dafd4b6bcc29fa80d877f8bd650375f4633fb0f0bc4398075677b583
4
+ data.tar.gz: 136a0fe30f033ad30f8867e327e18109255735b371cc9ab5a7d8e973d3b6e201
5
5
  SHA512:
6
- metadata.gz: e2a020f5b5e3d7796cf37194e7e77942ffe4f39e6d2ec2319d5c25e1d18ee62780240397df4e71407a5bfd45d04835fce02cfefb3731a19bcad10bcf5965196e
7
- data.tar.gz: 9c5dda03458471e2fa64b1853c2b0ddd08820802268dc4c4681de322b008912f2e79a100525135f2b2282939ef157bc4618ac21b178589d8987316747640e460
6
+ metadata.gz: d4de29f881f37f1149400324e8c97de77dd7d7ef21e983dd513e411ae4c5b3d67d886807accdfddccbcc388d03e242e4597457d42783525e8ddcf8dbf9064799
7
+ data.tar.gz: 46df8a4e8dff1054f60b8545db22df35159c20ee0ab405d78795d476cc990efffd7d8cfe635f7641667d78cbac38fc0d5709ae8e802d040989356a883d3a4cd8
@@ -1 +1 @@
1
- 2.4.2
1
+ 2.6.2
@@ -1,13 +1,12 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "2.3.8"
4
3
  - "2.4.5"
5
4
  - "2.5.3"
6
- - "2.6.0"
5
+ - "2.6.2"
7
6
  gemfile:
8
- - gemfiles/http2.gemfile
9
7
  - gemfiles/http3.gemfile
10
8
  - gemfiles/http4.gemfile
9
+ - gemfiles/http5.gemfile
11
10
  - gemfiles/rack1.gemfile
12
11
  - gemfiles/rack2.gemfile
13
12
 
@@ -1,3 +1,13 @@
1
+ ## 1.3.0 - 2019-05-18
2
+
3
+ * [#74](https://github.com/trusche/httplog/pull/74) Added ability to filter sensitive parameter values in the request (based on [#73](https://github.com/trusche/httplog/pull/73)). Default masking of `password` parameter
4
+ * Removed explicit support and tests for ruby 2.3 and http gem v2
5
+ * [#71](https://github.com/trusche/httplog/pull/71) Rounding benchmark in compact mode
6
+
7
+ ## 1.2.2 - 2019-03-15
8
+
9
+ * [#70](https://github.com/trusche/httplog/pull/70) Fixed a bug where blacklisting caused requests to not be sent with HTTP adapter
10
+
1
11
  ## 1.2.1 - 2019-01-28
2
12
 
3
13
  * [#67](https://github.com/trusche/httplog/pull/67) Gracefully handling empty response headers in Ethon
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- httplog (1.2.2)
4
+ httplog (1.3.0)
5
5
  rack (>= 1.0)
6
6
  rainbow (>= 2.0.0)
7
7
 
@@ -127,4 +127,4 @@ DEPENDENCIES
127
127
  thin (~> 1.7)
128
128
 
129
129
  BUNDLED WITH
130
- 1.17.1
130
+ 1.17.2
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Log outgoing HTTP requests made from your application. Helps with debugging pesky API error responses, or just generally understanding what's going on under the hood.
7
7
 
8
- Requires ruby >= 2.3.
8
+ Requires ruby >= 2.4.
9
9
 
10
10
  This gem works with the following ruby modules and libraries:
11
11
 
@@ -81,6 +81,9 @@ HttpLog.configure do |config|
81
81
  # Limit logging based on URL patterns
82
82
  config.url_whitelist_pattern = nil
83
83
  config.url_blacklist_pattern = nil
84
+
85
+ # Mask the values of sensitive requestparameters
86
+ config.filter_parameters = %w[password]
84
87
  end
85
88
  ```
86
89
 
@@ -121,15 +124,40 @@ If the log is too noisy for you, but you don't want to completely disable it eit
121
124
 
122
125
  If you want to log HTTP requests in a JSON format, set the `json_log` option to `true`. You can combine this with `compact_log` to only log the basic request metrics without headers and bodies.
123
126
 
127
+ ### Parameter filtering
128
+
129
+ Just like in Rails, you can filter the values of sensitive parameters by setting the `filter_parameters` to an array of (lower case) keys. The value for "password" is filtered by default.
130
+
131
+ **Please note** that this will **only filter the request data** with well-formed parameters (in the URL, the headers, and the request data) but **not the response**. It does not currently filter JSON request data either, just standard "key=value" pairs in the request body.
132
+
124
133
  ### Example
125
134
 
126
135
  With the default configuration, the log output might look like this:
127
136
 
128
- D, [2012-11-21T15:09:03.532970 #6857] DEBUG -- : [httplog] Connecting: localhost:80
129
- D, [2012-11-21T15:09:03.533877 #6857] DEBUG -- : [httplog] Sending: GET http://localhost:9292/index.html
130
- D, [2012-11-21T15:09:03.534499 #6857] DEBUG -- : [httplog] Status: 200
131
- D, [2012-11-21T15:09:03.534544 #6857] DEBUG -- : [httplog] Benchmark: 0.00057 seconds
132
- D, [2012-11-21T15:09:03.534578 #6857] DEBUG -- : [httplog] Response:
137
+ [httplog] Connecting: localhost:80
138
+ [httplog] Sending: GET http://localhost:9292/index.html
139
+ [httplog] Status: 200
140
+ [httplog] Benchmark: 0.00057 seconds
141
+ [httplog] Response:
142
+ <html>
143
+ <head>
144
+ <title>Test Page</title>
145
+ </head>
146
+ <body>
147
+ <h1>This is the test page.</h1>
148
+ </body>
149
+ </html>
150
+
151
+ With `log_headers = true` and a parameter 'password' in the request query and headers:
152
+
153
+
154
+ [httplog] Connecting: localhost:80
155
+ [httplog] Sending: GET http://localhost:9292/index.html?password=[FILTERED]
156
+ [httplog] Header: accept: *.*
157
+ [httplog] Header: password=[FILTERED]
158
+ [httplog] Status: 200
159
+ [httplog] Benchmark: 0.00057 seconds
160
+ [httplog] Response:
133
161
  <html>
134
162
  <head>
135
163
  <title>Test Page</title>
@@ -163,21 +191,21 @@ a suggestion for a fix, please open an issue or, even better, submit a pull requ
163
191
  * When using OpenURI, the reading of the HTTP response body is deferred,
164
192
  so it is not available for logging. This will be noted in the logging statement:
165
193
 
166
- D, [2012-11-21T15:09:03.547005 #6857] DEBUG -- : [httplog] Connecting: localhost:80
167
- D, [2012-11-21T15:09:03.547938 #6857] DEBUG -- : [httplog] Sending: GET http://localhost:9292/index.html
168
- D, [2012-11-21T15:09:03.548615 #6857] DEBUG -- : [httplog] Status: 200
169
- D, [2012-11-21T15:09:03.548662 #6857] DEBUG -- : [httplog] Benchmark: 0.000617 seconds
170
- D, [2012-11-21T15:09:03.548695 #6857] DEBUG -- : [httplog] Response: (not available yet)
194
+ [httplog] Connecting: localhost:80
195
+ [httplog] Sending: GET http://localhost:9292/index.html
196
+ [httplog] Status: 200
197
+ [httplog] Benchmark: 0.000617 seconds
198
+ [httplog] Response: (not available yet)
171
199
 
172
200
  * When using HTTPClient, the TCP connection establishment will be logged
173
201
  *after* the HTTP request and headers, due to the way HTTPClient is organized.
174
202
 
175
- D, [2012-11-22T18:39:46.031698 #12800] DEBUG -- : [httplog] Sending: GET http://localhost:9292/index.html
176
- D, [2012-11-22T18:39:46.031756 #12800] DEBUG -- : [httplog] Header: accept: */*
177
- D, [2012-11-22T18:39:46.031788 #12800] DEBUG -- : [httplog] Header: foo: bar
178
- D, [2012-11-22T18:39:46.031942 #12800] DEBUG -- : [httplog] Connecting: localhost:9292
179
- D, [2012-11-22T18:39:46.033409 #12800] DEBUG -- : [httplog] Status: 200
180
- D, [2012-11-22T18:39:46.033483 #12800] DEBUG -- : [httplog] Benchmark: 0.001562 seconds
203
+ [httplog] Sending: GET http://localhost:9292/index.html
204
+ [httplog] Header: accept: */*
205
+ [httplog] Header: foo: bar
206
+ [httplog] Connecting: localhost:9292
207
+ [httplog] Status: 200
208
+ [httplog] Benchmark: 0.001562 seconds
181
209
 
182
210
  * Also when using HTTPClient, make sure you include `httplog` **after** `httpclient` in your `Gemfile`.
183
211
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'http', github: 'httprb/http'
5
+ gem 'http', '~> 4.0'
6
6
 
7
7
  gemspec path: '..'
@@ -2,6 +2,6 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'http', '~> 2.0'
5
+ gem 'http', '~> 5.0.0.pre'
6
6
 
7
7
  gemspec path: '..'
@@ -4,7 +4,7 @@ if defined?(Excon)
4
4
  module Excon
5
5
  module HttpLogHelper
6
6
  def httplog_url(datum)
7
- @httplog_url ||= "#{datum[:scheme]}://#{datum[:host]}:#{datum[:port]}#{datum[:path]}#{datum[:query]}"
7
+ @httplog_url ||= ["#{datum[:scheme]}://#{datum[:host]}:#{datum[:port]}#{datum[:path]}", datum[:query]].compact.join('?')
8
8
  end
9
9
  end
10
10
 
@@ -20,7 +20,8 @@ module HttpLog
20
20
  :color,
21
21
  :prefix_data_lines,
22
22
  :prefix_response_lines,
23
- :prefix_line_numbers
23
+ :prefix_line_numbers,
24
+ :filter_parameters
24
25
 
25
26
  def initialize
26
27
  @enabled = true
@@ -42,12 +43,7 @@ module HttpLog
42
43
  @prefix_data_lines = false
43
44
  @prefix_response_lines = false
44
45
  @prefix_line_numbers = false
45
- end
46
-
47
- # TODO: remove in 1.0.0
48
- def []=(key, value)
49
- warn 'DEPRECATION WARNING: Assignment to HttpLog.options will be removed in version 1.0.0. Please use HttpLog.configure block instead as described here: https://github.com/trusche/httplog#configuration'
50
- send("#{key}=", value)
46
+ @filter_parameters = []
51
47
  end
52
48
  end
53
49
  end
@@ -8,6 +8,8 @@ require 'rack'
8
8
 
9
9
  module HttpLog
10
10
  LOG_PREFIX = '[httplog] '.freeze
11
+ PARAM_MASK = '[FILTERED]'
12
+
11
13
  class BodyParsingError < StandardError; end
12
14
 
13
15
  class << self
@@ -17,7 +19,6 @@ module HttpLog
17
19
  @configuration ||= Configuration.new
18
20
  end
19
21
  alias config configuration
20
- alias options configuration # TODO: remove with 1.0.0
21
22
 
22
23
  def reset!
23
24
  @configuration = nil
@@ -64,13 +65,13 @@ module HttpLog
64
65
  def log_request(method, uri)
65
66
  return unless config.log_request
66
67
 
67
- log("Sending: #{method.to_s.upcase} #{uri}")
68
+ log("Sending: #{method.to_s.upcase} #{masked(uri)}")
68
69
  end
69
70
 
70
71
  def log_headers(headers = {})
71
72
  return unless config.log_headers
72
73
 
73
- headers.each do |key, value|
74
+ masked(headers).each do |key, value|
74
75
  log("Header: #{key}: #{value}")
75
76
  end
76
77
  end
@@ -129,7 +130,8 @@ module HttpLog
129
130
 
130
131
  def log_data(data)
131
132
  return unless config.log_data
132
- data = utf_encoded(data.to_s.dup)
133
+
134
+ data = utf_encoded(masked(data.dup).to_s) unless data.nil?
133
135
 
134
136
  if config.prefix_data_lines
135
137
  log('Data:')
@@ -142,7 +144,7 @@ module HttpLog
142
144
  def log_compact(method, uri, status, seconds)
143
145
  return unless config.compact_log
144
146
  status = Rack::Utils.status_code(status) unless status == /\d{3}/
145
- log("#{method.to_s.upcase} #{uri} completed with status code #{status} in #{seconds} seconds")
147
+ log("#{method.to_s.upcase} #{masked(uri)} completed with status code #{status} in #{seconds.to_f.round(6)} seconds")
146
148
  end
147
149
 
148
150
  def log_json(data = {})
@@ -159,16 +161,16 @@ module HttpLog
159
161
  if config.compact_log
160
162
  log({
161
163
  method: data[:method].to_s.upcase,
162
- url: data[:url],
164
+ url: masked(data[:url]),
163
165
  response_code: data[:response_code].to_i,
164
166
  benchmark: data[:benchmark]
165
167
  }.to_json)
166
168
  else
167
169
  log({
168
170
  method: data[:method].to_s.upcase,
169
- url: data[:url],
170
- request_body: data[:request_body],
171
- request_headers: data[:request_headers].to_h,
171
+ url: masked(data[:url]),
172
+ request_body: masked(data[:request_body]),
173
+ request_headers: masked(data[:request_headers].to_h),
172
174
  response_code: data[:response_code].to_i,
173
175
  response_body: parsed_body,
174
176
  response_headers: data[:response_headers].to_h,
@@ -197,6 +199,48 @@ module HttpLog
197
199
 
198
200
  private
199
201
 
202
+ def masked(msg, key=nil)
203
+ return msg if config.filter_parameters.empty?
204
+ return msg if msg.nil?
205
+
206
+ # If a key is given, msg is just the value and can be replaced
207
+ # in its entirety.
208
+ return (config.filter_parameters.include?(key.downcase) ? PARAM_MASK : msg) if key
209
+
210
+ # Otherwise, we'll parse Strings for key=valye pairs...
211
+ case msg
212
+ when *string_classes
213
+ config.filter_parameters.reduce(msg) do |m,key|
214
+ m.to_s.gsub(/(#{key})=[^&]+/i, "#{key}=#{PARAM_MASK}")
215
+ end
216
+ # ...and recurse over hashes
217
+ when *hash_classes
218
+ Hash[msg.map {|k,v| [k, masked(v, k)]}]
219
+ else
220
+ log "*** FILTERING NOT APPLIED BECAUSE #{msg.class} IS UNEXPECTED ***"
221
+ msg
222
+ end
223
+ end
224
+
225
+ def string_classes
226
+ @string_classes ||= begin
227
+ string_classes = [String]
228
+ string_classes << HTTP::Response::Body if defined?(HTTP::Response::Body)
229
+ string_classes << HTTP::URI if defined?(HTTP::URI)
230
+ string_classes << URI::HTTP if defined?(URI::HTTP)
231
+ string_classes << HTTP::FormData::Urlencoded if defined?(HTTP::FormData::Urlencoded)
232
+ string_classes
233
+ end
234
+ end
235
+
236
+ def hash_classes
237
+ @hash_classes ||= begin
238
+ hash_classes = [Hash, Enumerator]
239
+ hash_classes << HTTP::Headers if defined?(HTTP::Headers)
240
+ hash_classes
241
+ end
242
+ end
243
+
200
244
  def utf_encoded(data, content_type = nil)
201
245
  charset = content_type.to_s.scan(/; charset=(\S+)/).flatten.first || 'UTF-8'
202
246
  begin
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HttpLog
4
- VERSION = '1.2.2'.freeze
4
+ VERSION = '1.3.0'.freeze
5
5
  end
@@ -4,7 +4,7 @@ require 'ethon'
4
4
  class EthonAdapter < HTTPBaseAdapter
5
5
  def send_get_request
6
6
  easy = Ethon::Easy.new
7
- easy.http_request(parse_uri.to_s, :get, headers: @headers)
7
+ easy.http_request(parse_uri(true).to_s, :get, headers: @headers)
8
8
  easy.perform
9
9
  end
10
10
 
@@ -3,7 +3,7 @@
3
3
  require 'excon'
4
4
  class ExconAdapter < HTTPBaseAdapter
5
5
  def send_get_request
6
- Excon.get(parse_uri.to_s, headers: @headers)
6
+ Excon.get(parse_uri(true).to_s, headers: @headers)
7
7
  end
8
8
 
9
9
  def send_head_request
@@ -4,7 +4,7 @@ require 'faraday'
4
4
  class FaradayAdapter < HTTPBaseAdapter
5
5
  def send_get_request
6
6
  connection.get do |req|
7
- req.url parse_uri.to_s
7
+ req.url parse_uri(true).to_s
8
8
  req.headers = @headers
9
9
  end
10
10
  end
@@ -42,6 +42,10 @@ class FaradayAdapter < HTTPBaseAdapter
42
42
  end
43
43
  end
44
44
 
45
+ def logs_form_data?
46
+ false
47
+ end
48
+
45
49
  private
46
50
 
47
51
  def connection
@@ -3,7 +3,7 @@
3
3
  require 'http'
4
4
  class HTTPAdapter < HTTPBaseAdapter
5
5
  def send_get_request
6
- client.get(parse_uri.to_s)
6
+ client.get(parse_uri(true).to_s)
7
7
  end
8
8
 
9
9
  def send_head_request
@@ -15,8 +15,14 @@ class HTTPBaseAdapter
15
15
  true
16
16
  end
17
17
 
18
- def parse_uri
19
- URI.parse("#{@protocol}://#{@host}:#{@port}#{@path}")
18
+ def logs_form_data?
19
+ true
20
+ end
21
+
22
+ def parse_uri(query=false)
23
+ uri = "#{@protocol}://#{@host}:#{@port}#{@path}"
24
+ uri = [uri, URI::encode(@data)].join('?') if query && @data
25
+ URI.parse(uri)
20
26
  end
21
27
 
22
28
  def expected_response_body
@@ -3,7 +3,7 @@
3
3
  require 'httparty'
4
4
  class HTTPartyAdapter < HTTPBaseAdapter
5
5
  def send_get_request
6
- HTTParty.get(parse_uri.to_s, headers: @headers)
6
+ HTTParty.get(parse_uri(true).to_s, headers: @headers)
7
7
  end
8
8
 
9
9
  def send_head_request
@@ -2,7 +2,7 @@
2
2
 
3
3
  class HTTPClientAdapter < HTTPBaseAdapter
4
4
  def send_get_request
5
- ::HTTPClient.get(parse_uri, header: @headers)
5
+ ::HTTPClient.get(parse_uri(true), header: @headers)
6
6
  end
7
7
 
8
8
  def send_head_request
@@ -24,4 +24,8 @@ class HTTPClientAdapter < HTTPBaseAdapter
24
24
  def self.response_should_be
25
25
  HTTP::Message
26
26
  end
27
+
28
+ def logs_form_data?
29
+ false
30
+ end
27
31
  end
@@ -2,7 +2,9 @@
2
2
 
3
3
  class NetHTTPAdapter < HTTPBaseAdapter
4
4
  def send_get_request
5
- Net::HTTP.get_response(@host, [@path, @data].compact.join('?'), @port)
5
+ path = @path
6
+ path = [@path, URI::encode(@data)].join('?') if @data
7
+ Net::HTTP.get_response(@host, path, @port)
6
8
  end
7
9
 
8
10
  def send_head_request
@@ -2,7 +2,7 @@
2
2
 
3
3
  class OpenUriAdapter < HTTPBaseAdapter
4
4
  def send_get_request
5
- open(parse_uri) # rubocop:disable Security/Open
5
+ open(parse_uri(true)) # rubocop:disable Security/Open
6
6
  end
7
7
 
8
8
  def expected_response_body
@@ -4,7 +4,7 @@ require 'patron'
4
4
  class PatronAdapter < HTTPBaseAdapter
5
5
  def send_get_request
6
6
  session = Patron::Session.new
7
- session.get(parse_uri.to_s, @headers)
7
+ session.get(parse_uri(true).to_s, @headers)
8
8
  end
9
9
 
10
10
  def send_head_request
@@ -3,7 +3,7 @@
3
3
  require 'excon'
4
4
  class TyphoeusAdapter < HTTPBaseAdapter
5
5
  def send_get_request
6
- Typhoeus.get(parse_uri.to_s, headers: @headers)
6
+ Typhoeus.get(parse_uri(true).to_s, headers: @headers)
7
7
  end
8
8
 
9
9
  def send_head_request
@@ -5,16 +5,17 @@ require 'spec_helper'
5
5
  describe HttpLog do
6
6
  subject { log } # see spec_helper
7
7
 
8
+ let(:secret) { 'my secret' }
8
9
  let(:host) { 'localhost' }
9
10
  let(:port) { 9292 }
10
11
  let(:path) { '/index.html' }
11
- let(:headers) { { 'accept' => '*/*', 'foo' => 'bar' } }
12
- let(:data) { 'foo=bar&bar=foo' }
13
- let(:params) { { 'foo' => 'bar:form-data', 'bar' => 'foo' } }
12
+ let(:headers) { { 'accept' => '*/*', 'foo' => secret } }
13
+ let(:data) { "foo=#{secret}&bar=foo" }
14
+ let(:params) { { 'foo' => secret, 'bar' => 'foo:form-data' } }
14
15
  let(:html) { File.read('./spec/support/index.html') }
15
16
  let(:json) { JSON.parse(log.match(/\[httplog\]\s(.*)/).captures.first) }
16
17
 
17
- # Configuration
18
+ # Default configuration
18
19
  let(:enabled) { HttpLog.configuration.enabled }
19
20
  let(:severity) { HttpLog.configuration.severity }
20
21
  let(:log_headers) { HttpLog.configuration.log_headers }
@@ -31,6 +32,7 @@ describe HttpLog do
31
32
  let(:compact_log) { HttpLog.configuration.compact_log }
32
33
  let(:url_blacklist_pattern) { HttpLog.configuration.url_blacklist_pattern }
33
34
  let(:url_whitelist_pattern) { HttpLog.configuration.url_whitelist_pattern }
35
+ let(:filter_parameters) { HttpLog.configuration.filter_parameters }
34
36
 
35
37
  def configure
36
38
  HttpLog.configure do |c|
@@ -50,6 +52,7 @@ describe HttpLog do
50
52
  c.compact_log = compact_log
51
53
  c.url_blacklist_pattern = url_blacklist_pattern
52
54
  c.url_whitelist_pattern = url_whitelist_pattern
55
+ c.filter_parameters = filter_parameters
53
56
  end
54
57
  end
55
58
 
@@ -135,7 +138,7 @@ describe HttpLog do
135
138
 
136
139
  it_behaves_like 'logs request', 'POST'
137
140
  it_behaves_like 'logs expected response'
138
- it_behaves_like 'logs data', 'foo=bar&bar=foo'
141
+ it_behaves_like 'logs data'
139
142
  it_behaves_like 'logs status', 200
140
143
  it_behaves_like 'logs benchmark'
141
144
 
@@ -174,6 +177,7 @@ describe HttpLog do
174
177
  let(:log_headers) { true }
175
178
  it { is_expected.to match(%r{Header: accept: */*}i) } # request
176
179
  it { is_expected.to match(/Header: Server: thin/i) } # response
180
+ it_behaves_like 'filtered parameters'
177
181
  end
178
182
 
179
183
  context 'with blacklist hit' do
@@ -206,6 +210,7 @@ describe HttpLog do
206
210
  it_behaves_like 'data logging disabled'
207
211
  it_behaves_like 'response logging disabled'
208
212
  it_behaves_like 'benchmark logging disabled'
213
+ it_behaves_like 'filtered parameters'
209
214
 
210
215
  context 'with single color' do
211
216
  let(:color) { :red }
@@ -231,7 +236,7 @@ describe HttpLog do
231
236
 
232
237
  context 'with compact config' do
233
238
  let(:compact_log) { true }
234
- it { is_expected.to match(%r{\[httplog\] GET http://#{host}:#{port}#{path}(\?.*)? completed with status code \d{3} in (\d|\.)+}) }
239
+ it { is_expected.to match(%r{\[httplog\] GET http://#{host}:#{port}#{path}(\?.*)? completed with status code \d{3} in \d+\.\d{1,6} }) }
235
240
  it { is_expected.to_not include("Connecting: #{host}:#{port}") }
236
241
  it { is_expected.to_not include('Response:') }
237
242
  it { is_expected.to_not include('Data:') }
@@ -248,6 +253,7 @@ describe HttpLog do
248
253
  it_behaves_like 'benchmark logging disabled'
249
254
  it_behaves_like 'with prefix response lines'
250
255
  it_behaves_like 'with line numbers'
256
+ it_behaves_like 'filtered parameters'
251
257
  end
252
258
  end
253
259
 
@@ -260,12 +266,13 @@ describe HttpLog do
260
266
  it_behaves_like 'benchmark logging disabled'
261
267
  it_behaves_like 'with prefix response lines'
262
268
  it_behaves_like 'with line numbers'
269
+ it_behaves_like 'filtered parameters'
263
270
  end
264
271
  end
265
272
 
266
273
  context 'POST multi-part requests (file upload)' do
267
274
  let(:upload) { Tempfile.new('http-log') }
268
- let(:params) { { 'foo' => 'bar', 'file' => upload } }
275
+ let(:params) { { 'foo' => secret, 'file' => upload } }
269
276
 
270
277
  if adapter_class.method_defined? :send_multipart_post_request
271
278
  before { adapter.send_multipart_post_request }
@@ -275,6 +282,7 @@ describe HttpLog do
275
282
  it_behaves_like 'benchmark logging disabled'
276
283
  it_behaves_like 'with prefix response lines'
277
284
  it_behaves_like 'with line numbers'
285
+ it_behaves_like 'filtered parameters'
278
286
  end
279
287
  end
280
288
  end
@@ -292,6 +300,7 @@ describe HttpLog do
292
300
  it { expect(json['response_code']).to eq(200) }
293
301
  it { expect(json['response_body']).to eq(html) }
294
302
  it { expect(json['benchmark']).to be_a(Numeric) }
303
+ it_behaves_like 'filtered parameters'
295
304
 
296
305
  context 'and compact config' do
297
306
  let(:compact_log) { true }
@@ -12,8 +12,15 @@ RSpec.shared_examples 'logs expected response' do
12
12
  it { is_expected.to include("Response:#{adapter.expected_response_body}") }
13
13
  end
14
14
 
15
- RSpec.shared_examples 'logs data' do |data|
16
- it { is_expected.to include(["Data:", data].compact.join(' ')) }
15
+ RSpec.shared_examples 'logs data' do
16
+ # Some adapters (YOU, Faraday!) re-order the keys for no bloody
17
+ # reason whatsover. So we need to check them individually. And some
18
+ # (guess who?) use non-standard URL encoding for spaces...
19
+ it do
20
+ data.split('&').each do |param|
21
+ is_expected.to match(Regexp.new(param.gsub(' ', '( |%20|\\\+)')))
22
+ end
23
+ end
17
24
  end
18
25
 
19
26
  RSpec.shared_examples 'logs status' do |status|
@@ -61,3 +68,12 @@ RSpec.shared_examples 'with connection logging disabled' do
61
68
  let(:log_connect) { false }
62
69
  it { is_expected.to_not include('Connecting:') }
63
70
  end
71
+
72
+ RSpec.shared_examples 'filtered parameters' do
73
+ let(:filter_parameters) { %w(foo) }
74
+
75
+ it 'masks the filtered value' do
76
+ # is_expected.to include('foo=[FILTERED]&').or exclude('foo')
77
+ is_expected.to_not include('secret')
78
+ end
79
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httplog
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thilo Rusche
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-15 00:00:00.000000000 Z
11
+ date: 2019-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ethon
@@ -241,9 +241,9 @@ files:
241
241
  - MIT-LICENSE
242
242
  - README.md
243
243
  - Rakefile
244
- - gemfiles/http2.gemfile
245
244
  - gemfiles/http3.gemfile
246
245
  - gemfiles/http4.gemfile
246
+ - gemfiles/http5.gemfile
247
247
  - gemfiles/rack1.gemfile
248
248
  - gemfiles/rack2.gemfile
249
249
  - httplog.gemspec
@@ -302,8 +302,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
302
302
  - !ruby/object:Gem::Version
303
303
  version: '0'
304
304
  requirements: []
305
- rubyforge_project:
306
- rubygems_version: 2.6.13
305
+ rubygems_version: 3.0.3
307
306
  signing_key:
308
307
  specification_version: 4
309
308
  summary: Log outgoing HTTP requests.