braintreehttp 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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