api_hammer 0.4.1 → 0.4.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
  SHA1:
3
- metadata.gz: ea5469a646316cf076f0fb0016ac81b661c864f4
4
- data.tar.gz: 45c3e691c8692b974496e8ffd40fb213bedf8f41
3
+ metadata.gz: c2f9e2e65c6bd39813bce85257d2ff06f3a9296c
4
+ data.tar.gz: dd5ba2a6902c635d761edf351399820ace975bfc
5
5
  SHA512:
6
- metadata.gz: e953cde20b88e2ee2bc2804a5c030b55abad006a90fe9f7794970da303db467116833fe069f4059a155489e31cde8373f57759f82df58a384b8b0ef035a4f2af
7
- data.tar.gz: 534622ea02a5d88b6ea43e4d6f4f110c15394c4b1a612f310af3841598c6aef14e30a50501b0eb596d463b2c878ce4ce3c4b209179b5966687e0ebcce6d080ff
6
+ metadata.gz: 22059c86a14b39b299ca220fe0465ebcd0fd2d220832a3c49152f02c82b40aca902032c9fd1649cb2052046ac8836e234d7052dd454211feb4d6249fbedbcd57
7
+ data.tar.gz: 907c407c523d113eb6ceb0c21bcb32357dd4bb26c71fd08d3b27e8d0dd721473f4d1a6bf62d87e216e1c504f850a82f3c81e441b23486652cfe07697f365f520
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ # 0.4.2
2
+ - bugfix encoding in faraday request logger
3
+
1
4
  # 0.4.1
2
5
  - bugfix
3
6
 
@@ -2,6 +2,7 @@ require 'faraday'
2
2
  require 'rack'
3
3
  require 'term/ansicolor'
4
4
  require 'json'
5
+ require 'strscan'
5
6
 
6
7
  if Faraday.respond_to?(:register_middleware)
7
8
  Faraday.register_middleware(:request, :api_hammer_request_logger => proc { ApiHammer::Faraday::RequestLogger })
@@ -28,6 +29,69 @@ module ApiHammer
28
29
  @options = options
29
30
  end
30
31
 
32
+ # deal with the vagaries of getting the response body in a form which JSON
33
+ # gem will not cry about dumping
34
+ def response_body(response_env)
35
+ # first try to change the string's encoding per the Content-Type header
36
+ content_type = response_env.response_headers['Content-Type']
37
+ response_body = response_env.body.dup
38
+ unless response_body.valid_encoding?
39
+ # I think this always comes in as ASCII-8BIT anyway so may never get here. hopefully.
40
+ response_body.force_encoding('ASCII-8BIT')
41
+ end
42
+
43
+ if content_type
44
+ # TODO refactor this parsing somewhere better?
45
+ parsed = false
46
+ attributes = Hash.new { |h,k| h[k] = [] }
47
+ catch(:unparseable) do
48
+ uri_parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
49
+ scanner = StringScanner.new(content_type)
50
+ scanner.scan(/.*;\s*/) || throw(:unparseable)
51
+ while match = scanner.scan(/(\w+)=("?)([^"]*)("?)\s*(,?)\s*/)
52
+ key = scanner[1]
53
+ quote1 = scanner[2]
54
+ value = scanner[3]
55
+ quote2 = scanner[4]
56
+ comma_follows = !scanner[5].empty?
57
+ throw(:unparseable) unless quote1 == quote2
58
+ throw(:unparseable) if !comma_follows && !scanner.eos?
59
+ attributes[uri_parser.unescape(key)] << uri_parser.unescape(value)
60
+ end
61
+ throw(:unparseable) unless scanner.eos?
62
+ parsed = true
63
+ end
64
+ if parsed
65
+ charset = attributes['charset'].first
66
+ if Encoding.list.any? { |enc| enc.to_s.downcase == charset.downcase }
67
+ if response_body.dup.force_encoding(charset).valid_encoding?
68
+ response_body.force_encoding(charset)
69
+ else
70
+ # I guess just ignore the specified encoding if the result is not valid. fall back to
71
+ # something else below.
72
+ end
73
+ end
74
+ end
75
+ end
76
+ begin
77
+ JSON.dump([response_body])
78
+ rescue Encoding::UndefinedConversionError
79
+ # if updating by content-type didn't do it, try UTF8 since JSON wants that - but only
80
+ # if it seems to be valid utf8.
81
+ # don't try utf8 if the response content-type indicated something else.
82
+ try_utf8 = !(parsed && attributes['charset'].any?)
83
+ if try_utf8 && response_body.dup.force_encoding('UTF-8').valid_encoding?
84
+ response_body.force_encoding('UTF-8')
85
+ else
86
+ # I'm not sure if there is a way in this situation to get JSON gem to dump the
87
+ # string correctly. fall back to an array of codepoints I guess? this is a weird
88
+ # solution but the best I've got for now.
89
+ response_body = response_body.codepoints.to_a
90
+ end
91
+ end
92
+ response_body
93
+ end
94
+
31
95
  def call(request_env)
32
96
  began_at = Time.now
33
97
 
@@ -60,7 +124,7 @@ module ApiHammer
60
124
  'response' => {
61
125
  'status' => response_env.status,
62
126
  'headers' => response_env.response_headers,
63
- 'body' => response_env.body,
127
+ 'body' => response_body(response_env),
64
128
  }.reject{|k,v| v.nil? },
65
129
  'processing' => {
66
130
  'began_at' => began_at.utc.to_i,
@@ -1,3 +1,3 @@
1
1
  module ApiHammer
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('.', File.dirname(__FILE__)))
2
4
  require 'helper'
3
5
  require 'logger'
@@ -41,4 +43,54 @@ describe ApiHammer::RequestLogger do
41
43
  conn.get '/'
42
44
  assert_match(/200/, logio.string)
43
45
  end
46
+
47
+ describe 'response body encoding' do
48
+ it 'deals with encoding specified properly by the content type' do
49
+ app = proc do |env|
50
+ [200, {'Content-Type' => 'text/plain; charset=utf-8'}, ["Jalapeños".force_encoding("ASCII-8BIT")]]
51
+ end
52
+ conn = Faraday.new do |f|
53
+ f.request :api_hammer_request_logger, logger
54
+ f.use Faraday::Adapter::Rack, app
55
+ end
56
+ conn.get '/'
57
+ assert_match(/Jalapeños/, logio.string)
58
+ end
59
+
60
+ it 'deals with encoding not specified by the content type' do
61
+ app = proc do |env|
62
+ [200, {}, ["Jalapeños".force_encoding("ASCII-8BIT")]]
63
+ end
64
+ conn = Faraday.new do |f|
65
+ f.request :api_hammer_request_logger, logger
66
+ f.use Faraday::Adapter::Rack, app
67
+ end
68
+ conn.get '/'
69
+ assert_match(/Jalapeños/, logio.string)
70
+ end
71
+
72
+ it 'falls back to array of codepoints when encoding is improperly specified by the content type' do
73
+ app = proc do |env|
74
+ [200, {'Content-Type' => 'text/plain; charset=utf-8'}, ["xx" + [195].pack("C*")]]
75
+ end
76
+ conn = Faraday.new do |f|
77
+ f.request :api_hammer_request_logger, logger
78
+ f.use Faraday::Adapter::Rack, app
79
+ end
80
+ conn.get '/'
81
+ assert_match('[120,120,195]', logio.string)
82
+ end
83
+
84
+ it 'falls back to array of codepoints when encoding is not specified and not valid utf8' do
85
+ app = proc do |env|
86
+ [200, {}, ["xx" + [195].pack("C*")]]
87
+ end
88
+ conn = Faraday.new do |f|
89
+ f.request :api_hammer_request_logger, logger
90
+ f.use Faraday::Adapter::Rack, app
91
+ end
92
+ conn.get '/'
93
+ assert_match('[120,120,195]', logio.string)
94
+ end
95
+ end
44
96
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_hammer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-02 00:00:00.000000000 Z
11
+ date: 2014-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack