rest-core 0.8.2 → 1.0.0
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/.travis.yml +4 -2
- data/CHANGES.md +130 -19
- data/Gemfile +4 -0
- data/README.md +147 -13
- data/TODO.md +0 -10
- data/doc/ToC.md +7 -0
- data/doc/dependency.md +4 -0
- data/doc/design.md +4 -0
- data/example/auto.rb +51 -0
- data/example/coolio.rb +21 -0
- data/example/eventmachine.rb +28 -0
- data/example/multi.rb +33 -0
- data/example/rest-client.rb +16 -0
- data/lib/rest-core/app/abstract/async_fiber.rb +13 -0
- data/lib/rest-core/app/auto.rb +22 -0
- data/lib/rest-core/app/coolio-async.rb +32 -0
- data/lib/rest-core/app/coolio-fiber.rb +30 -0
- data/lib/rest-core/app/coolio.rb +9 -0
- data/lib/rest-core/app/dry.rb +1 -0
- data/lib/rest-core/app/em-http-request-async.rb +34 -0
- data/lib/rest-core/app/em-http-request-fiber.rb +39 -0
- data/lib/rest-core/app/em-http-request.rb +9 -0
- data/lib/rest-core/app/rest-client.rb +24 -7
- data/lib/rest-core/client/universal.rb +3 -4
- data/lib/rest-core/client.rb +31 -4
- data/lib/rest-core/middleware/cache.rb +23 -5
- data/lib/rest-core/middleware/common_logger.rb +13 -3
- data/lib/rest-core/middleware/error_detector.rb +10 -1
- data/lib/rest-core/middleware/error_handler.rb +7 -1
- data/lib/rest-core/middleware/follow_redirect.rb +42 -0
- data/lib/rest-core/middleware/json_decode.rb +11 -2
- data/lib/rest-core/middleware/timeout/coolio_timer.rb +4 -0
- data/lib/rest-core/middleware/timeout/eventmachine_timer.rb +14 -0
- data/lib/rest-core/middleware/timeout.rb +73 -1
- data/lib/rest-core/middleware.rb +7 -0
- data/lib/rest-core/patch/rest-client.rb +35 -0
- data/lib/rest-core/version.rb +1 -1
- data/lib/rest-core.rb +19 -0
- data/rest-core.gemspec +28 -8
- data/test/test_client.rb +20 -3
- data/test/test_follow_redirect.rb +47 -0
- data/test/test_json_decode.rb +24 -0
- metadata +36 -11
- data/example/facebook.rb +0 -9
- data/example/github.rb +0 -4
- data/example/linkedin.rb +0 -8
- data/example/twitter.rb +0 -11
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
require 'rest-core/middleware'
|
3
|
+
|
4
|
+
class RestCore::Auto
|
5
|
+
include RestCore::Middleware
|
6
|
+
def call env
|
7
|
+
client = http_client
|
8
|
+
client.call(log(env, "Auto picked: #{client.class}"))
|
9
|
+
end
|
10
|
+
|
11
|
+
def http_client
|
12
|
+
if Object.const_defined?(:Coolio) && ::Coolio::Loop.default.
|
13
|
+
has_active_watchers?
|
14
|
+
@coolio ||= RestCore::Coolio.new
|
15
|
+
elsif Object.const_defined?(:EventMachine) && ::EventMachine.
|
16
|
+
reactor_running?
|
17
|
+
@emhttprequest ||= RestCore::EmHttpRequest.new
|
18
|
+
else
|
19
|
+
@restclient ||= RestCore::RestClient.new
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
require 'rest-core/middleware'
|
3
|
+
|
4
|
+
require 'cool.io-http'
|
5
|
+
|
6
|
+
class RestCore::CoolioAsync
|
7
|
+
include RestCore::Middleware
|
8
|
+
def call env
|
9
|
+
client = ::Coolio::Http.request(:method => env[REQUEST_METHOD] ,
|
10
|
+
:url => request_uri(env) ,
|
11
|
+
:payload => env[REQUEST_PAYLOAD],
|
12
|
+
:headers => env[REQUEST_HEADERS]){ |res|
|
13
|
+
|
14
|
+
env[TIMER].detach if env[TIMER]
|
15
|
+
env[ASYNC].call(env.merge(RESPONSE_BODY => res.body ,
|
16
|
+
RESPONSE_STATUS => res.status,
|
17
|
+
RESPONSE_HEADERS => res.headers)) if
|
18
|
+
env[ASYNC]
|
19
|
+
}
|
20
|
+
|
21
|
+
env[TIMER].on_timer{
|
22
|
+
detach
|
23
|
+
client.detach
|
24
|
+
env[ASYNC].call(env.merge(RESPONSE_BODY => env[TIMER].error,
|
25
|
+
RESPONSE_STATUS => 0 ,
|
26
|
+
RESPONSE_HEADERS => {} )) if
|
27
|
+
env[ASYNC]
|
28
|
+
} if env[TIMER]
|
29
|
+
|
30
|
+
env
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
require 'rest-core/middleware'
|
3
|
+
|
4
|
+
require 'cool.io-http'
|
5
|
+
|
6
|
+
class RestCore::CoolioFiber
|
7
|
+
include RestCore::Middleware
|
8
|
+
def call env
|
9
|
+
process(env,
|
10
|
+
::Coolio::HttpFiber.request(:method => env[REQUEST_METHOD] ,
|
11
|
+
:url => request_uri(env) ,
|
12
|
+
:payload => env[REQUEST_PAYLOAD],
|
13
|
+
:headers => env[REQUEST_HEADERS]))
|
14
|
+
end
|
15
|
+
|
16
|
+
def process env, response
|
17
|
+
env[TIMER].detach if env[TIMER]
|
18
|
+
Thread.current[:coolio_http_client].detach if
|
19
|
+
Thread.current[:coolio_http_client].kind_of?(::Coolio::HttpFiber)
|
20
|
+
|
21
|
+
raise response if response.kind_of?(::Exception)
|
22
|
+
|
23
|
+
result = env.merge(RESPONSE_BODY => response.body ,
|
24
|
+
RESPONSE_STATUS => response.status,
|
25
|
+
RESPONSE_HEADERS => response.headers)
|
26
|
+
|
27
|
+
result[ASYNC].call(result) if result[ASYNC]
|
28
|
+
result
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
|
2
|
+
require 'rest-core/app/abstract/async_fiber'
|
3
|
+
require 'rest-core/app/coolio-async'
|
4
|
+
require 'rest-core/app/coolio-fiber'
|
5
|
+
|
6
|
+
class RestCore::Coolio < RestCore::AsyncFiber
|
7
|
+
def async; @async ||= CoolioAsync.new; end
|
8
|
+
def fiber; @fiber ||= CoolioFiber.new; end
|
9
|
+
end
|
data/lib/rest-core/app/dry.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
require 'rest-core/middleware'
|
3
|
+
|
4
|
+
require 'rest-client'
|
5
|
+
require 'em-http-request'
|
6
|
+
|
7
|
+
class RestCore::EmHttpRequestAsync
|
8
|
+
include RestCore::Middleware
|
9
|
+
def call env
|
10
|
+
payload = ::RestClient::Payload.generate(env[REQUEST_PAYLOAD])
|
11
|
+
client = ::EventMachine::HttpRequest.new(request_uri(env)).send(
|
12
|
+
env[REQUEST_METHOD],
|
13
|
+
:body => payload.read,
|
14
|
+
:head => payload.headers.merge(env[REQUEST_HEADERS]))
|
15
|
+
|
16
|
+
client.callback{
|
17
|
+
env[TIMER].cancel if env[TIMER]
|
18
|
+
env[ASYNC].call(env.merge(
|
19
|
+
RESPONSE_BODY => client.response,
|
20
|
+
RESPONSE_STATUS => client.response_header.status,
|
21
|
+
RESPONSE_HEADERS => client.response_header)) if env[ASYNC]
|
22
|
+
}
|
23
|
+
|
24
|
+
env[TIMER].on_timeout{
|
25
|
+
client.close
|
26
|
+
env[ASYNC].call(env.merge(RESPONSE_BODY => env[TIMER].error,
|
27
|
+
RESPONSE_STATUS => 0 ,
|
28
|
+
RESPONSE_HEADERS => {} )) if
|
29
|
+
env[ASYNC]
|
30
|
+
} if env[TIMER]
|
31
|
+
|
32
|
+
env
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
require 'rest-core/middleware'
|
3
|
+
|
4
|
+
require 'rest-client'
|
5
|
+
require 'em-http-request'
|
6
|
+
require 'fiber'
|
7
|
+
|
8
|
+
class RestCore::EmHttpRequestFiber
|
9
|
+
include RestCore::Middleware
|
10
|
+
def call env
|
11
|
+
f = Fiber.current
|
12
|
+
|
13
|
+
payload = ::RestClient::Payload.generate(env[REQUEST_PAYLOAD])
|
14
|
+
client = ::EventMachine::HttpRequest.new(request_uri(env)).send(
|
15
|
+
env[REQUEST_METHOD],
|
16
|
+
:body => payload.read,
|
17
|
+
:head => payload.headers.merge(env[REQUEST_HEADERS]))
|
18
|
+
|
19
|
+
client.callback{
|
20
|
+
env[TIMER].cancel if env[TIMER]
|
21
|
+
f.resume(process(env, client)) if f.alive?
|
22
|
+
}
|
23
|
+
|
24
|
+
if (response = Fiber.yield).kind_of?(::Exception)
|
25
|
+
client.close
|
26
|
+
raise response
|
27
|
+
else
|
28
|
+
response
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def process env, client
|
33
|
+
result = env.merge(RESPONSE_BODY => client.response,
|
34
|
+
RESPONSE_STATUS => client.response_header.status,
|
35
|
+
RESPONSE_HEADERS => client.response_header)
|
36
|
+
result[ASYNC].call(result) if result[ASYNC]
|
37
|
+
result
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
|
2
|
+
require 'rest-core/app/abstract/async_fiber'
|
3
|
+
require 'rest-core/app/em-http-request-async'
|
4
|
+
require 'rest-core/app/em-http-request-fiber'
|
5
|
+
|
6
|
+
class RestCore::EmHttpRequest < RestCore::AsyncFiber
|
7
|
+
def async; @async ||= EmHttpRequestAsync.new; end
|
8
|
+
def fiber; @fiber ||= EmHttpRequestFiber.new; end
|
9
|
+
end
|
@@ -3,22 +3,39 @@ require 'rest-core/middleware'
|
|
3
3
|
|
4
4
|
require 'restclient'
|
5
5
|
|
6
|
+
require 'rest-core/patch/rest-client'
|
7
|
+
|
6
8
|
class RestCore::RestClient
|
7
9
|
include RestCore::Middleware
|
8
10
|
def call env
|
9
|
-
|
11
|
+
process(env,
|
10
12
|
::RestClient::Request.execute(:method => env[REQUEST_METHOD ],
|
11
13
|
:url => request_uri(env) ,
|
12
14
|
:payload => env[REQUEST_PAYLOAD],
|
13
|
-
:headers => env[REQUEST_HEADERS]
|
15
|
+
:headers => env[REQUEST_HEADERS],
|
16
|
+
:max_redirects => 0))
|
14
17
|
|
15
18
|
rescue ::RestClient::Exception => e
|
16
|
-
|
19
|
+
process(env, e.response)
|
20
|
+
end
|
21
|
+
|
22
|
+
def process env, response
|
23
|
+
result = env.merge(RESPONSE_BODY => response.body,
|
24
|
+
RESPONSE_STATUS => response.code,
|
25
|
+
RESPONSE_HEADERS => normalize_headers(
|
26
|
+
response.raw_headers))
|
27
|
+
result[ASYNC].call(result) if result[ASYNC]
|
28
|
+
result
|
17
29
|
end
|
18
30
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
|
31
|
+
def normalize_headers raw_headers
|
32
|
+
raw_headers.inject({}){ |r, (k, v)|
|
33
|
+
r[k.to_s.upcase.tr('-', '_')] = if v.kind_of?(Array) && v.size == 1
|
34
|
+
v.first
|
35
|
+
else
|
36
|
+
v
|
37
|
+
end
|
38
|
+
r
|
39
|
+
}
|
23
40
|
end
|
24
41
|
end
|
@@ -1,19 +1,18 @@
|
|
1
1
|
|
2
|
-
RestCore::Universal = RestCore::Builder.client
|
2
|
+
RestCore::Universal = RestCore::Builder.client do
|
3
3
|
s = self.class # this is only for ruby 1.8!
|
4
4
|
use s::Timeout , 0
|
5
5
|
|
6
6
|
use s::DefaultSite , nil
|
7
7
|
use s::DefaultHeaders, {}
|
8
8
|
use s::DefaultQuery , {}
|
9
|
+
use s::AuthBasic , nil, nil
|
9
10
|
|
11
|
+
use s::FollowRedirect, 10
|
10
12
|
use s::CommonLogger , method(:puts)
|
11
|
-
use s::AuthBasic , nil, nil
|
12
13
|
use s::Cache , {}, 600 do
|
13
14
|
use s::ErrorHandler, nil
|
14
15
|
use s::ErrorDetectorHttp
|
15
16
|
use s::JsonDecode , false
|
16
17
|
end
|
17
|
-
|
18
|
-
use s::Defaults , :data => lambda{{}}
|
19
18
|
end
|
data/lib/rest-core/client.rb
CHANGED
@@ -60,8 +60,8 @@ module RestCore::Client
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def inspect
|
63
|
-
|
64
|
-
|
63
|
+
fields = attributes.map{ |k, v| "#{k}=#{v.inspect}" }.join(', ')
|
64
|
+
"#<struct #{self.class.name}#{if fields.empty? then '' else fields end}>"
|
65
65
|
end
|
66
66
|
|
67
67
|
def lighten! o={}
|
@@ -118,6 +118,20 @@ module RestCore::Client
|
|
118
118
|
REQUEST_QUERY => query }.merge(opts), &cb)
|
119
119
|
end
|
120
120
|
|
121
|
+
def head path, query={}, opts={}, &cb
|
122
|
+
request(
|
123
|
+
{REQUEST_METHOD => :head ,
|
124
|
+
REQUEST_PATH => path ,
|
125
|
+
REQUEST_QUERY => query }.merge(opts), &cb)
|
126
|
+
end
|
127
|
+
|
128
|
+
def options path, query={}, opts={}, &cb
|
129
|
+
request(
|
130
|
+
{REQUEST_METHOD => :options,
|
131
|
+
REQUEST_PATH => path ,
|
132
|
+
REQUEST_QUERY => query }.merge(opts), &cb)
|
133
|
+
end
|
134
|
+
|
121
135
|
def post path, payload={}, query={}, opts={}, &cb
|
122
136
|
request(
|
123
137
|
{REQUEST_METHOD => :post ,
|
@@ -134,6 +148,14 @@ module RestCore::Client
|
|
134
148
|
REQUEST_PAYLOAD => payload}.merge(opts), &cb)
|
135
149
|
end
|
136
150
|
|
151
|
+
def patch path, payload={}, query={}, opts={}, &cb
|
152
|
+
request(
|
153
|
+
{REQUEST_METHOD => :patch ,
|
154
|
+
REQUEST_PATH => path ,
|
155
|
+
REQUEST_QUERY => query ,
|
156
|
+
REQUEST_PAYLOAD => payload}.merge(opts), &cb)
|
157
|
+
end
|
158
|
+
|
137
159
|
def request env, app=app
|
138
160
|
if block_given?
|
139
161
|
request_full(env, app){ |response|
|
@@ -152,10 +174,15 @@ module RestCore::Client
|
|
152
174
|
REQUEST_PAYLOAD => {} ,
|
153
175
|
REQUEST_HEADERS => {} ,
|
154
176
|
FAIL => [] ,
|
155
|
-
LOG => []
|
177
|
+
LOG => [] ,
|
178
|
+
ASYNC => if block_given?
|
179
|
+
lambda{ |response| yield(response) }
|
180
|
+
else
|
181
|
+
nil
|
182
|
+
end}.merge(env)))
|
156
183
|
|
157
184
|
if block_given?
|
158
|
-
|
185
|
+
self
|
159
186
|
else
|
160
187
|
response
|
161
188
|
end
|
@@ -25,16 +25,34 @@ class RestCore::Cache
|
|
25
25
|
if cached = cache_get(e)
|
26
26
|
wrapped.call(cached)
|
27
27
|
else
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
if e[ASYNC]
|
29
|
+
app.call(e.merge(ASYNC => lambda{ |response|
|
30
|
+
process(e, response)
|
31
|
+
}))
|
32
32
|
else
|
33
|
-
|
33
|
+
process(e, app.call(e))
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
def process env, response
|
39
|
+
if env[ASYNC]
|
40
|
+
wrapped.call(response.merge(ASYNC => lambda{ |response_wrapped|
|
41
|
+
env[ASYNC].call(process_wrapped(env, response, response_wrapped))
|
42
|
+
}))
|
43
|
+
else
|
44
|
+
process_wrapped(env, response, wrapped.call(response))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def process_wrapped env, response, response_wrapped
|
49
|
+
if (response_wrapped[FAIL] || []).empty?
|
50
|
+
cache_for(env, response).merge(response_wrapped)
|
51
|
+
else
|
52
|
+
response_wrapped
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
38
56
|
protected
|
39
57
|
def cache_key env
|
40
58
|
Digest::MD5.hexdigest(env['cache.key'] || request_uri(env))
|
@@ -8,13 +8,23 @@ class RestCore::CommonLogger
|
|
8
8
|
|
9
9
|
def call env
|
10
10
|
start_time = Time.now
|
11
|
-
|
12
|
-
|
11
|
+
flushed = flush(env)
|
12
|
+
if env[ASYNC]
|
13
|
+
app.call(flushed.merge(ASYNC => lambda{ |response|
|
14
|
+
env[ASYNC].call(process(response, start_time))
|
15
|
+
}))
|
16
|
+
else
|
17
|
+
process(app.call(flushed), start_time)
|
18
|
+
end
|
13
19
|
rescue
|
14
|
-
|
20
|
+
process(flushed, start_time)
|
15
21
|
raise
|
16
22
|
end
|
17
23
|
|
24
|
+
def process response, start_time
|
25
|
+
flush(log(response, log_request(start_time, response)))
|
26
|
+
end
|
27
|
+
|
18
28
|
def flush env
|
19
29
|
return env if !log_method(env) || env[DRY]
|
20
30
|
(env[LOG] || []).compact.
|
@@ -6,7 +6,16 @@ class RestCore::ErrorDetector
|
|
6
6
|
include RestCore::Middleware
|
7
7
|
|
8
8
|
def call env
|
9
|
-
|
9
|
+
if env[ASYNC]
|
10
|
+
app.call(env.merge(ASYNC => lambda{ |response|
|
11
|
+
env[ASYNC].call(process(env, response))
|
12
|
+
}))
|
13
|
+
else
|
14
|
+
process(env, app.call(env))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def process env, response
|
10
19
|
detector = error_detector(env)
|
11
20
|
if error = (detector && detector.call(response))
|
12
21
|
fail(response, error)
|
@@ -6,7 +6,13 @@ class RestCore::ErrorHandler
|
|
6
6
|
include RestCore::Middleware
|
7
7
|
|
8
8
|
def call env
|
9
|
-
|
9
|
+
if env[ASYNC]
|
10
|
+
app.call(handle(env).merge(ASYNC => lambda{ |response|
|
11
|
+
env[ASYNC].call(handle(response))
|
12
|
+
}))
|
13
|
+
else
|
14
|
+
handle(app.call(handle(env)))
|
15
|
+
end
|
10
16
|
end
|
11
17
|
|
12
18
|
def handle env
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
require 'rest-core/middleware'
|
3
|
+
|
4
|
+
class RestCore::FollowRedirect
|
5
|
+
def self.members; [:max_redirects]; end
|
6
|
+
include RestCore::Middleware
|
7
|
+
|
8
|
+
def call env
|
9
|
+
e = env.merge('follow_redirect.max_redirects' =>
|
10
|
+
env['follow_redirect.max_redirects'] ||
|
11
|
+
max_redirects(env))
|
12
|
+
|
13
|
+
return app.call(e) if e[DRY]
|
14
|
+
if e[ASYNC]
|
15
|
+
app.call(e.merge(ASYNC => lambda{ |response|
|
16
|
+
e[ASYNC].call(process(response))
|
17
|
+
}))
|
18
|
+
else
|
19
|
+
process(app.call(e))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def process res
|
24
|
+
return res if res['follow_redirect.max_redirects'] <= 0
|
25
|
+
return res if ![301,302,303,307].include?(res[RESPONSE_STATUS])
|
26
|
+
return res if [301,302 ,307].include?(res[RESPONSE_STATUS]) &&
|
27
|
+
![:get, :head ].include?(res[REQUEST_METHOD])
|
28
|
+
|
29
|
+
location = [res[RESPONSE_HEADERS]['LOCATION']].flatten.first
|
30
|
+
meth = if res[RESPONSE_STATUS] == 303
|
31
|
+
:get
|
32
|
+
else
|
33
|
+
res[REQUEST_METHOD]
|
34
|
+
end
|
35
|
+
|
36
|
+
call(res.merge(REQUEST_PATH => location,
|
37
|
+
REQUEST_METHOD => meth ,
|
38
|
+
REQUEST_PAYLOAD => nil ,
|
39
|
+
'follow_redirect.max_redirects' =>
|
40
|
+
res['follow_redirect.max_redirects'] - 1))
|
41
|
+
end
|
42
|
+
end
|
@@ -7,8 +7,17 @@ class RestCore::JsonDecode
|
|
7
7
|
|
8
8
|
def call env
|
9
9
|
return app.call(env) if env[DRY]
|
10
|
-
|
11
|
-
|
10
|
+
if env[ASYNC]
|
11
|
+
app.call(env.merge(ASYNC => lambda{ |response|
|
12
|
+
env[ASYNC].call(process(response))
|
13
|
+
}))
|
14
|
+
else
|
15
|
+
process(app.call(env))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def process response
|
20
|
+
if json_decode(response)
|
12
21
|
response.merge(RESPONSE_BODY =>
|
13
22
|
self.class.json_decode("[#{response[RESPONSE_BODY]}]").first)
|
14
23
|
# [this].first is not needed for yajl-ruby
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
class RestCore::Timeout::EventMachineTimer < ::EventMachine::Timer
|
3
|
+
attr_accessor :timeout, :error
|
4
|
+
|
5
|
+
def initialize timeout, error, &block
|
6
|
+
super(timeout, &block) if block_given?
|
7
|
+
self.timeout = timeout
|
8
|
+
self.error = error
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_timeout &block
|
12
|
+
send(:initialize, timeout, error, &block)
|
13
|
+
end
|
14
|
+
end
|
@@ -8,6 +8,78 @@ class RestCore::Timeout
|
|
8
8
|
include RestCore::Middleware
|
9
9
|
|
10
10
|
def call env
|
11
|
-
|
11
|
+
return app.call(env) if env[DRY]
|
12
|
+
monitor(env){ |e| app.call(e) }
|
12
13
|
end
|
14
|
+
|
15
|
+
def monitor env
|
16
|
+
class_name = case name = run.class.to_s
|
17
|
+
when /Auto/
|
18
|
+
run.http_client.class.to_s
|
19
|
+
else
|
20
|
+
name
|
21
|
+
end
|
22
|
+
|
23
|
+
case class_name
|
24
|
+
when /Coolio|EmHttpRequest/
|
25
|
+
if root_fiber? && env[ASYNC]
|
26
|
+
yield(env.merge(TIMER => timeout_with_callback(env, class_name)))
|
27
|
+
else
|
28
|
+
yield(env.merge(TIMER => timeout_with_resume( env, class_name)))
|
29
|
+
end
|
30
|
+
else
|
31
|
+
::Timeout.timeout(timeout(env)){ yield(env) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def root_fiber?
|
36
|
+
if RestCore.const_defined?(:RootFiber)
|
37
|
+
RootFiber == Fiber.current
|
38
|
+
else
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def timeout_with_callback env, class_name
|
44
|
+
case class_name
|
45
|
+
when /Coolio/
|
46
|
+
timer = CoolioTimer.new(timeout(env))
|
47
|
+
timer.error = timeout_error
|
48
|
+
timer.attach(::Coolio::Loop.default)
|
49
|
+
timer
|
50
|
+
when /EmHttpRequest/
|
51
|
+
EventMachineTimer.new(timeout(env), timeout_error)
|
52
|
+
else
|
53
|
+
raise "BUG: #{run} is not supported"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def timeout_with_resume env, class_name
|
58
|
+
case class_name
|
59
|
+
when /Coolio/
|
60
|
+
f = Fiber.current
|
61
|
+
timer = CoolioTimer.new(timeout(env))
|
62
|
+
error = timer.error = timeout_error
|
63
|
+
timer.on_timer{ f.resume(error) if f.alive? }
|
64
|
+
timer.attach(::Coolio::Loop.default)
|
65
|
+
timer
|
66
|
+
|
67
|
+
when /EmHttpRequest/
|
68
|
+
f = Fiber.current
|
69
|
+
EventMachineTimer.new(timeout(env), error = timeout_error){
|
70
|
+
f.resume(error) if f.alive?
|
71
|
+
}
|
72
|
+
else
|
73
|
+
raise "BUG: #{run} is not supported"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def timeout_error
|
78
|
+
::Timeout::Error.new('execution expired')
|
79
|
+
end
|
80
|
+
|
81
|
+
autoload :CoolioTimer,
|
82
|
+
'rest-core/middleware/timeout/coolio_timer'
|
83
|
+
autoload :EventMachineTimer,
|
84
|
+
'rest-core/middleware/timeout/eventmachine_timer'
|
13
85
|
end
|
data/lib/rest-core/middleware.rb
CHANGED
@@ -37,6 +37,13 @@ module RestCore::Middleware
|
|
37
37
|
def call env ; app.call(env) ; end
|
38
38
|
def fail env, obj; env.merge(FAIL => (env[FAIL] || []) + [obj]); end
|
39
39
|
def log env, obj; env.merge(LOG => (env[LOG] || []) + [obj]); end
|
40
|
+
def run app=app
|
41
|
+
if app.respond_to?(:app) && app.app
|
42
|
+
run(app.app)
|
43
|
+
else
|
44
|
+
app
|
45
|
+
end
|
46
|
+
end
|
40
47
|
|
41
48
|
module_function
|
42
49
|
def request_uri env
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
module RestClient
|
3
|
+
module AbstractResponse
|
4
|
+
# begin patch
|
5
|
+
# https://github.com/archiloque/rest-client/pull/103
|
6
|
+
remove_method :to_i if method_defined?(:to_i)
|
7
|
+
# end patch
|
8
|
+
|
9
|
+
# Follow a redirection
|
10
|
+
def follow_redirection request = nil, result = nil, & block
|
11
|
+
url = headers[:location]
|
12
|
+
if url !~ /^http/
|
13
|
+
url = URI.parse(args[:url]).merge(url).to_s
|
14
|
+
end
|
15
|
+
args[:url] = url
|
16
|
+
if request
|
17
|
+
if request.max_redirects == 0
|
18
|
+
# begin patch
|
19
|
+
# https://github.com/archiloque/rest-client/pull/118
|
20
|
+
raise MaxRedirectsReached.new(self, code)
|
21
|
+
# end patch
|
22
|
+
end
|
23
|
+
args[:password] = request.password
|
24
|
+
args[:user] = request.user
|
25
|
+
args[:headers] = request.headers
|
26
|
+
args[:max_redirects] = request.max_redirects - 1
|
27
|
+
# pass any cookie set in the result
|
28
|
+
if result && result['set-cookie']
|
29
|
+
args[:headers][:cookies] = (args[:headers][:cookies] || {}).merge(parse_cookie(result['set-cookie']))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
Request.execute args, &block
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/rest-core/version.rb
CHANGED