braintreehttp 0.3.0 → 0.4.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
2
  SHA1:
3
- metadata.gz: 8f9eecbaee9baceb441762bc358a9fdd70ff6775
4
- data.tar.gz: 8cca413a46d85a6f02d4208ced9aff63a0473bef
3
+ metadata.gz: 5713242e8cfed8abeb24124ba10ca92c3e95ec2b
4
+ data.tar.gz: 93e09fa466ce4c6ecf25a506da8fd8305d7da6b5
5
5
  SHA512:
6
- metadata.gz: 1231f2845245b696eea965a638bba671d9b1b342968e7855b705b053e90b00e7edb66b97528ecea0d17671ac3896b4a68f5c5e3f814deb3242160518f6a27656
7
- data.tar.gz: 099178fdfadd1fd5ef8d01b01ae6df470bc5ca1be55234ce6816b4de02e6e659b42acb0dfd30523778e2c8edc9ab205bdcbd374520f737f7a4c44585007c6cce
6
+ metadata.gz: 2ddacb0b0df421383f074526d9cff0fbdce994f6b0c5f853498e16c9cb4d292b57638e26ee5b60576b05f73854abbb8690927792430ef3a14187fa9bc0ac4f8c
7
+ data.tar.gz: 1cbe84a0729e3077412e21b881c461aa07e6b73ba66ea0ebb1156bf808c7b0c5089a8b39e1c4420fdab5d2a190c9c79b19453c2d41d174764edad8313be9dab7
@@ -1,5 +1,9 @@
1
- require 'json'
2
- require 'uri'
1
+ require 'zlib'
2
+
3
+ require_relative './serializers/json'
4
+ require_relative './serializers/form_encoded'
5
+ require_relative './serializers/text'
6
+ require_relative './serializers/multipart'
3
7
 
4
8
  module BraintreeHttp
5
9
  class Encoder
@@ -10,24 +14,35 @@ module BraintreeHttp
10
14
  def serialize_request(req)
11
15
  raise UnsupportedEncodingError.new('HttpRequest did not have Content-Type header set') unless req.headers && (req.headers['content-type'] || req.headers['Content-Type'])
12
16
 
13
- content_type = req.headers['content-type'] || req.headers['Content-Type']
14
- content_type = content_type.first if content_type.kind_of?(Array)
17
+ content_type = _extract_header(req.headers, 'Content-Type')
15
18
 
16
19
  enc = _encoder(content_type)
17
20
  raise UnsupportedEncodingError.new("Unable to serialize request with Content-Type #{content_type}. Supported encodings are #{supported_encodings}") unless enc
18
21
 
19
- enc.encode(req)
22
+ encoded = enc.encode(req)
23
+ content_encoding = _extract_header(req.headers, 'Content-Encoding')
24
+
25
+ if content_encoding == 'gzip'
26
+ encoded = Zlib::Deflate.deflate(encoded)
27
+ end
28
+
29
+ encoded
20
30
  end
21
31
 
22
32
  def deserialize_response(resp, headers)
23
33
  raise UnsupportedEncodingError.new('HttpResponse did not have Content-Type header set') unless headers && (headers['content-type'] || headers['Content-Type'])
24
34
 
25
- content_type = headers['content-type'] || headers['Content-Type']
26
- content_type = content_type.first if content_type.kind_of?(Array)
35
+ content_type = _extract_header(headers, 'Content-Type')
27
36
 
28
37
  enc = _encoder(content_type)
29
38
  raise UnsupportedEncodingError.new("Unable to deserialize response with Content-Type #{content_type}. Supported decodings are #{supported_encodings}") unless enc
30
39
 
40
+ content_encoding = _extract_header(headers, 'Content-Encoding')
41
+
42
+ if content_encoding == 'gzip'
43
+ resp = Zlib::Inflate.inflate(resp)
44
+ end
45
+
31
46
  enc.decode(resp)
32
47
  end
33
48
 
@@ -40,101 +55,12 @@ module BraintreeHttp
40
55
 
41
56
  @encoders[idx] if idx
42
57
  end
43
- end
44
-
45
- class Json
46
- def encode(request)
47
- JSON.generate(request.body)
48
- end
49
-
50
- def decode(body)
51
- JSON.parse(body)
52
- end
53
-
54
- def content_type
55
- /^application\/json$/
56
- end
57
- end
58
58
 
59
- class Text
60
- def encode(request)
61
- request.body.to_s
62
- end
59
+ def _extract_header(headers, key)
60
+ value = headers[key] || headers[key.downcase]
61
+ value = value.first if value.kind_of?(Array)
63
62
 
64
- def decode(body)
65
- body.to_s
66
- end
67
-
68
- def content_type
69
- /^text\/.*/
70
- end
71
- end
72
-
73
- class FormEncoded
74
- def encode(request)
75
- encoded_params = []
76
- request.body.each do |k, v|
77
- encoded_params.push("#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}")
78
- end
79
-
80
- encoded_params.join("&")
81
- end
82
-
83
- def decode(body)
84
- raise UnsupportedEncodingError.new("FormEncoded does not support deserialization")
85
- end
86
-
87
- def content_type
88
- /^application\/x-www-form-urlencoded/
89
- end
90
- end
91
-
92
- class Multipart
93
- def encode(request)
94
- boundary = DateTime.now.strftime("%Q")
95
- request.headers["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
96
-
97
- form_params = []
98
- request.body.each do |k, v|
99
- if v.is_a? File
100
- form_params.push(_add_file_part(k, v))
101
- else
102
- form_params.push(_add_form_field(k, v))
103
- end
104
- end
105
-
106
- form_params.collect {|p| "--" + boundary + "#{LINE_FEED}" + p}.join("") + "--" + boundary + "--"
107
- end
108
-
109
- def decode(body)
110
- raise UnsupportedEncodingError.new("Multipart does not support deserialization")
111
- end
112
-
113
- def content_type
114
- /^multipart\/.*/
115
- end
116
-
117
- def _add_form_field(key, value)
118
- return "Content-Disposition: form-data; name=\"#{key}\"#{LINE_FEED}#{LINE_FEED}#{value}#{LINE_FEED}"
119
- end
120
-
121
- def _add_file_part(key, file)
122
- mime_type = _mime_type_for_file_name(file.path)
123
- return "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{File.basename(file.path)}\"#{LINE_FEED}" +
124
- "Content-Type: #{mime_type}#{LINE_FEED}#{LINE_FEED}#{file.read}#{LINE_FEED}"
125
- end
126
-
127
- def _mime_type_for_file_name(filename)
128
- file_extension = File.extname(filename).strip.downcase[1..-1]
129
- if file_extension == "jpeg" || file_extension == "jpg"
130
- return "image/jpeg"
131
- elsif file_extension == "png"
132
- return "image/png"
133
- elsif file_extension == "pdf"
134
- return "application/pdf"
135
- else
136
- return "application/octet-stream"
137
- end
63
+ value
138
64
  end
139
65
  end
140
66
  end
@@ -27,7 +27,16 @@ module BraintreeHttp
27
27
  request.respond_to?(:body) and request.body
28
28
  end
29
29
 
30
- def execute(request)
30
+ def execute(req)
31
+ headers = req.headers || {}
32
+
33
+ request = OpenStruct.new({
34
+ :verb => req.verb,
35
+ :path => req.path,
36
+ :headers => headers.clone,
37
+ :body => req.body,
38
+ })
39
+
31
40
  if !request.headers
32
41
  request.headers = {}
33
42
  end
@@ -0,0 +1,22 @@
1
+ require 'uri'
2
+
3
+ module BraintreeHttp
4
+ class FormEncoded
5
+ def encode(request)
6
+ encoded_params = []
7
+ request.body.each do |k, v|
8
+ encoded_params.push("#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}")
9
+ end
10
+
11
+ encoded_params.join("&")
12
+ end
13
+
14
+ def decode(body)
15
+ raise UnsupportedEncodingError.new("FormEncoded does not support deserialization")
16
+ end
17
+
18
+ def content_type
19
+ /^application\/x-www-form-urlencoded/
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ require 'json'
2
+
3
+ module BraintreeHttp
4
+ class Json
5
+ def encode(request)
6
+ JSON.generate(request.body)
7
+ end
8
+
9
+ def decode(body)
10
+ JSON.parse(body)
11
+ end
12
+
13
+ def content_type
14
+ /application\/json/
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,50 @@
1
+ module BraintreeHttp
2
+ class Multipart
3
+ def encode(request)
4
+ boundary = DateTime.now.strftime("%Q")
5
+ request.headers["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
6
+
7
+ form_params = []
8
+ request.body.each do |k, v|
9
+ if v.is_a? File
10
+ form_params.push(_add_file_part(k, v))
11
+ else
12
+ form_params.push(_add_form_field(k, v))
13
+ end
14
+ end
15
+
16
+ form_params.collect {|p| "--" + boundary + "#{LINE_FEED}" + p}.join("") + "--" + boundary + "--"
17
+ end
18
+
19
+ def decode(body)
20
+ raise UnsupportedEncodingError.new("Multipart does not support deserialization")
21
+ end
22
+
23
+ def content_type
24
+ /multipart\/.*/
25
+ end
26
+
27
+ def _add_form_field(key, value)
28
+ return "Content-Disposition: form-data; name=\"#{key}\"#{LINE_FEED}#{LINE_FEED}#{value}#{LINE_FEED}"
29
+ end
30
+
31
+ def _add_file_part(key, file)
32
+ mime_type = _mime_type_for_file_name(file.path)
33
+ return "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{File.basename(file.path)}\"#{LINE_FEED}" +
34
+ "Content-Type: #{mime_type}#{LINE_FEED}#{LINE_FEED}#{file.read}#{LINE_FEED}"
35
+ end
36
+
37
+ def _mime_type_for_file_name(filename)
38
+ file_extension = File.extname(filename).strip.downcase[1..-1]
39
+ if file_extension == "jpeg" || file_extension == "jpg"
40
+ return "image/jpeg"
41
+ elsif file_extension == "png"
42
+ return "image/png"
43
+ elsif file_extension == "pdf"
44
+ return "application/pdf"
45
+ else
46
+ return "application/octet-stream"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,15 @@
1
+ module BraintreeHttp
2
+ class Text
3
+ def encode(request)
4
+ request.body.to_s
5
+ end
6
+
7
+ def decode(body)
8
+ body.to_s
9
+ end
10
+
11
+ def content_type
12
+ /text\/.*/
13
+ end
14
+ end
15
+ end
@@ -1 +1 @@
1
- VERSION = "0.3.0"
1
+ VERSION = "0.4.0"
@@ -1,4 +1,6 @@
1
1
  require 'ostruct'
2
+ require 'json'
3
+ require 'zlib'
2
4
 
3
5
  describe Encoder do
4
6
 
@@ -6,7 +8,7 @@ describe Encoder do
6
8
  it 'serializes the request when content-type == application/json' do
7
9
  req = OpenStruct.new({
8
10
  :headers => {
9
- "content-type" => "application/json"
11
+ "content-type" => "application/json; charset=utf8"
10
12
  },
11
13
  :body => {
12
14
  "string" => "value",
@@ -28,7 +30,7 @@ describe Encoder do
28
30
  it 'serializes the request when content-type == text/*' do
29
31
  req = OpenStruct.new({
30
32
  :headers => {
31
- "content-type" => "text/plain"
33
+ "content-type" => "text/plain; charset=utf8"
32
34
  },
33
35
  :body => "some text"
34
36
  })
@@ -39,10 +41,10 @@ describe Encoder do
39
41
  it 'serializes the request when content-type == multipart/form-data' do
40
42
  file = File.new("README.md", "r")
41
43
  req = OpenStruct.new({
42
- :verb => "POST",
43
- :path => "/v1/api",
44
+ :verb => "POST",
45
+ :path => "/v1/api",
44
46
  :headers => {
45
- "Content-Type" => "multipart/form-data"
47
+ "Content-Type" => "multipart/form-data; charset=utf8"
46
48
  },
47
49
  :body => {
48
50
  :key => "value",
@@ -63,10 +65,10 @@ describe Encoder do
63
65
 
64
66
  it 'serializes the request when content-type == application/x-www-form-urlencoded' do
65
67
  req = OpenStruct.new({
66
- :verb => "POST",
67
- :path => "/v1/api",
68
+ :verb => "POST",
69
+ :path => "/v1/api",
68
70
  :headers => {
69
- "Content-Type" => "application/x-www-form-urlencoded"
71
+ "Content-Type" => "application/x-www-form-urlencoded; charset=utf8"
70
72
  },
71
73
  :body => {
72
74
  :key => "value with a space",
@@ -78,10 +80,10 @@ describe Encoder do
78
80
  expect(serialized).to eq("key=value%20with%20a%20space&another_key=1013")
79
81
  end
80
82
 
81
- it 'throws when content-type is not application/json' do
83
+ it 'throws when content-type is unsupported' do
82
84
  req = OpenStruct.new({
83
85
  :headers => {
84
- "content-type" => "not application/json"
86
+ "content-type" => "fake/content-type"
85
87
  },
86
88
  :body => { :string => "value" }
87
89
  })
@@ -96,10 +98,38 @@ describe Encoder do
96
98
 
97
99
  expect{Encoder.new.serialize_request(req)}.to raise_error(UnsupportedEncodingError, 'HttpRequest did not have Content-Type header set')
98
100
  end
101
+
102
+ it 'throws when conent-type undefined' do
103
+ req = OpenStruct.new({
104
+ :headers => {},
105
+ :body => { :key => "value" }
106
+ })
107
+
108
+
109
+ expect{Encoder.new.serialize_request(req)}.to raise_error(UnsupportedEncodingError, 'HttpRequest did not have Content-Type header set')
110
+ end
111
+
112
+ it 'encodes data as gzip when content-encoding == gzip' do
113
+ req = OpenStruct.new({
114
+ :path => '/143j2bz1',
115
+ :verb => "POST",
116
+ :headers => {
117
+ 'Content-Type' => 'application/json',
118
+ 'Content-Encoding' => 'gzip'
119
+ },
120
+ :body => {
121
+ :one => "two"
122
+ }
123
+ })
124
+
125
+ encoder = Encoder.new
126
+
127
+ expect(encoder.serialize_request(req)).to eq(Zlib::Deflate.deflate(JSON.generate(req.body)))
128
+ end
99
129
  end
100
130
 
101
131
  describe 'deserialize_response' do
102
- it 'throws when content-type not application/json' do
132
+ it 'throws when content-type unsupported' do
103
133
  body = '{"string":"value","number":1.23,"bool":true,"array":["one","two","three"],"nested":{"nested_string":"nested_value","nested_array":[1,2,3]}}'
104
134
  headers = {
105
135
  "content-type" => ["application/xml"]
@@ -114,6 +144,12 @@ describe Encoder do
114
144
  expect{Encoder.new.deserialize_response(body, nil)}.to raise_error(UnsupportedEncodingError, 'HttpResponse did not have Content-Type header set')
115
145
  end
116
146
 
147
+ it 'throws when content-type undefined' do
148
+ body = '{"string":"value","number":1.23,"bool":true,"array":["one","two","three"],"nested":{"nested_string":"nested_value","nested_array":[1,2,3]}}'
149
+
150
+ expect{Encoder.new.deserialize_response(body, {})}.to raise_error(UnsupportedEncodingError, 'HttpResponse did not have Content-Type header set')
151
+ end
152
+
117
153
  it 'deserializes the response when content-type == application/json' do
118
154
  expected = {
119
155
  "string" => "value",
@@ -126,17 +162,45 @@ describe Encoder do
126
162
  }
127
163
  }
128
164
 
129
- headers = {"content-type" => ["application/json"]}
165
+ headers = {"content-type" => ["application/json; charset=utf8"]}
130
166
  body = '{"string":"value","number":1.23,"bool":true,"array":["one","two","three"],"nested":{"nested_string":"nested_value","nested_array":[1,2,3]}}'
131
167
 
132
168
  expect(Encoder.new.deserialize_response(body, headers)).to eq(expected)
133
169
  end
134
170
 
135
171
  it 'deserializes the response when content-type == text/*' do
136
- headers = {"content-type" => ["text/plain"]}
172
+ headers = {"content-type" => ["text/plain; charset=utf8"]}
137
173
  body = 'some text'
138
174
 
139
175
  expect(Encoder.new.deserialize_response(body, headers)).to eq('some text')
140
176
  end
177
+
178
+ it 'throws when attempting to deserialize multipart/*' do
179
+ headers = {"content-type" => ["multipart/form-data"]}
180
+ body = 'some multipart encoded data here'
181
+
182
+ expect{Encoder.new.deserialize_response(body, headers)}.to raise_error(UnsupportedEncodingError, 'Multipart does not support deserialization')
183
+ end
184
+
185
+ it 'throws when attempting to deserialize application/x-www-form-urlencoded' do
186
+ headers = {"content-type" => ["application/x-www-form-urlencoded"]}
187
+ body = 'some multipart encoded data here'
188
+
189
+ expect{Encoder.new.deserialize_response(body, headers)}.to raise_error(UnsupportedEncodingError, 'FormEncoded does not support deserialization')
190
+ end
191
+
192
+ it 'decodes data from gzip when content-encoding == gzip' do
193
+ headers = {
194
+ 'content-type' => 'application/json',
195
+ 'content-encoding' => 'gzip'
196
+ }
197
+ body = JSON.generate({
198
+ :one => 'two'
199
+ })
200
+
201
+ encoded_body = Zlib::Deflate.deflate(body)
202
+
203
+ expect(Encoder.new.deserialize_response(encoded_body, headers)).to eq({'one' => 'two'})
204
+ end
141
205
  end
142
206
  end
@@ -23,7 +23,10 @@ describe HttpClient do
23
23
 
24
24
  http_client.execute(req)
25
25
 
26
- expect(req.headers["Some-Key"]).to eq("Some Value")
26
+ assert_requested :get, "#{@environment.base_url}/", {
27
+ :headers => {'Some-Key' => 'Some Value'},
28
+ :times => 1
29
+ }
27
30
  end
28
31
 
29
32
  it "uses method injector to modify request" do
@@ -43,7 +46,10 @@ describe HttpClient do
43
46
 
44
47
  http_client.execute(req)
45
48
 
46
- expect(req.headers["Some-Key"]).to eq("Some Value")
49
+ assert_requested :get, "#{@environment.base_url}/", {
50
+ :headers => {'Some-Key' => 'Some Value'},
51
+ :times => 1
52
+ }
47
53
  end
48
54
 
49
55
  it "sets User-Agent header in request if not set" do
@@ -56,7 +62,10 @@ describe HttpClient do
56
62
 
57
63
  http_client.execute(req)
58
64
 
59
- expect(req.headers["User-Agent"]).to eq("BraintreeHttp-Ruby HTTP/1.1")
65
+ assert_requested :get, "#{@environment.base_url}/", {
66
+ :headers => {"User-Agent" => "BraintreeHttp-Ruby HTTP/1.1"},
67
+ :times => 1
68
+ }
60
69
  end
61
70
 
62
71
  it "does not overwrite User-Agent header if set" do
@@ -70,7 +79,24 @@ describe HttpClient do
70
79
 
71
80
  http_client.execute(req)
72
81
 
73
- expect(req.headers["User-Agent"]).to eq("Not Ruby Http/1.1")
82
+ assert_requested :get, "#{@environment.base_url}/", {
83
+ :headers => {"User-Agent" => "Not Ruby Http/1.1"},
84
+ :times => 1
85
+ }
86
+ end
87
+
88
+ it "does not modify the original request" do
89
+ WebMock.enable!
90
+
91
+ http_client = HttpClient.new(@environment)
92
+
93
+ req = OpenStruct.new({:verb => "GET", :path => "/"})
94
+
95
+ stub_request(:any, @environment.base_url)
96
+
97
+ http_client.execute(req)
98
+
99
+ expect(req.headers).to be_nil
74
100
  end
75
101
 
76
102
  it "uses body in request" do
@@ -210,15 +236,6 @@ describe HttpClient do
210
236
  @verb = "POST"
211
237
  @path = "/v1/api"
212
238
  end
213
-
214
- def requestBody(body)
215
- @body = body
216
- end
217
-
218
- def setFile(file)
219
- @file = file
220
- end
221
-
222
239
  end
223
240
 
224
241
  WebMock.enable!
@@ -231,8 +248,6 @@ describe HttpClient do
231
248
  rescue Exception => e
232
249
  fail e.message
233
250
  end
234
-
235
251
  end
236
-
237
252
  end
238
253
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: braintreehttp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Braintree
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-25 00:00:00.000000000 Z
11
+ date: 2017-11-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Used for generated API clients
14
14
  email: code@getbraintree.com
@@ -22,6 +22,10 @@ files:
22
22
  - lib/braintreehttp/environment.rb
23
23
  - lib/braintreehttp/errors.rb
24
24
  - lib/braintreehttp/http_client.rb
25
+ - lib/braintreehttp/serializers/form_encoded.rb
26
+ - lib/braintreehttp/serializers/json.rb
27
+ - lib/braintreehttp/serializers/multipart.rb
28
+ - lib/braintreehttp/serializers/text.rb
25
29
  - lib/braintreehttp/version.rb
26
30
  - spec/braintreehttp/encoder_spec.rb
27
31
  - spec/braintreehttp/http_client_spec.rb
@@ -46,7 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
50
  version: '0'
47
51
  requirements: []
48
52
  rubyforge_project: braintreehttp
49
- rubygems_version: 2.2.2
53
+ rubygems_version: 2.5.2
50
54
  signing_key:
51
55
  specification_version: 4
52
56
  summary: BraintreeHttp Client Library