http_logger 1.0.1 → 1.0.2

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
2
  SHA256:
3
- metadata.gz: 23dfe1231c8bedcaea4968b27d855c5832249e8977f70315738db6f45ca69d65
4
- data.tar.gz: 1e39712f106bde111c1fca4825ebb25ba03270e2255d9b47aadac7307a153954
3
+ metadata.gz: 8a29fc0bc0ae3d05a32edc02ec4e53eb8ac4ff97400d842704aba4f9ff865a98
4
+ data.tar.gz: bc303ae5878d4755a67814ef9f89970b2a03007421b419d0f834fbab40156960
5
5
  SHA512:
6
- metadata.gz: 7bded89851f6cc5f5b3207f11e1c765f05cf5ece32b42a2be45fcc1b3a6de2e6cea3de6cba53733611df23a2a8265edcf1b99ab95b8eb7c1741afafcb8a32528
7
- data.tar.gz: 7efb4e05af6a5ae4f7f13c0915c9df61b65cba27749786315fcdb7082c3f930b5549e63126c2827f15b9a42673d0f7dd001ae9808661c70e46ffcdcd1f9f0fa0
6
+ metadata.gz: 2761a8a1c86c6be1dfade5b9046a2bf5d8b111271b21d3cb6468e001db480619929ba46b9f9a2a2133958535a698c772bed031f38b3dbe46afbd69f036e880bc
7
+ data.tar.gz: 0ca796ddd939dfec32218caa017597cc62a368c4e03d1b34085611864471f0b250dccc77b7150d394c6a4aeb49426e020bdb86f995df2b6a5386eaa168a91607
@@ -1,3 +1,3 @@
1
1
  class HttpLogger
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
data/lib/http_logger.rb CHANGED
@@ -2,6 +2,7 @@ require 'net/http'
2
2
  require 'uri'
3
3
  require 'set'
4
4
  require 'http_logger/configuration'
5
+ require 'http_logger/version'
5
6
 
6
7
  # Usage:
7
8
  #
@@ -48,7 +49,7 @@ class HttpLogger
48
49
  ensure
49
50
  if require_logging?(http, request)
50
51
  log_request_url(http, request, start_time)
51
- log_request_body(request)
52
+ log_request_body(request, request_body)
52
53
  log_request_headers(request)
53
54
  if defined?(response) && response
54
55
  log_response_code(response)
@@ -64,10 +65,17 @@ class HttpLogger
64
65
  content_type = response['Content-Type']
65
66
  return false if content_type.nil?
66
67
 
67
- !content_type.start_with?('text/', 'application/json', 'application/xml', 'application/javascript', 'application/x-www-form-urlencoded', 'application/xhtml+xml', 'application/rss+xml', 'application/atom+xml', 'application/svg+xml', 'application/yaml')
68
+ !textual_content_type?(content_type)
68
69
 
69
70
  end
70
71
 
72
+ def binary_request?(request)
73
+ content_type = request['Content-Type']
74
+ return false if content_type.nil?
75
+
76
+ !textual_content_type?(content_type)
77
+ end
78
+
71
79
  def log_request_url(http, request, start_time)
72
80
  ofset = Time.now - start_time
73
81
  log("HTTP #{request.method} (%0.2fms)" % (ofset * 1000), request_url(http, request))
@@ -92,11 +100,12 @@ class HttpLogger
92
100
 
93
101
  HTTP_METHODS_WITH_BODY = Set.new(%w(POST PUT GET PATCH))
94
102
 
95
- def log_request_body(request)
103
+ def log_request_body(request, request_body = nil)
96
104
  if configuration.log_request_body
97
105
  if HTTP_METHODS_WITH_BODY.include?(request.method)
98
- if (body = request.body) && !body.empty?
99
- log("Request body", truncate_body(body))
106
+ body = request.body || request_body
107
+ if body && !body.empty?
108
+ log("Request body", format_request_body_for_log(request, body))
100
109
  end
101
110
  end
102
111
  end
@@ -197,9 +206,85 @@ class HttpLogger
197
206
  configuration.collapse_body_limit
198
207
  end
199
208
 
209
+ def textual_content_type?(content_type)
210
+ normalized = content_type.to_s.downcase
211
+ normalized.start_with?(
212
+ 'text/',
213
+ 'application/json',
214
+ 'application/xml',
215
+ 'application/javascript',
216
+ 'application/x-www-form-urlencoded',
217
+ 'application/xhtml+xml',
218
+ 'application/rss+xml',
219
+ 'application/atom+xml',
220
+ 'application/svg+xml',
221
+ 'application/yaml',
222
+ )
223
+ end
224
+
200
225
  def configuration
201
226
  self.class.configuration
202
227
  end
228
+
229
+ def format_request_body_for_log(request, body)
230
+ content_type = request['Content-Type']
231
+
232
+ if multipart_content_type?(content_type)
233
+ return truncate_body(sanitize_multipart_binary_parts(body, multipart_boundary(content_type)))
234
+ end
235
+
236
+ binary_request?(request) ? "<binary #{body.bytesize} bytes>" : truncate_body(body)
237
+ end
238
+
239
+ def multipart_content_type?(content_type)
240
+ content_type.to_s.downcase.start_with?('multipart/')
241
+ end
242
+
243
+ def multipart_boundary(content_type)
244
+ match = content_type.to_s.match(/boundary="?([^";]+)"?/i)
245
+ match && match[1]
246
+ end
247
+
248
+ def sanitize_multipart_binary_parts(body, boundary)
249
+ return body unless boundary
250
+
251
+ binary_body = body.dup.force_encoding(Encoding::BINARY)
252
+ delimiter = "--#{boundary}".b
253
+ segments = binary_body.split(delimiter, -1)
254
+ return body if segments.size < 2
255
+
256
+ segments.each_with_index.map do |segment, index|
257
+ if index == 0
258
+ segment
259
+ elsif segment.start_with?("--")
260
+ "#{delimiter}#{segment}"
261
+ else
262
+ "#{delimiter}#{sanitize_multipart_segment(segment)}"
263
+ end
264
+ end.join
265
+ end
266
+
267
+ def sanitize_multipart_segment(segment)
268
+ separator = if segment.include?("\r\n\r\n")
269
+ "\r\n\r\n"
270
+ elsif segment.include?("\n\n")
271
+ "\n\n"
272
+ end
273
+ return segment unless separator
274
+
275
+ headers, part_body = segment.split(separator, 2)
276
+ return segment unless part_body
277
+
278
+ content_type = headers.each_line.find { |line| line.downcase.start_with?('content-type:') }
279
+ return segment unless content_type
280
+
281
+ part_content_type = content_type.split(':', 2).last.to_s.strip
282
+ return segment if textual_content_type?(part_content_type)
283
+
284
+ trailing_newline = part_body.end_with?("\r\n") ? "\r\n" : (part_body.end_with?("\n") ? "\n" : "")
285
+ payload = trailing_newline.empty? ? part_body : part_body[0...-trailing_newline.bytesize]
286
+ "#{headers}#{separator}<binary #{payload.bytesize} bytes>#{trailing_newline}"
287
+ end
203
288
  end
204
289
 
205
290
  block = lambda do |a|
@@ -195,6 +195,48 @@ describe HttpLogger do
195
195
  it { should include("<binary 41887 bytes>") }
196
196
  end
197
197
 
198
+ context "when binary request" do
199
+ let(:url) { "http://example.com/upload" }
200
+ let(:request) do
201
+ http = Net::HTTP.new(uri.host, uri.port)
202
+ request = Net::HTTP::Post.new(uri.path)
203
+ request['Content-Type'] = 'image/jpeg'
204
+ request.body = "\xFF\xD8\xFF\xDBbinarypayload".b
205
+ http.request(request)
206
+ end
207
+
208
+ it { should include("Request body") }
209
+ it { should include("<binary 17 bytes>") }
210
+ it { should_not include("binarypayload") }
211
+ end
212
+
213
+ context "when multipart request has binary and text parts" do
214
+ let(:url) { "http://example.com/upload" }
215
+ let(:boundary) { "turing-export-80cd207c6b0b5f0c" }
216
+ let(:request) do
217
+ http = Net::HTTP.new(uri.host, uri.port)
218
+ request = Net::HTTP::Post.new(uri.path)
219
+ request['Content-Type'] = "multipart/related; boundary=#{boundary}"
220
+ request.body = <<~BODY.chomp
221
+ --#{boundary}
222
+ Content-Type: application/json; charset=UTF-8
223
+
224
+ {"name":"IMG_20190921_152700.jpg","parents":["1LxERY9t0fCAJXJBvBSIGAVhP4IpD0Iyv"]}
225
+ --#{boundary}
226
+ Content-Type: image/jpeg
227
+
228
+ \xFF\xD8\xFF\xDBJPEGDATA
229
+ --#{boundary}--
230
+ BODY
231
+ http.request(request)
232
+ end
233
+
234
+ it { should include(%({"name":"IMG_20190921_152700.jpg","parents":["1LxERY9t0fCAJXJBvBSIGAVhP4IpD0Iyv"]})) }
235
+ it { should include("Content-Type: image/jpeg") }
236
+ it { should include("<binary 12 bytes>") }
237
+ it { should_not include("JPEGDATA") }
238
+ end
239
+
198
240
  after(:each) do
199
241
  HttpLogger.configuration.reset
200
242
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bogdan Gusiev
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-02-22 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: bundler
@@ -66,6 +65,48 @@ dependencies:
66
65
  - - ">="
67
66
  - !ruby/object:Gem::Version
68
67
  version: '3.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: bigdecimal
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: base64
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: logger
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
69
110
  - !ruby/object:Gem::Dependency
70
111
  name: debug
71
112
  requirement: !ruby/object:Gem::Requirement
@@ -117,7 +158,6 @@ licenses:
117
158
  metadata:
118
159
  source_code_uri: https://github.com/railsware/http_logger
119
160
  changelog_uri: https://github.com/railsware/http_logger/CHANGELOG.md
120
- post_install_message:
121
161
  rdoc_options: []
122
162
  require_paths:
123
163
  - lib
@@ -132,8 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
172
  - !ruby/object:Gem::Version
133
173
  version: '0'
134
174
  requirements: []
135
- rubygems_version: 3.5.14
136
- signing_key:
175
+ rubygems_version: 3.6.9
137
176
  specification_version: 4
138
177
  summary: Log your http api calls just like SQL queries
139
178
  test_files: []