rubylet-rack 2.0.0.pre1-java
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/MIT-LICENSE +20 -0
- data/VERSION +1 -0
- data/lib/rubylet/rack.rb +5 -0
- data/lib/rubylet/rack/dechunking_body.rb +45 -0
- data/lib/rubylet/rack/errors.rb +25 -0
- data/lib/rubylet/rack/ext.jar +0 -0
- data/lib/rubylet/rack/logger.rb +40 -0
- data/lib/rubylet/rack/mem_file_io.rb +80 -0
- data/lib/rubylet/rack/rewindable_io.rb +66 -0
- data/lib/rubylet/rack/session.rb +63 -0
- data/lib/rubylet/rack/session/container_store.rb +29 -0
- data/lib/rubylet/rack/tee_io.rb +43 -0
- data/spec/rubylet/rack/dechunking_body_spec.rb +24 -0
- data/spec/rubylet/rack/mem_file_io_spec.rb +68 -0
- data/spec/rubylet/rack/rewindable_io_spec.rb +39 -0
- data/spec/rubylet/rack/tee_io_spec.rb +75 -0
- data/spec/spec_helper.rb +5 -0
- metadata +191 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Common Ground Publishing
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0.pre1
|
data/lib/rubylet/rack.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Rubylet
|
2
|
+
module Rack
|
3
|
+
# Rails and possibly others manually set 'Transfer-Encoding:
|
4
|
+
# chunked' and then send the body as chunks. Java servlet
|
5
|
+
# environment expects the server to handle chunking as needed
|
6
|
+
# (e.g. when a response overflows the buffer and must be flushed to
|
7
|
+
# the client before the servlet has closed the stream).
|
8
|
+
#
|
9
|
+
# This class makes the rather large assumption that {body#each}
|
10
|
+
# iterates through the chunks, so we don't actually do much parsing.
|
11
|
+
#
|
12
|
+
# FIXME: ignores encoding?
|
13
|
+
class DechunkingBody
|
14
|
+
EOL = "\r\n".freeze
|
15
|
+
|
16
|
+
CHUNK_START = Regexp.compile /^((\h+)#{Regexp.quote(EOL)})/
|
17
|
+
|
18
|
+
def initialize(body)
|
19
|
+
@body = body
|
20
|
+
end
|
21
|
+
|
22
|
+
def each
|
23
|
+
@body.each do |chunk|
|
24
|
+
yield chunk_to_part(chunk)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def close
|
29
|
+
@body.close
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def chunk_to_part(chunk)
|
35
|
+
if chunk =~ CHUNK_START
|
36
|
+
chunk_start = $1.bytesize
|
37
|
+
chunk_length = $2.to_i(16)
|
38
|
+
chunk.byteslice(chunk_start, chunk_length)
|
39
|
+
else
|
40
|
+
chunk
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Implements the rack.errors interface, logging everything via
|
2
|
+
# ServletContext#log
|
3
|
+
module Rubylet
|
4
|
+
module Rack
|
5
|
+
class Errors
|
6
|
+
def initialize(context)
|
7
|
+
@context = context
|
8
|
+
end
|
9
|
+
|
10
|
+
def puts(obj)
|
11
|
+
write(obj.to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(str)
|
15
|
+
@context.log(str)
|
16
|
+
end
|
17
|
+
|
18
|
+
# A no-op for ServletContext#log
|
19
|
+
def flush; end
|
20
|
+
|
21
|
+
# Spec says this must never be called
|
22
|
+
def close; end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
Binary file
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubylet/rack/errors'
|
2
|
+
|
3
|
+
# TODO: should this wrap slf4j or something? Or is it typically overridden
|
4
|
+
# by the rack application?
|
5
|
+
module Rubylet
|
6
|
+
module Rack
|
7
|
+
class Logger < Rubylet::Errors
|
8
|
+
|
9
|
+
def info(message = nil, &block)
|
10
|
+
log(:info, message, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def debug(message = nil, &block)
|
14
|
+
log(:debug, message, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def warn(message = nil, &block)
|
18
|
+
log(:warn, message, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def error(message = nil, &block)
|
22
|
+
log(:error, message, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def fatal(message = nil, &block)
|
26
|
+
log(:fatal, message, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def log(level, message = nil, &block)
|
30
|
+
msg = if message
|
31
|
+
message
|
32
|
+
elsif block_given?
|
33
|
+
yield
|
34
|
+
end
|
35
|
+
|
36
|
+
write("#{level.to_s.upcase}: #{msg}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
# A memory/file IO buffer. Data will be written to a memory buffer up
|
4
|
+
# to a limit, after which a file buffer is used. Supports Rack input
|
5
|
+
# stream operations. Not threadsafe.
|
6
|
+
module Rubylet::Rack
|
7
|
+
class MemFileIO
|
8
|
+
DEFAULT_LIMIT = 4096 * 4
|
9
|
+
|
10
|
+
# @param [Integer] limit the max size of the first (memory) buffer
|
11
|
+
def initialize(limit = DEFAULT_LIMIT)
|
12
|
+
@limit = limit
|
13
|
+
@mem = StringIO.new
|
14
|
+
@file = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def puts(str)
|
18
|
+
for_write(str.size + $/.size).puts(str)
|
19
|
+
end
|
20
|
+
|
21
|
+
def write(str)
|
22
|
+
for_write(str.size).write(str)
|
23
|
+
end
|
24
|
+
|
25
|
+
def gets
|
26
|
+
for_read.gets
|
27
|
+
end
|
28
|
+
|
29
|
+
def read(length = nil, buffer = nil)
|
30
|
+
if buffer
|
31
|
+
for_read.read(length, buffer)
|
32
|
+
else
|
33
|
+
for_read.read(length)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def each(&block)
|
38
|
+
for_read.each(&block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def rewind
|
42
|
+
for_read.rewind
|
43
|
+
end
|
44
|
+
|
45
|
+
def close
|
46
|
+
for_read.close
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def for_read
|
52
|
+
@mem || @file
|
53
|
+
end
|
54
|
+
|
55
|
+
def switch_to_file
|
56
|
+
mem = @mem
|
57
|
+
@mem = nil
|
58
|
+
mem.rewind
|
59
|
+
@file = make_file(mem.read)
|
60
|
+
end
|
61
|
+
|
62
|
+
def for_write(size)
|
63
|
+
if @file
|
64
|
+
@file
|
65
|
+
elsif (@mem.size + size) <= @limit
|
66
|
+
@mem
|
67
|
+
else
|
68
|
+
switch_to_file
|
69
|
+
@file
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def make_file(data)
|
74
|
+
file = Tempfile.new('MemFileBacking')
|
75
|
+
file.unlink
|
76
|
+
file.write(data)
|
77
|
+
file
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rubylet/rack/tee_io'
|
2
|
+
require 'rubylet/rack/mem_file_io'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
# Wraps an IO with a memory and file backed buffer to support Rack's
|
6
|
+
# required #rewind.
|
7
|
+
#
|
8
|
+
# Only some IO methods are supported.
|
9
|
+
module Rubylet::Rack
|
10
|
+
class RewindableIO
|
11
|
+
def initialize(io, limit = MemFileIO::DEFAULT_LIMIT)
|
12
|
+
@buf = MemFileIO.new(limit)
|
13
|
+
@io = TeeIO.new(io, @buf)
|
14
|
+
end
|
15
|
+
|
16
|
+
def gets
|
17
|
+
str = @buf.gets
|
18
|
+
if str.nil? # end of buffer
|
19
|
+
@io.gets
|
20
|
+
elsif str.end_with?($/) # good, we got a whole line
|
21
|
+
str
|
22
|
+
else # partial line
|
23
|
+
str + (@io.gets || '')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def read(length = nil, buffer = nil)
|
28
|
+
if length.nil? && buffer.nil?
|
29
|
+
@buf.read + @io.read
|
30
|
+
elsif length.nil?
|
31
|
+
@buf.read(nil, buffer)
|
32
|
+
@io.read(nil, buffer)
|
33
|
+
elsif buffer.nil?
|
34
|
+
str = ''
|
35
|
+
@buf.read(length, str)
|
36
|
+
if (str.size == length)
|
37
|
+
@io.read(length - str.size, str)
|
38
|
+
end
|
39
|
+
str
|
40
|
+
else # both non-nil
|
41
|
+
size0 = buffer.size
|
42
|
+
@buf.read(length, buffer)
|
43
|
+
from_buf = buffer.size - size0
|
44
|
+
if (from_buf < length)
|
45
|
+
@io.read(length - from_buf, buffer)
|
46
|
+
end
|
47
|
+
buffer
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def each
|
52
|
+
while s = gets
|
53
|
+
yield s
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def rewind
|
58
|
+
@buf.rewind
|
59
|
+
end
|
60
|
+
|
61
|
+
def close
|
62
|
+
@buf.close
|
63
|
+
@io.close
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# A Rack compatible session object that forwards to an underlying
|
2
|
+
# +javax.servlet.http.HttpSession+.
|
3
|
+
module Rubylet; module Rack
|
4
|
+
class Session
|
5
|
+
# @param [javax.servlet.http.HttpServletRequest] req
|
6
|
+
# @param [Hash] options
|
7
|
+
# @option options [Integer] :expire_after The max inactive interval, in seconds
|
8
|
+
def initialize(req, options={})
|
9
|
+
@javaSession = req.getSession
|
10
|
+
|
11
|
+
if @javaSession.isNew
|
12
|
+
if exp = options[:expire_after]
|
13
|
+
req.setMaxInactiveInterval exp.to_i
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def store(key, value)
|
19
|
+
@javaSession.setAttribute(key, value)
|
20
|
+
end
|
21
|
+
alias_method :[]=, :store
|
22
|
+
|
23
|
+
def fetch(key, default = nil)
|
24
|
+
@javaSession.getAttribute(key) || default
|
25
|
+
end
|
26
|
+
alias_method :[], :fetch
|
27
|
+
|
28
|
+
def delete(key)
|
29
|
+
@javaSession.removeAttribute(key)
|
30
|
+
end
|
31
|
+
|
32
|
+
def clear
|
33
|
+
@javaSession.getAttributeNames.each {|key| delete(key) }
|
34
|
+
end
|
35
|
+
|
36
|
+
# This method is not required by the Rack SPEC for session
|
37
|
+
# objects, but Rails calls it anyway in +actionpack (3.2.9)
|
38
|
+
# lib/action_dispatch/middleware/flash.rb:258:in `call'+
|
39
|
+
def has_key?(key)
|
40
|
+
!(fetch(key).nil?)
|
41
|
+
end
|
42
|
+
alias_method :include?, :has_key?
|
43
|
+
alias_method :key?, :has_key?
|
44
|
+
alias_method :member?, :has_key?
|
45
|
+
|
46
|
+
# Used by Rails but not required by Rack.
|
47
|
+
def destroy
|
48
|
+
@javaSession.invalidate
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_hash
|
52
|
+
hash = {}
|
53
|
+
@javaSession.getAttributeNames.each do
|
54
|
+
|key| hash[key] = @javaSession.getAttribute(key)
|
55
|
+
end
|
56
|
+
hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def inspect
|
60
|
+
to_hash.inspect
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end; end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubylet/rack/session'
|
2
|
+
|
3
|
+
# Rack middleware to make the servlet container's sessions available to ruby.
|
4
|
+
module Rubylet
|
5
|
+
module Rack
|
6
|
+
class Session
|
7
|
+
class ContainerStore
|
8
|
+
def initialize(app, options={})
|
9
|
+
@app = app
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
context(env)
|
15
|
+
end
|
16
|
+
|
17
|
+
# For Rack::Util::Context
|
18
|
+
def context(env, app=@app)
|
19
|
+
if req = env['java.servlet_request']
|
20
|
+
env['rack.session'] = Session.new(req, @options)
|
21
|
+
else
|
22
|
+
env['rack.errors'].puts 'java.servlet_request not found; cannot make session'
|
23
|
+
end
|
24
|
+
app.call(env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# All reads on +io+ are copied to +out+. Only supports IO methods
|
2
|
+
# specified by Rack Input Stream spec.
|
3
|
+
module Rubylet::Rack
|
4
|
+
class TeeIO
|
5
|
+
def initialize(io, out)
|
6
|
+
@io = io
|
7
|
+
@out = out
|
8
|
+
end
|
9
|
+
|
10
|
+
# Does not support custom separator per Rack spec
|
11
|
+
def gets
|
12
|
+
str = @io.gets
|
13
|
+
@out.write(str) if str
|
14
|
+
str
|
15
|
+
end
|
16
|
+
|
17
|
+
def read(length = nil, buffer = nil)
|
18
|
+
str = ''
|
19
|
+
ret = @io.read(length, str)
|
20
|
+
@out.write(str)
|
21
|
+
if buffer
|
22
|
+
buffer << str
|
23
|
+
if ret.object_id == str.object_id
|
24
|
+
buffer
|
25
|
+
else
|
26
|
+
ret
|
27
|
+
end
|
28
|
+
else
|
29
|
+
ret
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def each
|
34
|
+
while s = gets
|
35
|
+
yield s
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def close
|
40
|
+
@io.close
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rubylet/rack/dechunking_body'
|
3
|
+
|
4
|
+
module Rubylet::Rack
|
5
|
+
describe DechunkingBody do
|
6
|
+
def chunk(strs)
|
7
|
+
strs.map do |str|
|
8
|
+
str.bytesize.to_s(16) + "\r\n" + str + "\r\n"
|
9
|
+
end + ["0\r\n\r\n"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def dechunk(body)
|
13
|
+
''.tap do |str|
|
14
|
+
DechunkingBody.new(body).each { |part| str << part }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'de-chunks a chunked body' do
|
19
|
+
data = ["some", "data", "\n in chunks."]
|
20
|
+
expected = data.join
|
21
|
+
assert_equal expected, dechunk(chunk(data))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rubylet/rack/mem_file_io'
|
3
|
+
|
4
|
+
module Rubylet::Rack
|
5
|
+
|
6
|
+
describe MemFileIO do
|
7
|
+
|
8
|
+
it 'writes data with puts' do
|
9
|
+
@io = MemFileIO.new
|
10
|
+
@io.puts('hello')
|
11
|
+
@io.rewind
|
12
|
+
@io.read.must_equal "hello#{$/}"
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'writes data with write' do
|
16
|
+
@io = MemFileIO.new
|
17
|
+
@io.write('hello')
|
18
|
+
@io.rewind
|
19
|
+
@io.read.must_equal 'hello'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'allows multiple rewind' do
|
23
|
+
@io = MemFileIO.new
|
24
|
+
|
25
|
+
@io.write('hello')
|
26
|
+
@io.rewind
|
27
|
+
@io.read.must_equal 'hello'
|
28
|
+
|
29
|
+
@io.write('hello')
|
30
|
+
@io.rewind
|
31
|
+
@io.read.must_equal 'hellohello'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'overwrites? (FIXME: is this correct?)' do
|
35
|
+
@io = MemFileIO.new
|
36
|
+
|
37
|
+
@io.write('hello')
|
38
|
+
@io.rewind
|
39
|
+
@io.read.must_equal 'hello'
|
40
|
+
|
41
|
+
@io.rewind
|
42
|
+
@io.write('***')
|
43
|
+
@io.rewind
|
44
|
+
@io.read.must_equal '***lo'
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'switches to backing file' do
|
48
|
+
@io = MemFileIO.new(4)
|
49
|
+
@io.write('1234')
|
50
|
+
@io.write('5678')
|
51
|
+
@io.rewind
|
52
|
+
@io.read.must_equal '12345678'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'returns nil on EOF' do
|
56
|
+
@io = MemFileIO.new
|
57
|
+
@io.read
|
58
|
+
@io.read(1).must_equal nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns empty string on EOF' do
|
62
|
+
@io = MemFileIO.new
|
63
|
+
@io.read
|
64
|
+
@io.read.must_equal ''
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rubylet/rack/rewindable_io'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module Rubylet::Rack
|
6
|
+
|
7
|
+
describe RewindableIO do
|
8
|
+
|
9
|
+
data = "some data\nwith newlines\nanother line"
|
10
|
+
|
11
|
+
before :each do
|
12
|
+
@io = StringIO.new
|
13
|
+
@io.write(data)
|
14
|
+
@io.rewind
|
15
|
+
|
16
|
+
@reio = RewindableIO.new(@io)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'rewinds' do
|
20
|
+
@reio.read.must_equal data
|
21
|
+
@reio.rewind
|
22
|
+
@reio.read.must_equal data
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'rewinds with file spill over' do
|
26
|
+
expected = ''
|
27
|
+
10.times do
|
28
|
+
@io.write(data)
|
29
|
+
expected << data
|
30
|
+
end
|
31
|
+
@io.rewind
|
32
|
+
|
33
|
+
@reio = RewindableIO.new(@io, 32)
|
34
|
+
@reio.read.must_equal expected
|
35
|
+
@reio.rewind
|
36
|
+
@reio.read.must_equal expected
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rubylet/rack/tee_io'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module Rubylet::Rack
|
6
|
+
|
7
|
+
describe TeeIO do
|
8
|
+
|
9
|
+
DATA = "some data\nwith newlines\nanother line"
|
10
|
+
|
11
|
+
before :each do
|
12
|
+
@io = StringIO.new
|
13
|
+
@io.write(DATA)
|
14
|
+
@io.rewind
|
15
|
+
|
16
|
+
@out = StringIO.new
|
17
|
+
|
18
|
+
@tee = TeeIO.new(@io, @out)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'copies data on read' do
|
22
|
+
@tee.read
|
23
|
+
@out.rewind
|
24
|
+
@out.read.must_equal DATA
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#gets' do
|
28
|
+
it 'copies data on gets' do
|
29
|
+
@tee.gets
|
30
|
+
@out.rewind
|
31
|
+
@out.read.must_equal "some data\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'returns nil on EOF' do
|
35
|
+
@tee.read
|
36
|
+
@tee.gets.must_equal nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'copies data on each' do
|
41
|
+
@tee.each {}
|
42
|
+
@out.rewind
|
43
|
+
@out.read.must_equal DATA
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'copies data byte by byte' do
|
47
|
+
@tee.read(1)
|
48
|
+
@tee.read(1)
|
49
|
+
@out.rewind
|
50
|
+
@out.read.must_equal 'so'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'reads data into a given buffer' do
|
54
|
+
buf = String.new
|
55
|
+
ret = @tee.read nil, buf
|
56
|
+
|
57
|
+
ret.object_id.must_equal buf.object_id
|
58
|
+
|
59
|
+
buf.must_equal DATA
|
60
|
+
@out.rewind
|
61
|
+
@out.read.must_equal DATA
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns nil on EOF' do
|
65
|
+
@tee.read
|
66
|
+
@tee.read(1).must_equal nil
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'returns empty string on EOF' do
|
70
|
+
@tee.read
|
71
|
+
@tee.read.must_equal ''
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubylet-rack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: 6
|
5
|
+
version: 2.0.0.pre1
|
6
|
+
platform: java
|
7
|
+
authors:
|
8
|
+
- Patrick Mahoney
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rack
|
16
|
+
version_requirements: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: !binary |-
|
21
|
+
MA==
|
22
|
+
none: false
|
23
|
+
requirement: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: !binary |-
|
28
|
+
MA==
|
29
|
+
none: false
|
30
|
+
prerelease: false
|
31
|
+
type: :runtime
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: mechanize
|
34
|
+
version_requirements: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: !binary |-
|
39
|
+
MA==
|
40
|
+
none: false
|
41
|
+
requirement: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: !binary |-
|
46
|
+
MA==
|
47
|
+
none: false
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: mini_aether
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: !binary |-
|
57
|
+
MA==
|
58
|
+
none: false
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: !binary |-
|
64
|
+
MA==
|
65
|
+
none: false
|
66
|
+
prerelease: false
|
67
|
+
type: :development
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: minitest-matchers
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: !binary |-
|
75
|
+
MA==
|
76
|
+
none: false
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: !binary |-
|
82
|
+
MA==
|
83
|
+
none: false
|
84
|
+
prerelease: false
|
85
|
+
type: :development
|
86
|
+
- !ruby/object:Gem::Dependency
|
87
|
+
name: rake
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: !binary |-
|
93
|
+
MA==
|
94
|
+
none: false
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: !binary |-
|
100
|
+
MA==
|
101
|
+
none: false
|
102
|
+
prerelease: false
|
103
|
+
type: :development
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: unf
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "<="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.0.5
|
111
|
+
none: false
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "<="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 0.0.5
|
117
|
+
none: false
|
118
|
+
prerelease: false
|
119
|
+
type: :development
|
120
|
+
- !ruby/object:Gem::Dependency
|
121
|
+
name: version
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - "~>"
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: !binary |-
|
127
|
+
MQ==
|
128
|
+
none: false
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: !binary |-
|
134
|
+
MQ==
|
135
|
+
none: false
|
136
|
+
prerelease: false
|
137
|
+
type: :development
|
138
|
+
description: Java Servlet implementation that forwards to Rack application
|
139
|
+
email:
|
140
|
+
- pat@polycrystal.org
|
141
|
+
executables: []
|
142
|
+
extensions: []
|
143
|
+
extra_rdoc_files: []
|
144
|
+
files:
|
145
|
+
- VERSION
|
146
|
+
- MIT-LICENSE
|
147
|
+
- lib/rubylet/rack/ext.jar
|
148
|
+
- lib/rubylet/rack.rb
|
149
|
+
- lib/rubylet/rack/dechunking_body.rb
|
150
|
+
- lib/rubylet/rack/errors.rb
|
151
|
+
- lib/rubylet/rack/logger.rb
|
152
|
+
- lib/rubylet/rack/mem_file_io.rb
|
153
|
+
- lib/rubylet/rack/rewindable_io.rb
|
154
|
+
- lib/rubylet/rack/session.rb
|
155
|
+
- lib/rubylet/rack/tee_io.rb
|
156
|
+
- lib/rubylet/rack/session/container_store.rb
|
157
|
+
- spec/spec_helper.rb
|
158
|
+
- spec/rubylet/rack/dechunking_body_spec.rb
|
159
|
+
- spec/rubylet/rack/mem_file_io_spec.rb
|
160
|
+
- spec/rubylet/rack/rewindable_io_spec.rb
|
161
|
+
- spec/rubylet/rack/tee_io_spec.rb
|
162
|
+
homepage:
|
163
|
+
licenses: []
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
require_paths:
|
167
|
+
- lib
|
168
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
segments:
|
173
|
+
- 0
|
174
|
+
hash: 2
|
175
|
+
version: !binary |-
|
176
|
+
MA==
|
177
|
+
none: false
|
178
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - !binary |-
|
181
|
+
Pg==
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: 1.3.1
|
184
|
+
none: false
|
185
|
+
requirements: []
|
186
|
+
rubyforge_project:
|
187
|
+
rubygems_version: 1.8.24
|
188
|
+
signing_key:
|
189
|
+
specification_version: 3
|
190
|
+
summary: Java Servlet implementation that forwards to Rack application
|
191
|
+
test_files: []
|