jubilee 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.rbenv-version +1 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +54 -0
- data/Guardfile +24 -0
- data/README.md +61 -0
- data/Rakefile +94 -0
- data/VERSION +1 -0
- data/bin/jubilee +6 -0
- data/bin/jubilee_d +10 -0
- data/examples/jubilee/keystore.jks +0 -0
- data/examples/jubilee/server-keystore.jks +0 -0
- data/examples/ssl/ServerTest.java +19 -0
- data/examples/ssl/webroot/index.html +10 -0
- data/jars/netty-3.6.0.Beta1.jar +0 -0
- data/jars/vertx-core-1.3.0.final.jar +0 -0
- data/java/.idea/ant.xml +7 -0
- data/java/.idea/libraries/jruby.xml +9 -0
- data/java/.idea/libraries/netty_3_6_0_Beta1.xml +9 -0
- data/java/.idea/libraries/vertx_core_1_3_0_final.xml +9 -0
- data/java/src/jubilee/JubileeService.java +21 -0
- data/java/src/org/jruby/jubilee/Const.java +148 -0
- data/java/src/org/jruby/jubilee/RackApplication.java +78 -0
- data/java/src/org/jruby/jubilee/RackEnvironment.java +13 -0
- data/java/src/org/jruby/jubilee/RackErrors.java +44 -0
- data/java/src/org/jruby/jubilee/RackInput.java +62 -0
- data/java/src/org/jruby/jubilee/RackResponse.java +16 -0
- data/java/src/org/jruby/jubilee/Server.java +104 -0
- data/java/src/org/jruby/jubilee/deploy/Starter.java +26 -0
- data/java/src/org/jruby/jubilee/impl/DefaultRackEnvironment.java +98 -0
- data/java/src/org/jruby/jubilee/impl/NullIO.java +111 -0
- data/java/src/org/jruby/jubilee/impl/RubyIORackErrors.java +68 -0
- data/java/src/org/jruby/jubilee/impl/RubyIORackInput.java +164 -0
- data/lib/jubilee.rb +11 -0
- data/lib/jubilee/application.rb +13 -0
- data/lib/jubilee/cli.rb +74 -0
- data/lib/jubilee/configuration.rb +52 -0
- data/lib/jubilee/const.rb +39 -0
- data/lib/jubilee/jubilee.jar +0 -0
- data/lib/jubilee/response.rb +64 -0
- data/lib/jubilee/server.rb +16 -0
- data/lib/rack/handler/jubilee.rb +43 -0
- data/test/.rbenv-version +1 -0
- data/test/config/app.rb +5 -0
- data/test/jubilee/test_cli.rb +11 -0
- data/test/jubilee/test_config.rb +14 -0
- data/test/jubilee/test_persistent.rb +238 -0
- data/test/jubilee/test_rack_server.rb +116 -0
- data/test/jubilee/test_server.rb +68 -0
- data/test/sinatra_app/app.rb +31 -0
- data/test/sinatra_app/config.ru +6 -0
- data/test/sinatra_app/public/test.html +10 -0
- data/test/sinatra_app/unicorn.conf.rb +29 -0
- data/test/test_helper.rb +21 -0
- metadata +160 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
module Jubilee
|
2
|
+
module Const
|
3
|
+
JUBILEE_VERSION = VERSION = "0.1.0".freeze
|
4
|
+
HTTP_11 = "HTTP/1.1".freeze
|
5
|
+
HTTP_10 = "HTTP/1.0".freeze
|
6
|
+
|
7
|
+
SERVER_SOFTWARE = "SERVER_SOFTWARE".freeze
|
8
|
+
SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
|
9
|
+
GATEWAY_INTERFACE = "GATEWAY_INTERFACE".freeze
|
10
|
+
SERVER_NAME = "SERVER_NAME".freeze
|
11
|
+
SERVER_PORT = "SERVER_PORT".freeze
|
12
|
+
|
13
|
+
CGI_VER = "CGI/1.2".freeze
|
14
|
+
|
15
|
+
RACK_INPUT = "rack.input".freeze
|
16
|
+
|
17
|
+
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
18
|
+
GET = 'GET'.freeze
|
19
|
+
POST = "POST".freeze
|
20
|
+
REQUEST_PATH = "REQUEST_PATH".freeze
|
21
|
+
REQUEST_URI = "REQUEST_URI".freeze
|
22
|
+
PATH_INFO = "PATH_INFO".freeze
|
23
|
+
QUERY_STRING = "QUERY_STRING".freeze
|
24
|
+
|
25
|
+
CONTENT_LENGTH = "Content-Length".freeze
|
26
|
+
TRANSFER_ENCODING = "Transfer-Encoding".freeze
|
27
|
+
|
28
|
+
HTTP_VERSION = "HTTP_VERSION".freeze
|
29
|
+
HTTP_HOST = "HTTP_HOST".freeze
|
30
|
+
HTTP_USER_AGENT = "HTTP_USER_AGENT".freeze
|
31
|
+
HTTP_ACCEPT = "HTTP_ACCEPT".freeze
|
32
|
+
HTTP_COOKIE = "HTTP_COOKIE".freeze
|
33
|
+
HTTP_ACCEPT_LANGUAGE = "HTTP_ACCEPT_LANGUAGE".freeze
|
34
|
+
HTTP_ACCEPT_ENCODING = "HTTP_ACCEPT_ENCODING".freeze
|
35
|
+
HTTP_CONNECTION = "HTTP_CONNECTION".freeze
|
36
|
+
|
37
|
+
STATUS_WITH_NO_ENTITY_BODY = Hash[Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.map{|s| [s, true]}]
|
38
|
+
end
|
39
|
+
end
|
Binary file
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'java'
|
2
|
+
module Jubilee
|
3
|
+
class Response
|
4
|
+
include Const
|
5
|
+
include org.jruby.jubilee.RackResponse
|
6
|
+
|
7
|
+
def initialize(array)
|
8
|
+
@status, @headers, @body = *array
|
9
|
+
@content_length = nil
|
10
|
+
if @body.kind_of? Array and @body.size == 1
|
11
|
+
@content_length = @body[0].bytesize
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def respond(response)
|
16
|
+
no_body = @status < 200 || STATUS_WITH_NO_ENTITY_BODY[@status]
|
17
|
+
write_status(response)
|
18
|
+
write_headers(response)
|
19
|
+
if no_body
|
20
|
+
response.end
|
21
|
+
else
|
22
|
+
if @body.respond_to?(:to_path)
|
23
|
+
response.sendFile(@body.to_path)
|
24
|
+
else
|
25
|
+
write_body(response)
|
26
|
+
response.end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
ensure
|
30
|
+
@body.close if @body.respond_to?(:close)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def write_status(response)
|
35
|
+
response.statusCode = @status
|
36
|
+
end
|
37
|
+
|
38
|
+
def write_headers(response)
|
39
|
+
@headers.each do |key, value|
|
40
|
+
case key
|
41
|
+
when CONTENT_LENGTH
|
42
|
+
@content_length = value
|
43
|
+
next
|
44
|
+
when TRANSFER_ENCODING
|
45
|
+
@allow_chunked = false
|
46
|
+
@content_length = nil
|
47
|
+
end
|
48
|
+
response.putHeader(key, value)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def write_body(response)
|
53
|
+
if @content_length
|
54
|
+
response.putHeader(CONTENT_LENGTH, @content_length.to_s)
|
55
|
+
else
|
56
|
+
response.setChunked(true)
|
57
|
+
end
|
58
|
+
|
59
|
+
@body.each do |part|
|
60
|
+
response.write(part)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Jubilee
|
2
|
+
class Server < VertxServer
|
3
|
+
def initialize(app, opts = {})
|
4
|
+
options = {port: 3215, ssl: false}.merge(opts)
|
5
|
+
if (options[:ssl])
|
6
|
+
if options[:keystore].nil?
|
7
|
+
raise ArgumentError, "Please provide a keystore for ssl"
|
8
|
+
else
|
9
|
+
super(Application.new(app), options[:port], options[:ssl], options[:keystore], options[:keystore_password])
|
10
|
+
end
|
11
|
+
else
|
12
|
+
super(Application.new(app), options[:port])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rack/handler'
|
2
|
+
require 'jubilee'
|
3
|
+
require 'java'
|
4
|
+
|
5
|
+
module Rack
|
6
|
+
module Handler
|
7
|
+
module Jubilee
|
8
|
+
DEFAULT_OPTIONS = {
|
9
|
+
:host => '0.0.0.0',
|
10
|
+
:port => 3000,
|
11
|
+
:verbose => false
|
12
|
+
}
|
13
|
+
def self.run(app, options = {})
|
14
|
+
options = DEFAULT_OPTIONS.merge(options)
|
15
|
+
|
16
|
+
if options[:verbose]
|
17
|
+
app = Rack::CommonLogger.new(app, STDOUT)
|
18
|
+
end
|
19
|
+
|
20
|
+
if options[:environment]
|
21
|
+
ENV["RACK_ENV"] = options[:environment].to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
@server = ::Jubilee::Server.new(app, options)
|
25
|
+
|
26
|
+
puts "Jubilee starting..."
|
27
|
+
puts "Environment: #{ENV['RACK_ENV']}"
|
28
|
+
|
29
|
+
yield @server if block_given?
|
30
|
+
|
31
|
+
@server.start
|
32
|
+
@starter = org.jruby.jubilee.deploy.Starter.new
|
33
|
+
@starter.block
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.shutdown
|
37
|
+
@server.stop{ @starter.unblock }
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
end
|
41
|
+
register :jubilee, Jubilee
|
42
|
+
end
|
43
|
+
end
|
data/test/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
jruby-1.7.0
|
data/test/config/app.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'jubilee/cli'
|
3
|
+
|
4
|
+
class TestJubileeCLI < MiniTest::Unit::TestCase
|
5
|
+
def test_parse_options
|
6
|
+
cli = Jubilee::CLI.new(["app.rb"])
|
7
|
+
cli.parse_options
|
8
|
+
assert_equal "app.rb", cli.options[:rackup]
|
9
|
+
assert_equal 3215, cli.options[:port]
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'jubilee/configuration'
|
3
|
+
|
4
|
+
class TestConfig < MiniTest::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@config = Jubilee::Configuration.new({rackup: "config/app.rb"})
|
7
|
+
end
|
8
|
+
def test_load
|
9
|
+
@config.load
|
10
|
+
resp = [200, {"Content-Type" => "text/plain"}, ["embeded app"]]
|
11
|
+
skip "hard to test because of Rack::Lint"
|
12
|
+
#assert_equal resp, @config.app.call({})
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'timeout'
|
3
|
+
require 'socket'
|
4
|
+
class TestPersistent < MiniTest::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@valid_request = "GET / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
|
7
|
+
@close_request = "GET / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n"
|
8
|
+
@http10_request = "GET / HTTP/1.0\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
|
9
|
+
@keep_request = "GET / HTTP/1.0\r\nHost: test.com\r\nContent-Type: text/plain\r\nConnection: Keep-Alive\r\n\r\n"
|
10
|
+
|
11
|
+
@valid_post = "POST / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\nContent-Length: 5\r\n\r\nhello"
|
12
|
+
@valid_no_body = "GET / HTTP/1.1\r\nHost: test.com\r\nX-Status: 204\r\nContent-Type: text/plain\r\n\r\n"
|
13
|
+
|
14
|
+
@headers = { "X-Header" => "Works" }
|
15
|
+
@body = ["Hello"]
|
16
|
+
@inputs = []
|
17
|
+
|
18
|
+
@simple = lambda do |env|
|
19
|
+
@inputs << env['rack.input']
|
20
|
+
status = Integer(env['HTTP_X_STATUS'] || 200)
|
21
|
+
[status, @headers, @body]
|
22
|
+
end
|
23
|
+
|
24
|
+
@host = "127.0.0.1"
|
25
|
+
@port = 3215
|
26
|
+
|
27
|
+
@server = Jubilee::Server.new @simple
|
28
|
+
@server.start
|
29
|
+
|
30
|
+
@client = TCPSocket.new @host, @port
|
31
|
+
end
|
32
|
+
|
33
|
+
def teardown
|
34
|
+
@client.close
|
35
|
+
sleep 0.1 # in case server shutdown before request is submitted
|
36
|
+
@server.stop
|
37
|
+
end
|
38
|
+
|
39
|
+
def lines(count, s=@client)
|
40
|
+
str = ""
|
41
|
+
timeout(5) do
|
42
|
+
count.times { str << s.gets }
|
43
|
+
end
|
44
|
+
str
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_one_with_content_length
|
48
|
+
@client << @valid_request
|
49
|
+
sz = @body[0].size.to_s
|
50
|
+
|
51
|
+
assert_match Regexp.new("HTTP/1.1 200 OK\r\nContent-Length: #{sz}\r\nX-Header: Works\r\n\r\n", true), lines(4)
|
52
|
+
assert_equal "Hello", @client.read(5)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_two_back_to_back
|
56
|
+
@client << @valid_request
|
57
|
+
sz = @body[0].size.to_s
|
58
|
+
|
59
|
+
assert_match Regexp.new("HTTP/1.1 200 OK\r\nContent-Length: #{sz}\r\nX-Header: Works\r\n\r\n", true), lines(4)
|
60
|
+
assert_equal "Hello", @client.read(5)
|
61
|
+
|
62
|
+
@client << @valid_request
|
63
|
+
sz = @body[0].size.to_s
|
64
|
+
|
65
|
+
assert_match Regexp.new("HTTP/1.1 200 OK\r\nContent-Length: #{sz}\r\nX-Header: Works\r\n\r\n", true), lines(4)
|
66
|
+
assert_equal "Hello", @client.read(5)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_post_then_get
|
70
|
+
@client << @valid_post
|
71
|
+
sz = @body[0].size.to_s
|
72
|
+
|
73
|
+
assert_match Regexp.new("HTTP/1.1 200 OK\r\nContent-Length: #{sz}\r\nX-Header: Works\r\n\r\n", true), lines(4)
|
74
|
+
assert_equal "Hello", @client.read(5)
|
75
|
+
|
76
|
+
@client << @valid_request
|
77
|
+
sz = @body[0].size.to_s
|
78
|
+
|
79
|
+
assert_match Regexp.new("HTTP/1.1 200 OK\r\nContent-Length: #{sz}\r\nX-Header: Works\r\n\r\n", true), lines(4)
|
80
|
+
assert_equal "Hello", @client.read(5)
|
81
|
+
end
|
82
|
+
|
83
|
+
#def test_no_body_then_get
|
84
|
+
# @client << @valid_no_body
|
85
|
+
# assert_equal "HTTP/1.1 204 No Content\r\nX-Header: Works\r\n\r\n", lines(3)
|
86
|
+
|
87
|
+
# @client << @valid_request
|
88
|
+
# sz = @body[0].size.to_s
|
89
|
+
|
90
|
+
# assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
|
91
|
+
# assert_equal "Hello", @client.read(5)
|
92
|
+
#end
|
93
|
+
|
94
|
+
def test_chunked
|
95
|
+
@body << "Chunked"
|
96
|
+
|
97
|
+
@client << @valid_request
|
98
|
+
|
99
|
+
assert_equal "HTTP/1.1 200 OK\r\nx-header: Works\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nHello\r\n7\r\nChunked\r\n0\r\n\r\n", lines(10)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_no_chunked_in_http10
|
103
|
+
@body << "Chunked"
|
104
|
+
|
105
|
+
@client << @http10_request
|
106
|
+
|
107
|
+
assert_equal "HTTP/1.0 200 OK\r\nConnection: close\r\nx-header: Works\r\n\r\n", lines(4)
|
108
|
+
assert_equal "HelloChunked", @client.read
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_hex
|
112
|
+
str = "This is longer and will be in hex"
|
113
|
+
@body << str
|
114
|
+
|
115
|
+
@client << @valid_request
|
116
|
+
|
117
|
+
assert_equal "HTTP/1.1 200 OK\r\nx-header: Works\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nHello\r\n#{str.size.to_s(16)}\r\n#{str}\r\n0\r\n\r\n", lines(10)
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_client11_close
|
122
|
+
@client << @close_request
|
123
|
+
sz = @body[0].size.to_s
|
124
|
+
|
125
|
+
assert_equal "HTTP/1.1 200 OK\r\nConnection: close\r\ncontent-length: #{sz}\r\nx-header: Works\r\n\r\n", lines(5)
|
126
|
+
assert_equal "Hello", @client.read(5)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_client10_close
|
130
|
+
@client << @http10_request
|
131
|
+
sz = @body[0].size.to_s
|
132
|
+
|
133
|
+
assert_equal "HTTP/1.0 200 OK\r\nConnection: close\r\ncontent-length: #{sz}\r\nx-header: Works\r\n\r\n", lines(5)
|
134
|
+
assert_equal "Hello", @client.read(5)
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_one_with_keep_alive_header
|
138
|
+
@client << @keep_request
|
139
|
+
sz = @body[0].size.to_s
|
140
|
+
|
141
|
+
assert_equal "HTTP/1.0 200 OK\r\nConnection: keep-alive\r\ncontent-length: #{sz}\r\nx-header: Works\r\n\r\n", lines(5)
|
142
|
+
assert_equal "Hello", @client.read(5)
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_persistent_timeout
|
146
|
+
@server.persistent_timeout = 2
|
147
|
+
@client << @valid_request
|
148
|
+
sz = @body[0].size.to_s
|
149
|
+
|
150
|
+
assert_equal "HTTP/1.1 200 OK\r\ncontent-length: #{sz}\r\nx-header: Works\r\n\r\n", lines(4)
|
151
|
+
assert_equal "Hello", @client.read(5)
|
152
|
+
|
153
|
+
sleep 3
|
154
|
+
|
155
|
+
assert_raises EOFError do
|
156
|
+
@client.read_nonblock(1)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_app_sets_content_length
|
161
|
+
@body = ["hello", " world"]
|
162
|
+
@headers['Content-Length'] = "11"
|
163
|
+
|
164
|
+
@client << @valid_request
|
165
|
+
|
166
|
+
assert_equal "HTTP/1.1 200 OK\r\ncontent-length: 11\r\nx-header: Works\r\n\r\n",
|
167
|
+
lines(4)
|
168
|
+
assert_equal "hello world", @client.read(11)
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_allow_app_to_chunk_itself
|
172
|
+
skip "vertx doesn't support chunk self yet"
|
173
|
+
@headers = {'Transfer-Encoding' => "chunked" }
|
174
|
+
|
175
|
+
@body = ["5\r\nhello\r\n0\r\n\r\n"]
|
176
|
+
|
177
|
+
@client << @valid_request
|
178
|
+
|
179
|
+
assert_equal "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n", lines(7)
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
def test_two_requests_in_one_chunk
|
184
|
+
@server.persistent_timeout = 3
|
185
|
+
|
186
|
+
req = @valid_request.to_s
|
187
|
+
req << "GET /second HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
|
188
|
+
|
189
|
+
@client << req
|
190
|
+
|
191
|
+
sz = @body[0].size.to_s
|
192
|
+
|
193
|
+
assert_equal "HTTP/1.1 200 OK\r\ncontent-length: #{sz}\r\nx-header: Works\r\n\r\n", lines(4)
|
194
|
+
assert_equal "Hello", @client.read(5)
|
195
|
+
|
196
|
+
assert_equal "HTTP/1.1 200 OK\r\ncontent-length: #{sz}\r\nx-header: Works\r\n\r\n", lines(4)
|
197
|
+
assert_equal "Hello", @client.read(5)
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_second_request_not_in_first_req_body
|
201
|
+
@server.persistent_timeout = 3
|
202
|
+
|
203
|
+
req = @valid_request.to_s
|
204
|
+
req << "GET /second HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
|
205
|
+
|
206
|
+
@client << req
|
207
|
+
|
208
|
+
sz = @body[0].size.to_s
|
209
|
+
|
210
|
+
assert_equal "HTTP/1.1 200 OK\r\ncontent-length: #{sz}\r\nx-header: Works\r\n\r\n", lines(4)
|
211
|
+
assert_equal "Hello", @client.read(5)
|
212
|
+
|
213
|
+
assert_equal "HTTP/1.1 200 OK\r\ncontent-length: #{sz}\r\nx-header: Works\r\n\r\n", lines(4)
|
214
|
+
assert_equal "Hello", @client.read(5)
|
215
|
+
|
216
|
+
# Since rack process request before the body is ready, we cannot
|
217
|
+
# utilize this optimization
|
218
|
+
# assert_kind_of Jubilee::NullIO, @inputs[0]
|
219
|
+
# assert_kind_of Jubilee::NullIO, @inputs[1]
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_keepalive_doesnt_starve_clients
|
223
|
+
sz = @body[0].size.to_s
|
224
|
+
|
225
|
+
@client << @valid_request
|
226
|
+
|
227
|
+
c2 = TCPSocket.new @host, @port
|
228
|
+
c2 << @valid_request
|
229
|
+
|
230
|
+
out = IO.select([c2], nil, nil, 1)
|
231
|
+
|
232
|
+
assert out, "select returned nil"
|
233
|
+
assert_equal c2, out.first.first
|
234
|
+
|
235
|
+
assert_equal "HTTP/1.1 200 OK\r\ncontent-length: #{sz}\r\nx-header: Works\r\n\r\n", lines(4, c2)
|
236
|
+
assert_equal "Hello", c2.read(5)
|
237
|
+
end
|
238
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'rack/lint'
|
3
|
+
require 'rack/commonlogger'
|
4
|
+
|
5
|
+
class TestRackServer < MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
class ErrorChecker
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
@exception = nil
|
11
|
+
@env = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :exception, :env
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
begin
|
18
|
+
@env = env
|
19
|
+
return @app.call(env)
|
20
|
+
rescue Exception => e
|
21
|
+
@exception = e
|
22
|
+
|
23
|
+
[
|
24
|
+
500,
|
25
|
+
{ "X-Exception" => e.message, "X-Exception-Class" => e.class.to_s },
|
26
|
+
["Error detected"]
|
27
|
+
]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class ServerLint < Rack::Lint
|
33
|
+
def call(env)
|
34
|
+
assert("No env given") { env }
|
35
|
+
check_env env
|
36
|
+
|
37
|
+
@app.call(env)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
@valid_request = "GET / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\n\r\n"
|
43
|
+
|
44
|
+
@simple = lambda { |env| [200, { "X-Header" => "Works" }, ["Hello"]] }
|
45
|
+
@checker = ErrorChecker.new ServerLint.new(@simple)
|
46
|
+
end
|
47
|
+
|
48
|
+
def teardown
|
49
|
+
@server.stop
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_lint
|
53
|
+
@server = Jubilee::Server.new @checker
|
54
|
+
|
55
|
+
@server.start
|
56
|
+
|
57
|
+
hit(['http://127.0.0.1:3215/test'])
|
58
|
+
|
59
|
+
if exc = @checker.exception
|
60
|
+
raise exc
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_large_post_body
|
65
|
+
@checker = ErrorChecker.new ServerLint.new(@simple)
|
66
|
+
@server = Jubilee::Server.new @checker
|
67
|
+
|
68
|
+
@server.start
|
69
|
+
|
70
|
+
big = "x" * (1024 * 16)
|
71
|
+
|
72
|
+
Net::HTTP.post_form URI.parse('http://127.0.0.1:3215/test'),
|
73
|
+
{ "big" => big }
|
74
|
+
|
75
|
+
if exc = @checker.exception
|
76
|
+
raise exc
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_path_info
|
81
|
+
input = nil
|
82
|
+
@server = Jubilee::Server.new (lambda { |env| input = env; @simple.call(env) })
|
83
|
+
@server.start
|
84
|
+
|
85
|
+
hit(['http://127.0.0.1:3215/test/a/b/c'])
|
86
|
+
|
87
|
+
assert_equal "/test/a/b/c", input['PATH_INFO']
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_query_string
|
91
|
+
input = nil
|
92
|
+
@server = Jubilee::Server.new (lambda { |env| input = env; @simple.call(env) })
|
93
|
+
@server.start
|
94
|
+
|
95
|
+
hit(['http://127.0.0.1:3215/test/a/b/c?foo=bar'])
|
96
|
+
|
97
|
+
assert_equal "foo=bar", input['QUERY_STRING']
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_post_data
|
101
|
+
require 'rack/request'
|
102
|
+
input = nil
|
103
|
+
@server = Jubilee::Server.new (lambda { |env| input = env; @simple.call(env) })
|
104
|
+
@server.start
|
105
|
+
|
106
|
+
req = Net::HTTP::Post::Multipart.new("/", "foo" => "bar")
|
107
|
+
resp = Net::HTTP.start('localhost', 3215) do |http|
|
108
|
+
http.request req
|
109
|
+
end
|
110
|
+
|
111
|
+
#Net::HTTP.post_form URI.parse('http://127.0.0.1:3215/test'), { "foo" => "bar" }
|
112
|
+
|
113
|
+
request = Rack::Request.new input
|
114
|
+
assert_equal "bar", request.params["foo"]
|
115
|
+
end
|
116
|
+
end
|