Skip to content

Commit

Permalink
taking content type and character set into account; instead of incorr…
Browse files Browse the repository at this point in the history
…ectly using content-encoding
  • Loading branch information
trusche committed Jan 15, 2016
1 parent 297d119 commit 64fb419
Show file tree
Hide file tree
Showing 14 changed files with 80 additions and 25 deletions.
5 changes: 3 additions & 2 deletions lib/httplog/adapters/ethon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ def perform

# Not sure where the acutal status code is stored - so let's
# extract it from the response header.
status = response_headers.scan(/HTTP\/... (\d{3})/).flatten.first
status = response_headers.scan(/HTTP\/... (\d{3})/).flatten.first
encoding = response_headers.scan(/Content-Encoding: (\S+)/).flatten.first
content_type = response_headers.scan(/Content-Type: (\S+(; charset=\S+)?)/).flatten.first
HttpLog.log_compact(@action_name, @url, @return_code, bm)
HttpLog.log_status(status)
HttpLog.log_benchmark(bm)
HttpLog.log_body(response_body, encoding)
HttpLog.log_body(response_body, encoding, content_type)
return_code
end
end
Expand Down
5 changes: 3 additions & 2 deletions lib/httplog/adapters/excon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ def response(datum={})
datum = orig_response(datum)
end
response = datum[:response]
encoding = response[:headers] && response[:headers]['Content-Encoding']
headers = response[:headers] || {}
content_type =
HttpLog.log_status(response[:status])
HttpLog.log_body(response[:body], encoding)
HttpLog.log_body(response[:body], headers['Content-Encoding'], headers['Content-Type'])
datum
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/httplog/adapters/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ def make_request(req, options)
end

if log_enabled
headers = @response.headers
HttpLog.log_compact(req.verb, req.uri, @response.code, bm)
HttpLog.log_status(@response.code)
HttpLog.log_benchmark(bm)
HttpLog.log_headers(@response.headers.to_h)
HttpLog.log_body(@response.body, @response.headers["Content-Encoding"])
HttpLog.log_body(@response.body, headers['Content-Encoding'], headers['Content-Type'])
end

@response
Expand Down
3 changes: 2 additions & 1 deletion lib/httplog/adapters/httpclient.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ def do_get_block(req, proxy, conn, &block)

if log_enabled
res = conn.pop
headers = res.headers
HttpLog.log_compact(req.header.request_method, req.header.request_uri, res.status_code, bm)
HttpLog.log_status(res.status_code)
HttpLog.log_benchmark(bm)
HttpLog.log_body(res.body, res.headers["Content-Encoding"])
HttpLog.log_body(res.body, headers['Content-Encoding'], headers['Content-Type'])
conn.push(res)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/httplog/adapters/net_http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def request(req, body = nil, &block)
HttpLog.log_status(@response.code)
HttpLog.log_benchmark(bm)
HttpLog.log_headers(@response.each_header.collect)
HttpLog.log_body(@response.body, @response["Content-Encoding"])
HttpLog.log_body(@response.body, @response['Content-Encoding'], @response['Content-Type'])
end

@response
Expand Down
3 changes: 2 additions & 1 deletion lib/httplog/adapters/patron.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ def request(action_name, url, headers, options = {})
end

if log_enabled
headers = @response.headers
HttpLog.log_compact(action_name, url, @response.status, bm)
HttpLog.log_status(@response.status)
HttpLog.log_benchmark(bm)
HttpLog.log_body(@response.body, @response.headers['Content-Encoding'])
HttpLog.log_body(@response.body, headers['Content-Encoding'], headers['Content-Type'])
end
end
end
Expand Down
42 changes: 26 additions & 16 deletions lib/httplog/http_log.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,12 @@ def url_approved?(url)
url.to_s.match(options[:url_whitelist_pattern])
end

def log(msg, encoding='UTF-8')
def log(msg)
# This builds a hash {0=>:DEBUG, 1=>:INFO, 2=>:WARN, 3=>:ERROR, 4=>:FATAL, 5=>:UNKNOWN}.
# Courtesy of the delayed_job gem in this commit:
# https://github.com/collectiveidea/delayed_job/commit/e7f5aa1ed806e61251bdb77daf25864eeb3aff59
severities = Hash[*Logger::Severity.constants.enum_for(:each_with_index).collect{ |s, i| [i, s] }.flatten]
severity = severities[options[:severity]].to_s.downcase

msg.force_encoding(encoding) rescue msg.force_encoding('UTF-8')
msg.encode('UTF-8', :invalid => :replace, :undef => :replace)

options[:logger].send(severity, colorize(LOG_PREFIX + msg))
end

Expand Down Expand Up @@ -80,25 +76,35 @@ def log_benchmark(seconds)
log("Benchmark: #{seconds} seconds")
end

def log_body(body, encoding = nil)
def log_body(body, encoding = nil, content_type=nil)
return if options[:compact_log] || !options[:log_response]

if content_type !~ /text/
log("Response: (not showing binary data)")
return
end

if body.is_a?(Net::ReadAdapter)
# open-uri wraps the response in a Net::ReadAdapter that defers reading
# the content, so the reponse body is not available here.
log("Response: (not available yet)")
else
if encoding =~ /gzip/
sio = StringIO.new( body.to_s )
gz = Zlib::GzipReader.new( sio )
log("Response:\n#{gz.read}")
else
log("Response:\n#{body}", encoding)
end
return
end

if encoding =~ /gzip/
sio = StringIO.new( body.to_s )
gz = Zlib::GzipReader.new( sio )
body = gz.read
end

data = utf_encoded(body.to_s, content_type)

log("Response:\n#{data}")
end

def log_data(data)
return if options[:compact_log] || !options[:log_data]
return if options[:compact_log] || !options[:log_data] || data.nil?
data = utf_encoded(data)
log("Data: #{data}")
end

Expand All @@ -113,6 +119,10 @@ def colorize(msg)
msg.send(:colorize, options[:color])
end


def utf_encoded(data, content_type=nil)
charset = content_type.to_s.scan(/; charset=(\S+)/).flatten.first || 'UTF-8'
data.force_encoding(charset) rescue data.force_encoding('UTF-8')
data.encode('UTF-8', :invalid => :replace, :undef => :replace)
end
end
end
4 changes: 4 additions & 0 deletions spec/adapters/http_base_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ def initialize(host, port, path, headers, data, params, protocol = 'http')
@protocol = protocol
end

def logs_data?
true
end

def parse_uri
URI.parse("#{@protocol}://#{@host}:#{@port}#{@path}")
end
Expand Down
4 changes: 4 additions & 0 deletions spec/adapters/open_uri_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ def expected_response_body
def self.should_log_headers?
false
end

def logs_data?
false
end
end
23 changes: 23 additions & 0 deletions spec/http_log_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,29 @@
expect(log).to include(HttpLog::LOG_PREFIX + "Response:#{adapter.expected_response_body}")
end
end

context "with UTF-8 response body" do
let(:path) { '/utf8.html' }
let(:data) { nil }

it "works" do
adapter.send_get_request
expect(log).to include(HttpLog::LOG_PREFIX + "Response:#{adapter.expected_response_body}")
if adapter.logs_data?
expect(log).to include(" <title>Блог Яндекса</title>")
end
end
end

context "with binary response body" do
let(:path) { '/test.bin' }
let(:data) { nil }

it "doesn't log response" do
adapter.send_get_request
expect(log).to include(HttpLog::LOG_PREFIX + "Response: (not showing binary data)")
end
end
end

if adapter_class.method_defined? :send_post_request
Expand Down
Binary file added spec/support/test.bin
Binary file not shown.
3 changes: 2 additions & 1 deletion spec/support/test_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ def call(env)

elsif File.exists?(file)
headers["Content-Type"] = "application/octet-stream" if File.extname(file) == '.bin'
headers["Content-Type"] = "text/html; charset=UTF-8" if path =~ /utf8/
headers["Content-Encoding"] = "gzip" if File.extname(file) == '.gz'
[ 200, headers, File.read(file) ]
[ 200, headers, File.binread(file) ]
else
[ 404, {'Content-Type' => 'text/plain'}, 'file not found' ]
end
Expand Down
Binary file added spec/support/utf8-invalid.html
Binary file not shown.
8 changes: 8 additions & 0 deletions spec/support/utf8.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<head>
<title>Блог Яндекса</title>
</head>
<body>
<h1>This is the test page.</h1>
</body>
</html>

0 comments on commit 64fb419

Please sign in to comment.