rest-core 0.8.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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