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 +7 -0
- data/README.md +15 -0
- data/lib/rest-core/middleware/error_detector_http.rb +3 -5
- data/lib/rest-core/middleware/oauth1_header.rb +34 -13
- data/lib/rest-core/version.rb +1 -1
- data/lib/rest-core/wrapper.rb +6 -1
- data/rest-core.gemspec +5 -4
- data/test/test_error_detector_http.rb +12 -0
- data/test/test_oauth1_header.rb +56 -24
- metadata +7 -6
- data/CONTRIBUTORS +0 -11
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
|
6
|
-
|
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
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
data/lib/rest-core/version.rb
CHANGED
data/lib/rest-core/wrapper.rb
CHANGED
@@ -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 ||
|
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
|
data/rest-core.gemspec
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "rest-core"
|
5
|
-
s.version = "0.8.
|
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 = "
|
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.
|
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
|
data/test/test_oauth1_header.rb
CHANGED
@@ -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.
|
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:
|
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: &
|
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: *
|
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.
|
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
|
data/CONTRIBUTORS
DELETED
@@ -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)
|