rest-core 0.8.0 → 0.8.1

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.
data/CHANGES.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # CHANGES
2
2
 
3
+ ## rest-core 0.8.1 -- 2012-02-09
4
+
5
+ ### Bugs fixes
6
+
7
+ * [ErrorDetectorHttp] Fixed argument error upon calling `lighten` for
8
+ clients using this middleware. (e.g. rest-more's Twitter client)
9
+
3
10
  ## rest-core 0.8.0 -- 2011-11-29
4
11
 
5
12
  Changes are mostly related to OAuth.
data/README.md CHANGED
@@ -159,6 +159,21 @@ and [slides][] from [rubyconf.tw/2011][rubyconf.tw] for concepts.
159
159
  could be any objects, it's handled by `RestCore::CommonLogger` or
160
160
  any other custom _middleware_.
161
161
 
162
+ ## CONTRIBUTORS:
163
+
164
+ * Andrew Liu (@eggegg)
165
+ * andy (@coopsite)
166
+ * Barnabas Debreczeni (@keo)
167
+ * Bruce Chu (@bruchu)
168
+ * Ethan Czahor (@ethanz5)
169
+ * Florent Vaucelle (@florent)
170
+ * Jaime Cham (@jcham)
171
+ * John Fan (@johnfan)
172
+ * Lin Jen-Shin (@godfat)
173
+ * Mariusz Pruszynski (@snicky)
174
+ * Mr. Big Cat (@miaout17)
175
+ * Nicolas Fouché (@nfo)
176
+
162
177
  ## LICENSE:
163
178
 
164
179
  Apache License 2.0
@@ -2,10 +2,8 @@
2
2
  require 'rest-core/middleware/error_detector'
3
3
 
4
4
  class RestCore::ErrorDetectorHttp < RestCore::ErrorDetector
5
- def self.members; [:error_detector]; end
6
- include RestCore::Middleware
7
-
8
- def initialize app
9
- super(app, lambda{ |env| (env[RESPONSE_STATUS] || 200) / 100 >= 4 })
5
+ def initialize app, detector=nil
6
+ super(app, detector ||
7
+ lambda{ |env| (env[RESPONSE_STATUS] || 200) / 100 >= 4 })
10
8
  end
11
9
  end
@@ -56,15 +56,7 @@ class RestCore::Oauth1Header
56
56
  def base_string env, oauth_params
57
57
  method = env[REQUEST_METHOD].to_s.upcase
58
58
  base_uri = env[REQUEST_PATH]
59
- # TODO: the detection should be checking if it's
60
- # application/x-www-form-urlencoded or not, instead of multipart or not.
61
- # but since the Content-Type is generated in app (http client),
62
- # we have no idea what it would be here. so simply guessing it...
63
- payload = if multipart?(env)
64
- {}
65
- else
66
- reject_blank(env[REQUEST_PAYLOAD] || {})
67
- end
59
+ payload = payload_params(env)
68
60
  query = reject_blank(env[REQUEST_QUERY] || {})
69
61
  params = reject_blank(oauth_params.merge(query.merge(payload))).
70
62
  to_a.sort.map{ |(k, v)|
@@ -77,10 +69,39 @@ class RestCore::Oauth1Header
77
69
  [OpenSSL::Random.random_bytes(32)].pack('m').tr("+/=\n", '')
78
70
  end
79
71
 
80
- def multipart? env
81
- !!(env[REQUEST_PAYLOAD] &&
82
- env[REQUEST_PAYLOAD].find{ |k, v| v.kind_of?(IO) ||
83
- v.respond_to?(:read) })
72
+ # according to OAuth 1.0a spec, only:
73
+ # Content-Type: application/x-www-form-urlencoded
74
+ # should take payload as a part of the base_string
75
+ def payload_params env
76
+ # if we already specified Content-Type and which is not
77
+ # application/x-www-form-urlencoded, then we should not
78
+ # take payload as a part of the base_string
79
+ if env[REQUEST_HEADERS].kind_of?(Hash) &&
80
+ env[REQUEST_HEADERS]['Content-Type'] &&
81
+ env[REQUEST_HEADERS]['Content-Type'] !=
82
+ 'application/x-www-form-urlencoded'
83
+ {}
84
+
85
+ # if it contains any binary data,
86
+ # then it shouldn't be application/x-www-form-urlencoded either
87
+ # the Content-Type header would be handled in our HTTP client
88
+ elsif contain_binary?(env[REQUEST_PAYLOAD])
89
+ {}
90
+
91
+ # so the Content-Type header must be application/x-www-form-urlencoded
92
+ else
93
+ reject_blank(env[REQUEST_PAYLOAD] || {})
94
+ end
95
+ end
96
+
97
+ def contain_binary? payload
98
+ return false unless payload
99
+ return true if payload.kind_of?(IO) ||
100
+ payload.respond_to?(:read)
101
+ return true if payload.find{ |k, v|
102
+ # if payload is an array, then v would be nil
103
+ (v || k).kind_of?(IO) || (v || k).respond_to?(:read) }
104
+ return false
84
105
  end
85
106
 
86
107
  def reject_blank params
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestCore
3
- VERSION = '0.8.0'
3
+ VERSION = '0.8.1'
4
4
  end
@@ -13,6 +13,11 @@ module RestCore::Wrapper
13
13
  end
14
14
  end
15
15
 
16
+ attr_writer :default_app
17
+ def default_app
18
+ @default_app ||= self.class.default_app
19
+ end
20
+
16
21
  def initialize &block
17
22
  @middles ||= []
18
23
  instance_eval(&block) if block_given?
@@ -38,7 +43,7 @@ module RestCore::Wrapper
38
43
  }.flatten
39
44
  end
40
45
 
41
- def to_app init=@init || self.class.default_app
46
+ def to_app init=@init || default_app
42
47
  # === foldr m.new app middles
43
48
  middles.reverse.inject(init.new){ |app_, (middle, args, block)|
44
49
  begin
@@ -2,13 +2,13 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "rest-core"
5
- s.version = "0.8.0"
5
+ s.version = "0.8.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = [
9
9
  "Cardinal Blue",
10
10
  "Lin Jen-Shin (godfat)"]
11
- s.date = "2011-11-29"
11
+ s.date = "2012-02-09"
12
12
  s.description = "Modular Ruby clients interface for REST APIs\n\nThere has been an explosion in the number of REST APIs available today.\nTo address the need for a way to access these APIs easily and elegantly,\nwe have developed [rest-core][], which consists of composable middleware\nthat allows you to build a REST client for any REST API. Or in the case of\ncommon APIs such as Facebook, Github, and Twitter, you can simply use the\ndedicated clients provided by [rest-more][].\n\n[rest-core]: http://github.com/cardinalblue/rest-core\n[rest-more]: http://github.com/cardinalblue/rest-more"
13
13
  s.email = ["dev (XD) cardinalblue.com"]
14
14
  s.files = [
@@ -16,7 +16,6 @@ Gem::Specification.new do |s|
16
16
  ".gitmodules",
17
17
  ".travis.yml",
18
18
  "CHANGES.md",
19
- "CONTRIBUTORS",
20
19
  "Gemfile",
21
20
  "LICENSE",
22
21
  "NOTE.md",
@@ -68,18 +67,20 @@ Gem::Specification.new do |s|
68
67
  "test/test_builder.rb",
69
68
  "test/test_client.rb",
70
69
  "test/test_client_oauth1.rb",
70
+ "test/test_error_detector_http.rb",
71
71
  "test/test_oauth1_header.rb",
72
72
  "test/test_universal.rb",
73
73
  "test/test_wrapper.rb"]
74
74
  s.homepage = "https://github.com/cardinalblue/rest-core"
75
75
  s.require_paths = ["lib"]
76
- s.rubygems_version = "1.8.11"
76
+ s.rubygems_version = "1.8.15"
77
77
  s.summary = "Modular Ruby clients interface for REST APIs"
78
78
  s.test_files = [
79
79
  "test/test_auth_basic.rb",
80
80
  "test/test_builder.rb",
81
81
  "test/test_client.rb",
82
82
  "test/test_client_oauth1.rb",
83
+ "test/test_error_detector_http.rb",
83
84
  "test/test_oauth1_header.rb",
84
85
  "test/test_universal.rb",
85
86
  "test/test_wrapper.rb"]
@@ -0,0 +1,12 @@
1
+
2
+ require 'rest-core/test'
3
+
4
+ describe RC::AuthBasic do
5
+ should 'lighten' do
6
+ RC::Builder.client do
7
+ s = self.class # this is only for ruby 1.8!
8
+ use s::ErrorDetectorHttp
9
+ run s::Dry
10
+ end.new.lighten.attributes.should.key?(:error_detector)
11
+ end
12
+ end
@@ -24,32 +24,64 @@ describe RestCore::Oauth1Header do
24
24
  'MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98')
25
25
  end
26
26
 
27
- should 'have correct base_string' do
28
- @auth.base_string(@env, @oauth_params).should.eq(
29
- 'POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&' \
30
- 'oauth_callback%3Dhttp%253A%252F%252Flocalhost%253A3005%252F' \
31
- 'the_dance%252Fprocess_callback%253Fservice_provider_id%253D' \
32
- '11%26oauth_consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonc' \
33
- 'e%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk%26oauth_sig' \
34
- 'nature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26' \
35
- 'oauth_version%3D1.0')
36
- end
37
-
38
- should 'not use payload in multipart request for base_string' do
39
- @env = @env.merge(RestCore::REQUEST_PAYLOAD =>
40
- {'file' => File.open(__FILE__)})
41
- @auth.base_string(@env, @oauth_params).should.eq(
42
- 'POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&' \
43
- 'oauth_callback%3Dhttp%253A%252F%252Flocalhost%253A3005%252F' \
44
- 'the_dance%252Fprocess_callback%253Fservice_provider_id%253D' \
45
- '11%26oauth_consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonc' \
46
- 'e%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk%26oauth_sig' \
47
- 'nature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26' \
48
- 'oauth_version%3D1.0')
49
- end
50
-
51
27
  should 'have correct signature' do
52
28
  @auth.signature(@env, @oauth_params).should.eq(
53
29
  '8wUi7m5HFQy76nowoCThusfgB+Q=')
54
30
  end
31
+
32
+ describe 'base_string' do
33
+ before do
34
+ @base_string =
35
+ 'POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&' \
36
+ 'oauth_callback%3Dhttp%253A%252F%252Flocalhost%253A3005%252F' \
37
+ 'the_dance%252Fprocess_callback%253Fservice_provider_id%253D' \
38
+ '11%26oauth_consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonc' \
39
+ 'e%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk%26oauth_sig' \
40
+ 'nature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26' \
41
+ 'oauth_version%3D1.0'
42
+ end
43
+
44
+ def check
45
+ @auth.base_string(@env, @oauth_params).should.eq @base_string
46
+ end
47
+
48
+ should 'have correct base_string' do
49
+ check
50
+ end
51
+
52
+ should 'not use payload in multipart request for base_string' do
53
+ @env.merge!(RC::REQUEST_PAYLOAD => {'file' => File.open(__FILE__)})
54
+ check
55
+ end
56
+
57
+ should 'not use payload if it contains binary' do
58
+ @env.merge!(RC::REQUEST_PAYLOAD => File.open(__FILE__))
59
+ check
60
+ end
61
+
62
+ should 'not use payload if it contains [binary]' do
63
+ @env.merge!(RC::REQUEST_PAYLOAD => [File.open(__FILE__)])
64
+ check
65
+ end
66
+
67
+ should 'not use payload if Content-Type is not x-www-form-urlencoded' do
68
+ @env.merge!(RC::REQUEST_PAYLOAD => {'pay' => 'load'},
69
+ RC::REQUEST_HEADERS => {'Content-Type' => 'text/plain'})
70
+ check
71
+ end
72
+
73
+ should 'use payload if Content-Type is x-www-form-urlencoded' do
74
+ @base_string << '%26pay%3Dload'
75
+ @env.merge!(RC::REQUEST_PAYLOAD => {'pay' => 'load'},
76
+ RC::REQUEST_HEADERS =>
77
+ {'Content-Type' => 'application/x-www-form-urlencoded'})
78
+ check
79
+ end
80
+
81
+ should 'use payload if there is no binary data' do
82
+ @base_string << '%26pay%3Dload'
83
+ @env.merge!(RC::REQUEST_PAYLOAD => {'pay' => 'load'})
84
+ check
85
+ end
86
+ end
55
87
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-11-29 00:00:00.000000000 Z
13
+ date: 2012-02-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rest-client
17
- requirement: &2164286260 !ruby/object:Gem::Requirement
17
+ requirement: &2168550920 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,7 +22,7 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2164286260
25
+ version_requirements: *2168550920
26
26
  description: ! 'Modular Ruby clients interface for REST APIs
27
27
 
28
28
 
@@ -52,7 +52,6 @@ files:
52
52
  - .gitmodules
53
53
  - .travis.yml
54
54
  - CHANGES.md
55
- - CONTRIBUTORS
56
55
  - Gemfile
57
56
  - LICENSE
58
57
  - NOTE.md
@@ -104,6 +103,7 @@ files:
104
103
  - test/test_builder.rb
105
104
  - test/test_client.rb
106
105
  - test/test_client_oauth1.rb
106
+ - test/test_error_detector_http.rb
107
107
  - test/test_oauth1_header.rb
108
108
  - test/test_universal.rb
109
109
  - test/test_wrapper.rb
@@ -127,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
127
  version: '0'
128
128
  requirements: []
129
129
  rubyforge_project:
130
- rubygems_version: 1.8.11
130
+ rubygems_version: 1.8.15
131
131
  signing_key:
132
132
  specification_version: 3
133
133
  summary: Modular Ruby clients interface for REST APIs
@@ -136,6 +136,7 @@ test_files:
136
136
  - test/test_builder.rb
137
137
  - test/test_client.rb
138
138
  - test/test_client_oauth1.rb
139
+ - test/test_error_detector_http.rb
139
140
  - test/test_oauth1_header.rb
140
141
  - test/test_universal.rb
141
142
  - test/test_wrapper.rb
@@ -1,11 +0,0 @@
1
- Lin Jen-Shin (godfat)
2
- Barnabas Debreczeni (keo)
3
- John Fan (johnfan)
4
- Jaime Cham (jcham)
5
- Andrew Liu (eggegg)
6
- Mariusz Pruszynski (snicky)
7
- Florent Vaucelle (florent)
8
- Ethan Czahor (ethanz5)
9
- Nicolas Fouché (nfo)
10
- andy (coopsite)
11
- Bruce Chu (bruchu)