async-rack 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/async_rack.rb +9 -2
- data/lib/async_rack/runtime.rb +2 -2
- data/lib/async_rack/session/cookie.rb +2 -2
- data/lib/async_rack/session/memcache.rb +2 -2
- data/lib/async_rack/session/pool.rb +2 -2
- data/lib/rack/async.rb +26 -0
- data/lib/rack/async/autoload_hook.rb +33 -0
- data/lib/rack/async/conditional_get.rb +12 -0
- data/lib/rack/async/lint.rb +22 -0
- data/lib/rack/async/original.rb +28 -0
- data/lib/rack/async/wrapper.rb +22 -0
- data/lib/rack/replaceable_response.rb +25 -0
- data/spec/spec_conditional_get_sync.rb +39 -0
- metadata +12 -4
data/lib/async_rack.rb
CHANGED
@@ -13,10 +13,17 @@ module AsyncRack
|
|
13
13
|
module ExtensionMixin
|
14
14
|
::AsyncRack.extend self
|
15
15
|
def autoload(class_name, path)
|
16
|
-
|
16
|
+
mod = Rack
|
17
|
+
mod_path = self.name.split("::")
|
18
|
+
mod_path.shift
|
19
|
+
while (mod_ = mod_path.shift)
|
20
|
+
mod = mod.const_get(mod_.to_sym)
|
21
|
+
end
|
22
|
+
# already loaded ? override.
|
23
|
+
if mod.autoload?(class_name) == nil
|
17
24
|
require path
|
18
25
|
else
|
19
|
-
|
26
|
+
mod.autoload class_name, path
|
20
27
|
super
|
21
28
|
end
|
22
29
|
end
|
data/lib/async_rack/runtime.rb
CHANGED
@@ -4,9 +4,9 @@ module AsyncRack
|
|
4
4
|
class Runtime < AsyncCallback(:Runtime)
|
5
5
|
def async_callback(result)
|
6
6
|
status, headers, body =result
|
7
|
-
request_time = Time.now - start_time
|
7
|
+
request_time = Time.now - @start_time
|
8
8
|
headers[@header_name] = "%0.6f" % request_time if !headers.has_key?(@header_name)
|
9
|
-
[status, headers, body]
|
9
|
+
super [status, headers, body]
|
10
10
|
end
|
11
11
|
|
12
12
|
def call(env)
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require "rack/cookie"
|
1
|
+
require "rack/session/cookie"
|
2
2
|
|
3
3
|
module AsyncRack
|
4
4
|
module Session
|
5
|
-
class Cookie < AsyncCallback(:Cookie, Rack::Session)
|
5
|
+
class Cookie < AsyncRack::AsyncCallback(:Cookie, Rack::Session)
|
6
6
|
def async_callback(result)
|
7
7
|
super commit_session(env, *result)
|
8
8
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require "rack/memcache"
|
1
|
+
require "rack/session/memcache"
|
2
2
|
|
3
3
|
module AsyncRack
|
4
4
|
module Session
|
5
|
-
class Memcache < AsyncCallback(:Memcache, Rack::Session)
|
5
|
+
class Memcache < AsyncRack::AsyncCallback(:Memcache, Rack::Session)
|
6
6
|
def async_callback(result)
|
7
7
|
super commit_session(env, *result)
|
8
8
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require "rack/pool"
|
1
|
+
require "rack/session/pool"
|
2
2
|
|
3
3
|
module AsyncRack
|
4
4
|
module Session
|
5
|
-
class Pool < AsyncCallback(:Pool, Rack::Session)
|
5
|
+
class Pool < AsyncRack::AsyncCallback(:Pool, Rack::Session)
|
6
6
|
def async_callback(result)
|
7
7
|
super commit_session(env, *result)
|
8
8
|
end
|
data/lib/rack/async.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
fail 'Rack version mismatch' if release != '1.2'
|
5
|
+
ASYNC_RESPONSE = [-1, {}, []].freeze
|
6
|
+
|
7
|
+
module Async
|
8
|
+
# Tools used to wrap sync middleware
|
9
|
+
autoload :AutoloadHook, 'rack/async/autoload_hook'
|
10
|
+
autoload :Original, 'rack/async/original'
|
11
|
+
autoload :Wrapper, 'rack/async/wrapper'
|
12
|
+
end
|
13
|
+
|
14
|
+
extend Async::AutoloadHook
|
15
|
+
|
16
|
+
# Wrapped middleware
|
17
|
+
autoload :ConditionalGet, 'rack/async/conditional_get'
|
18
|
+
autoload :Lint, 'rack/async/lint'
|
19
|
+
|
20
|
+
# New middleware
|
21
|
+
autoload :ReplaceableResponse, 'rack/replaceable_response'
|
22
|
+
|
23
|
+
module Session
|
24
|
+
extend Async::AutoloadHook
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Rack
|
2
|
+
module Async
|
3
|
+
module AutoloadHook
|
4
|
+
##
|
5
|
+
# Hooks into Rack.autoload to allow replacing already defined autoload
|
6
|
+
# paths with the paths to the async counterparts but avoids accidentally
|
7
|
+
# overwriting them with the old paths, for instance if Rack::Reloader is
|
8
|
+
# used.
|
9
|
+
#
|
10
|
+
# If the middleware is already loaded, +require+ the counterpart.
|
11
|
+
def autoload(const_name, path)
|
12
|
+
if const_defined?(const_name) and not autoload?(const_name)
|
13
|
+
require path
|
14
|
+
elsif autoload?(const_name) !~ /^rack\/async/
|
15
|
+
@autoloaded = false
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Module#autoload is not thread-safe.
|
22
|
+
# Use Rack.autoload! to preload all middleware in order to avoid race conditions.
|
23
|
+
def autoload!
|
24
|
+
return if @autoloaded
|
25
|
+
@autoloaded = true
|
26
|
+
constants.each do |const_name|
|
27
|
+
const = const_get(const_name)
|
28
|
+
const.autoload! if const.respond_to? :autoload!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rack/lint'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Async
|
5
|
+
class Lint < Original::Lint
|
6
|
+
def check_status(status) super unless status.to_i < 0 end
|
7
|
+
def check_content_type(status, headers) super unless status.to_i < 0 end
|
8
|
+
def check_content_length(status, headers) super unless status.to_i < 0 end
|
9
|
+
|
10
|
+
def _call(env)
|
11
|
+
status, *rest = catch(:async) { super } || ASYNC_RESPONSE
|
12
|
+
assert "async response detected without the handler supporting async.callback" do
|
13
|
+
status.to_i < 0 and not env.include?('async.callback')
|
14
|
+
end
|
15
|
+
[status, *rest]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
const_remove :Lint
|
21
|
+
Lint = Async::Lint
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rack
|
2
|
+
module Session; end
|
3
|
+
module Async
|
4
|
+
##
|
5
|
+
# This module is used as a bucket to keep a reference
|
6
|
+
# to old middleware in case it was replaced by a new implementation.
|
7
|
+
#
|
8
|
+
# Rack::Foo might get replaced by Rack::Async::Foo. The old Rack::Foo
|
9
|
+
# is still accessable as Rack::Original::Foo, if Rack::Async::Foo is
|
10
|
+
# subclassing it (recommended).
|
11
|
+
module Original
|
12
|
+
module Store
|
13
|
+
attr_accessor :base
|
14
|
+
def const_missing(name)
|
15
|
+
const_set name, base.const_get(name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
extend Store
|
20
|
+
self.base = ::Rack
|
21
|
+
|
22
|
+
module Session
|
23
|
+
extend Store
|
24
|
+
self.base = ::Rack::Session
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Rack
|
2
|
+
module Async
|
3
|
+
module Wrapper
|
4
|
+
def initialize(app, *args, &block)
|
5
|
+
super(CachedResponse.new(app), *args, &block)
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
return super unless callback = env['async.callback']
|
10
|
+
env['async.callback'] = proc do |result|
|
11
|
+
app.set_response_for(env, result)
|
12
|
+
async_call(env)
|
13
|
+
end
|
14
|
+
catch(:async) { super } || ASYNC_RESPONSE
|
15
|
+
end
|
16
|
+
|
17
|
+
def async_call(env)
|
18
|
+
call(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rack
|
2
|
+
##
|
3
|
+
# Middleware that allows setting a predefined response for a request.
|
4
|
+
# If response is set, it will be returned instead of handing env on to
|
5
|
+
# the next middleware/endpoint. Response is stored in env, so it will be
|
6
|
+
# eaten by the GC as soon as possible.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class Wrapper < Wrapped
|
10
|
+
# def call(env)
|
11
|
+
# @app.response_for(env, some_response) if some_condition
|
12
|
+
# super
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# use Wrapper
|
17
|
+
# use ReplaceableResponse
|
18
|
+
# run SomeApp
|
19
|
+
class ReplaceableResponse
|
20
|
+
def initialize(app) @app = app end
|
21
|
+
def response_for(env, result = nil) (env['cached.responses'] ||= {})[self] = result end
|
22
|
+
def call(env) response_for(env) or @app.call(env) end
|
23
|
+
alias set_response_for response_for
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'rack/async'
|
3
|
+
require 'rack/mock'
|
4
|
+
|
5
|
+
describe Rack::ConditionalGet do
|
6
|
+
should "set a 304 status and truncate body when If-Modified-Since hits" do
|
7
|
+
timestamp = Time.now.httpdate
|
8
|
+
app = Rack::ConditionalGet.new(lambda { |env|
|
9
|
+
[200, {'Last-Modified'=>timestamp}, ['TEST']] })
|
10
|
+
|
11
|
+
response = Rack::MockRequest.new(app).
|
12
|
+
get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp)
|
13
|
+
|
14
|
+
response.status.should.equal 304
|
15
|
+
response.body.should.be.empty
|
16
|
+
end
|
17
|
+
|
18
|
+
should "set a 304 status and truncate body when If-None-Match hits" do
|
19
|
+
app = Rack::ConditionalGet.new(lambda { |env|
|
20
|
+
[200, {'Etag'=>'1234'}, ['TEST']] })
|
21
|
+
|
22
|
+
response = Rack::MockRequest.new(app).
|
23
|
+
get("/", 'HTTP_IF_NONE_MATCH' => '1234')
|
24
|
+
|
25
|
+
response.status.should.equal 304
|
26
|
+
response.body.should.be.empty
|
27
|
+
end
|
28
|
+
|
29
|
+
should "not affect non-GET/HEAD requests" do
|
30
|
+
app = Rack::ConditionalGet.new(lambda { |env|
|
31
|
+
[200, {'Etag'=>'1234'}, ['TEST']] })
|
32
|
+
|
33
|
+
response = Rack::MockRequest.new(app).
|
34
|
+
post("/", 'HTTP_IF_NONE_MATCH' => '1234')
|
35
|
+
|
36
|
+
response.status.should.equal 200
|
37
|
+
response.body.should.equal 'TEST'
|
38
|
+
end
|
39
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-rack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 9
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 0.5.
|
9
|
+
- 1
|
10
|
+
version: 0.5.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Konstantin Haase
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-02-07 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -79,7 +79,15 @@ files:
|
|
79
79
|
- lib/async_rack/showstatus.rb
|
80
80
|
- lib/async_rack/throw_async.rb
|
81
81
|
- lib/async_rack.rb
|
82
|
+
- lib/rack/async/autoload_hook.rb
|
83
|
+
- lib/rack/async/conditional_get.rb
|
84
|
+
- lib/rack/async/lint.rb
|
85
|
+
- lib/rack/async/original.rb
|
86
|
+
- lib/rack/async/wrapper.rb
|
87
|
+
- lib/rack/async.rb
|
88
|
+
- lib/rack/replaceable_response.rb
|
82
89
|
- spec/async_rack/async_callback_spec.rb
|
90
|
+
- spec/spec_conditional_get_sync.rb
|
83
91
|
- spec/spec_helper.rb
|
84
92
|
- README.md
|
85
93
|
- LICENSE
|