rest-core 0.8.0 → 0.8.1

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