async-rack 0.5.0 → 0.5.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/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
|