braintreehttp 0.1.5 → 0.2.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: 9f5acc4be958983186e9a0ec676bb2cd63ef1826
4
- data.tar.gz: 1df1e3ea5528c38871d9095a5d950dce2858faa5
3
+ metadata.gz: 599bde79b1bc33cd0f46c65d37136855ed422343
4
+ data.tar.gz: 06d2cf5cc5eeda5fad37ba71b07c97f91068331a
5
5
  SHA512:
6
- metadata.gz: cd69056b00f9453007534051a1c64e54e203f10383e48b6848e3e2c04ce93066e607c76dbe4eca87136e0e7c1c2e0c266b2bebfae094096962b2f14177a41279
7
- data.tar.gz: 42179eb6e06bbe238b3f5e4e6022751dc3ef57d06c8254c51d0fa6a73e0dc74096e4e0e54fb2fd9810ed7f334867fc7deddca6068e1e9c804e8a5bcdf28b16c0
6
+ metadata.gz: 81fe0a125d8b991d02e9f3d77171e4b4c18745df78e3f0a6e6c30d01c8edc873952736a047063d45925af236672f2cdc74f2887e175b98c9ebab5d62a7cf87bd
7
+ data.tar.gz: 9375dd0800ea34885828d90b3c3987cd8571ff312d28af415be69840671210fcd4edd63a06de5cc9758783472cfca22630b29c47b778a60f1d478b49ed93adec
@@ -1,10 +1,12 @@
1
+ require_relative './lib/braintreehttp/version'
2
+
1
3
  $:.push File.expand_path("../lib", __FILE__)
2
4
 
3
5
  Gem::Specification.new do |s|
4
6
  s.name = "braintreehttp"
5
7
  s.summary = "BraintreeHttp Client Library"
6
8
  s.description = "Used for generated API clients"
7
- s.version = "0.1.5"
9
+ s.version = VERSION
8
10
  s.license = "MIT"
9
11
  s.author = "Braintree"
10
12
  s.email = "code@getbraintree.com"
@@ -1,10 +1,9 @@
1
1
  require 'json'
2
2
 
3
3
  module BraintreeHttp
4
-
5
4
  class Encoder
6
5
  def initialize
7
- @encoders = [Json.new, Text.new]
6
+ @encoders = [Json.new, Text.new, Multipart.new]
8
7
  end
9
8
 
10
9
  def serialize_request(req)
@@ -16,7 +15,7 @@ module BraintreeHttp
16
15
  enc = _encoder(content_type)
17
16
  raise UnsupportedEncodingError.new("Unable to serialize request with Content-Type #{content_type}. Supported encodings are #{supported_encodings}") unless enc
18
17
 
19
- enc.encode(req.body)
18
+ enc.encode(req)
20
19
  end
21
20
 
22
21
  def deserialize_response(resp, headers)
@@ -43,9 +42,8 @@ module BraintreeHttp
43
42
  end
44
43
 
45
44
  class Json
46
-
47
- def encode(body)
48
- JSON.generate(body)
45
+ def encode(request)
46
+ JSON.generate(request.body)
49
47
  end
50
48
 
51
49
  def decode(body)
@@ -58,9 +56,8 @@ module BraintreeHttp
58
56
  end
59
57
 
60
58
  class Text
61
-
62
- def encode(body)
63
- body.to_s
59
+ def encode(request)
60
+ request.body.to_s
64
61
  end
65
62
 
66
63
  def decode(body)
@@ -71,4 +68,53 @@ module BraintreeHttp
71
68
  /^text\/.*/
72
69
  end
73
70
  end
71
+
72
+ class Multipart
73
+ def encode(request)
74
+ boundary = DateTime.now.strftime("%Q")
75
+ request.headers["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
76
+
77
+ form_params = []
78
+ request.body.each do |k, v|
79
+ if v.is_a? File
80
+ form_params.push(_add_file_part(k, v))
81
+ else
82
+ form_params.push(_add_form_field(k, v))
83
+ end
84
+ end
85
+
86
+ form_params.collect {|p| "--" + boundary + "#{LINE_FEED}" + p}.join("") + "--" + boundary + "--"
87
+ end
88
+
89
+ def decode(body)
90
+ raise UnsupportedEncodingError.new("Multipart does not support deserialization")
91
+ end
92
+
93
+ def content_type
94
+ /^multipart\/.*/
95
+ end
96
+
97
+ def _add_form_field(key, value)
98
+ return "Content-Disposition: form-data; name=\"#{key}\"#{LINE_FEED}#{LINE_FEED}#{value}#{LINE_FEED}"
99
+ end
100
+
101
+ def _add_file_part(key, file)
102
+ mime_type = _mime_type_for_file_name(file.path)
103
+ return "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{File.basename(file.path)}\"#{LINE_FEED}" +
104
+ "Content-Type: #{mime_type}#{LINE_FEED}#{LINE_FEED}#{file.read}#{LINE_FEED}"
105
+ end
106
+
107
+ def _mime_type_for_file_name(filename)
108
+ file_extension = File.extname(filename).strip.downcase[1..-1]
109
+ if file_extension == "jpeg" || file_extension == "jpg"
110
+ return "image/jpeg"
111
+ elsif file_extension == "png"
112
+ return "image/png"
113
+ elsif file_extension == "pdf"
114
+ return "application/pdf"
115
+ else
116
+ return "application/octet-stream"
117
+ end
118
+ end
119
+ end
74
120
  end
@@ -7,7 +7,7 @@ module BraintreeHttp
7
7
  LINE_FEED = "\r\n"
8
8
 
9
9
  class HttpClient
10
- attr_accessor :environment
10
+ attr_accessor :environment, :encoder
11
11
 
12
12
  def initialize(environment)
13
13
  @environment = environment
@@ -40,65 +40,15 @@ module BraintreeHttp
40
40
  request.headers["User-Agent"] = user_agent
41
41
  end
42
42
 
43
- httpRequest = Net::HTTPGenericRequest.new(request.verb, true, true, request.path, request.headers)
43
+ http_request = Net::HTTPGenericRequest.new(request.verb, true, true, request.path, request.headers)
44
44
 
45
- content_type = request.headers["Content-Type"]
46
- if content_type && content_type.start_with?("multipart/")
47
- boundary = DateTime.now.strftime("%Q")
48
- httpRequest.set_content_type("multipart/form-data; boundary=#{boundary}")
49
-
50
- form_params = []
51
- request.body.each do |k, v|
52
- if v.is_a? File
53
- form_params.push(_add_file_part(k, v))
54
- else
55
- form_params.push(_add_form_field(k, v))
56
- end
57
- end
58
-
59
- httpRequest.body = form_params.collect {|p| "--" + boundary + "#{LINE_FEED}" + p}.join("") + "--" + boundary + "--"
60
- elsif has_body(request)
61
- if request.body.is_a? String
62
- httpRequest.body = request.body
63
- else
64
- httpRequest.body = serialize_request(request)
65
- end
45
+ if has_body(request)
46
+ http_request.body = @encoder.serialize_request(request)
66
47
  end
67
48
 
68
49
  uri = URI(@environment.base_url)
69
50
  Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
70
- _parse_response(http.request(httpRequest))
71
- end
72
- end
73
-
74
- def serialize_request(request)
75
- @encoder.serialize_request(request)
76
- end
77
-
78
- def deserialize_response(response_body, headers)
79
- @encoder.deserialize_response(response_body, headers)
80
- end
81
-
82
- def _add_form_field(key, value)
83
- return "Content-Disposition: form-data; name=\"#{key}\"#{LINE_FEED}#{LINE_FEED}#{value}#{LINE_FEED}"
84
- end
85
-
86
- def _add_file_part(key, file)
87
- mime_type = _mime_type_for_file_name(file.path)
88
- return "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{File.basename(file.path)}\"#{LINE_FEED}" +
89
- "Content-Type: #{mime_type}#{LINE_FEED}#{LINE_FEED}#{file.read}#{LINE_FEED}"
90
- end
91
-
92
- def _mime_type_for_file_name(filename)
93
- file_extension = File.extname(filename).strip.downcase[1..-1]
94
- if file_extension == "jpeg" || file_extension == "jpg"
95
- return "image/jpeg"
96
- elsif file_extension == "png"
97
- return "image/png"
98
- elsif file_extension == "pdf"
99
- return "application/pdf"
100
- else
101
- return "application/octet-stream"
51
+ _parse_response(http.request(http_request))
102
52
  end
103
53
  end
104
54
 
@@ -108,7 +58,7 @@ module BraintreeHttp
108
58
  result = response.body
109
59
  headers = response.to_hash
110
60
  if result && !result.empty?
111
- deserialized = deserialize_response(response.body, headers)
61
+ deserialized = @encoder.deserialize_response(response.body, headers)
112
62
  if deserialized.is_a?(String) || deserialized.is_a?(Array)
113
63
  result = deserialized
114
64
  else
@@ -0,0 +1 @@
1
+ VERSION = "0.2.0"
@@ -36,6 +36,32 @@ describe Encoder do
36
36
  expect(Encoder.new.serialize_request(req)).to eq("some text")
37
37
  end
38
38
 
39
+ it 'serializes the request when content-type == multipart/form-data' do
40
+ http_client = HttpClient.new(@environment)
41
+ file = File.new("README.md", "r")
42
+ req = OpenStruct.new({
43
+ :verb => "POST",
44
+ :path => "/v1/api",
45
+ :headers => {
46
+ "Content-Type" => "multipart/form-data"
47
+ },
48
+ :body => {
49
+ :key => "value",
50
+ :another_key => 1013,
51
+ :readme => file,
52
+ }
53
+ })
54
+
55
+ serialized = Encoder.new.serialize_request(req)
56
+
57
+ expect(serialized).to include("Content-Disposition: form-data; name=\"readme\"; filename=\"README.md\"")
58
+ expect(serialized).to include("Content-Disposition: form-data; name=\"readme\"; filename=\"README.md\"")
59
+ expect(serialized).to include("Content-Disposition: form-data; name=\"key\"")
60
+ expect(serialized).to include("value")
61
+ expect(serialized).to include("Content-Disposition: form-data; name=\"another_key\"")
62
+ expect(serialized).to include("1013")
63
+ end
64
+
39
65
  it 'throws when content-type is not application/json' do
40
66
  req = OpenStruct.new({
41
67
  :headers => {
@@ -58,7 +58,13 @@ describe HttpClient do
58
58
 
59
59
  stub_request(:delete, @environment.base_url + "/path")
60
60
 
61
- req = OpenStruct.new({:verb => "DELETE", :path => "/path"})
61
+ req = OpenStruct.new({
62
+ :verb => "DELETE",
63
+ :path => "/path",
64
+ :headers => {
65
+ "Content-Type" => "text/plain"
66
+ }
67
+ })
62
68
 
63
69
  req.body = "I want to delete the thing"
64
70
 
@@ -157,36 +163,6 @@ describe HttpClient do
157
163
  expect(resp.result.key).to eq('value')
158
164
  end
159
165
 
160
- it "allows subclasses to modify response body" do
161
- WebMock.enable!
162
-
163
- return_data = {
164
- :key => "value"
165
- }
166
-
167
- class JSONHttpClient < HttpClient
168
- def deserialize_response(body, headers)
169
- if headers["content-type"].include? "application/json"
170
- return 'something else'
171
- end
172
-
173
- body
174
- end
175
- end
176
-
177
- http_client = JSONHttpClient.new(@environment)
178
-
179
- stub_request(:get, @environment.base_url + "/v1/api")
180
- .to_return(body: JSON.generate(return_data), status: 200, headers: {"Content-Type" => "application/json"})
181
-
182
- req = OpenStruct.new({:verb => "GET", :path => "/v1/api"})
183
-
184
- resp = http_client.execute(req)
185
-
186
- expect(resp.status_code).to eq(200)
187
- expect(resp.result).to eq('something else')
188
- end
189
-
190
166
  it 'handles json array result' do
191
167
  WebMock.enable!
192
168
 
@@ -204,49 +180,6 @@ describe HttpClient do
204
180
  expect(resp.result).to eq(return_data)
205
181
  end
206
182
 
207
- it "encodes multipart/form-data when a file is present without body" do
208
- WebMock.enable!
209
-
210
- stub_request(:any, @environment.base_url + "/v1/api")
211
-
212
- http_client = HttpClient.new(@environment)
213
- file = File.new("README.md", "r")
214
- req = OpenStruct.new({:verb => "POST", :path => "/v1/api", :headers => {"Content-Type" => "multipart/form-data"}})
215
- req.body = {:readme => file}
216
-
217
- resp = http_client.execute(req)
218
-
219
- assert_requested(:post, @environment.base_url + "/v1/api") { |requested|
220
- requested.body.include? "Content-Disposition: form-data; name=\"readme\"; filename=\"README.md\""
221
- }
222
- end
223
-
224
- it "encodes multipart/form-data when a file is present with body" do
225
- WebMock.enable!
226
-
227
- stub_request(:any, @environment.base_url + "/v1/api")
228
-
229
- http_client = HttpClient.new(@environment)
230
- file = File.new("README.md", "r")
231
-
232
- req = OpenStruct.new({:verb => "POST", :path => "/v1/api", :headers => {"Content-Type" => "multipart/form-data"}})
233
- req.body = {
234
- :key => "value",
235
- :another_key => 1013,
236
- :readme => file,
237
- }
238
-
239
- resp = http_client.execute(req)
240
-
241
- assert_requested(:post, @environment.base_url + "/v1/api") { |requested|
242
- requested.body.include? "Content-Disposition: form-data; name=\"readme\"; filename=\"README.md\""
243
- requested.body.include? "Content-Disposition: form-data; name=\"key\""
244
- requested.body.include? "value"
245
- requested.body.include? "Content-Disposition: form-data; name=\"another_key\""
246
- requested.body.include? "1013"
247
- }
248
- end
249
-
250
183
  it "does not error if no file or body present on a request class" do
251
184
  class Request
252
185
 
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.1.5
4
+ version: 0.2.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-08-30 00:00:00.000000000 Z
11
+ date: 2017-10-25 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,7 @@ files:
22
22
  - lib/braintreehttp/environment.rb
23
23
  - lib/braintreehttp/errors.rb
24
24
  - lib/braintreehttp/http_client.rb
25
+ - lib/braintreehttp/version.rb
25
26
  - spec/braintreehttp/encoder_spec.rb
26
27
  - spec/braintreehttp/http_client_spec.rb
27
28
  - spec/spec_helper.rb
@@ -45,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
45
46
  version: '0'
46
47
  requirements: []
47
48
  rubyforge_project: braintreehttp
48
- rubygems_version: 2.6.12
49
+ rubygems_version: 2.2.2
49
50
  signing_key:
50
51
  specification_version: 4
51
52
  summary: BraintreeHttp Client Library