mizuno 0.3.6 → 0.4.0
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/.gitignore +4 -0
- data/{README → README.markdown} +10 -0
- data/bin/mizuno +2 -4
- data/lib/java/{jetty-continuation-7.0.2.v20100331.jar → jetty-continuation-7.3.0.v20110203.jar} +0 -0
- data/lib/java/jetty-http-7.3.0.v20110203.jar +0 -0
- data/lib/java/jetty-io-7.3.0.v20110203.jar +0 -0
- data/lib/java/jetty-jmx-7.3.0.v20110203.jar +0 -0
- data/lib/java/jetty-security-7.3.0.v20110203.jar +0 -0
- data/lib/java/jetty-server-7.3.0.v20110203.jar +0 -0
- data/lib/java/jetty-servlet-7.3.0.v20110203.jar +0 -0
- data/lib/java/jetty-servlets-7.3.0.v20110203.jar +0 -0
- data/lib/java/jetty-util-7.3.0.v20110203.jar +0 -0
- data/lib/java/servlet-api-2.5.jar +0 -0
- data/lib/mizuno.rb +16 -0
- data/lib/mizuno/http_server.rb +90 -0
- data/lib/mizuno/rack_servlet.rb +219 -0
- data/mizuno.gemspec +21 -22
- metadata +29 -30
- data/lib/java/cometd-api-1.1.0.jar +0 -0
- data/lib/java/cometd-java-server-1.1.0.jar +0 -0
- data/lib/java/jetty-http-7.0.2.v20100331.jar +0 -0
- data/lib/java/jetty-io-7.0.2.v20100331.jar +0 -0
- data/lib/java/jetty-jmx-7.0.2.v20100331.jar +0 -0
- data/lib/java/jetty-security-7.0.2.v20100331.jar +0 -0
- data/lib/java/jetty-server-7.0.2.v20100331.jar +0 -0
- data/lib/java/jetty-servlet-7.0.2.v20100331.jar +0 -0
- data/lib/java/jetty-servlets-7.0.2.v20100331.jar +0 -0
- data/lib/java/jetty-util-7.0.2.v20100331.jar +0 -0
- data/lib/rack/handler/mizuno.rb +0 -1
- data/lib/rack/handler/mizuno/http_server.rb +0 -64
- data/lib/rack/handler/mizuno/rack_servlet.rb +0 -218
data/.gitignore
CHANGED
data/{README → README.markdown}
RENAMED
@@ -27,7 +27,17 @@ because it doesn't produce WAR files or make any attempt to package a
|
|
27
27
|
Rack application for installation in a Java web container.
|
28
28
|
|
29
29
|
There's also a few features that I have yet to implement:
|
30
|
+
|
30
31
|
1. Integrate the cometd servlet to provide Comet/Bayeux.
|
31
32
|
2. Route Jetty's logs into Rack::Logger.
|
32
33
|
3. Add hooks for realtime monitoring of server performance.
|
33
34
|
4. Add the ability to run multiple Rack apps in a single JVM.
|
35
|
+
|
36
|
+
Mizuno is licensed under the Apache Public License, version 2.0; see
|
37
|
+
the LICENSE file for details, and was developed on behalf of
|
38
|
+
[Mad Wombat Software](http://www.madwombat.com)
|
39
|
+
|
40
|
+
Jetty is dual-licensed under the [Eclipse and Apache open-source
|
41
|
+
licenses](http://www.eclipse.org/jetty/licenses.php), and its
|
42
|
+
development is hosted by the [Eclipse
|
43
|
+
Foundation](http://www.eclipse.org/jetty/)
|
data/bin/mizuno
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
raise("Rack::Handler::Mizuno only runs on JRuby.") \
|
5
|
-
unless (RUBY_PLATFORM =~ /java/)
|
3
|
+
raise("Mizuno only runs on JRuby.") unless (RUBY_PLATFORM =~ /java/)
|
6
4
|
|
7
5
|
require 'rack'
|
8
|
-
require '
|
6
|
+
require 'mizuno'
|
9
7
|
|
10
8
|
server = Rack::Server.new
|
11
9
|
server.options[:server] = 'mizuno'
|
data/lib/java/{jetty-continuation-7.0.2.v20100331.jar → jetty-continuation-7.3.0.v20110203.jar}
RENAMED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/mizuno.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#
|
2
|
+
# A Rack handler for Jetty 7.
|
3
|
+
#
|
4
|
+
# Written by Don Werve <don@madwombat.com>
|
5
|
+
#
|
6
|
+
|
7
|
+
# Java integration for talking to Jetty.
|
8
|
+
require 'java'
|
9
|
+
|
10
|
+
# Load Jetty JARs.
|
11
|
+
jars = File.join(File.dirname(__FILE__), 'java', '*.jar')
|
12
|
+
Dir[jars].each { |j| require j }
|
13
|
+
|
14
|
+
require 'rack'
|
15
|
+
require 'mizuno/rack_servlet'
|
16
|
+
require 'mizuno/http_server'
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# Have Jetty log to stdout for the time being.
|
2
|
+
java.lang.System.setProperty("org.eclipse.jetty.util.log.class",
|
3
|
+
"org.eclipse.jetty.util.log.StdErrLog")
|
4
|
+
|
5
|
+
module Mizuno
|
6
|
+
class HttpServer
|
7
|
+
include_class 'org.eclipse.jetty.server.Server'
|
8
|
+
include_class 'org.eclipse.jetty.servlet.ServletContextHandler'
|
9
|
+
include_class 'org.eclipse.jetty.servlet.ServletHolder'
|
10
|
+
include_class 'org.eclipse.jetty.server.nio.SelectChannelConnector'
|
11
|
+
include_class 'org.eclipse.jetty.util.thread.QueuedThreadPool'
|
12
|
+
include_class 'org.eclipse.jetty.servlet.DefaultServlet'
|
13
|
+
|
14
|
+
#
|
15
|
+
# Provide accessors so we can set a custom logger and a location
|
16
|
+
# for static assets.
|
17
|
+
#
|
18
|
+
class << self
|
19
|
+
attr_accessor :logger
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Start up an instance of Jetty, running a Rack application.
|
24
|
+
# Options can be any of the follwing, and are not
|
25
|
+
# case-sensitive:
|
26
|
+
#
|
27
|
+
# :host::
|
28
|
+
# String specifying the IP address to bind to; defaults
|
29
|
+
# to 0.0.0.0.
|
30
|
+
#
|
31
|
+
# :port::
|
32
|
+
# String or integer with the port to bind to; defaults
|
33
|
+
# to 9292.
|
34
|
+
#
|
35
|
+
# FIXME: Clean up options hash (all downcase, all symbols)
|
36
|
+
#
|
37
|
+
def self.run(app, options = {})
|
38
|
+
# The Jetty server
|
39
|
+
@server = Server.new
|
40
|
+
|
41
|
+
options = Hash[options.map { |o|
|
42
|
+
[ o[0].to_s.downcase.to_sym, o[1] ] }]
|
43
|
+
|
44
|
+
# Thread pool
|
45
|
+
thread_pool = QueuedThreadPool.new
|
46
|
+
thread_pool.min_threads = 5
|
47
|
+
thread_pool.max_threads = 50
|
48
|
+
@server.set_thread_pool(thread_pool)
|
49
|
+
|
50
|
+
# Connector
|
51
|
+
connector = SelectChannelConnector.new
|
52
|
+
connector.setPort(options[:port].to_i)
|
53
|
+
connector.setHost(options[:host])
|
54
|
+
@server.addConnector(connector)
|
55
|
+
|
56
|
+
# Servlet context.
|
57
|
+
context = ServletContextHandler.new(nil, "/",
|
58
|
+
ServletContextHandler::NO_SESSIONS)
|
59
|
+
|
60
|
+
# The servlet itself.
|
61
|
+
rack_servlet = RackServlet.new
|
62
|
+
rack_servlet.rackup(app)
|
63
|
+
holder = ServletHolder.new(rack_servlet)
|
64
|
+
context.addServlet(holder, "/")
|
65
|
+
|
66
|
+
# Add the context to the server and start.
|
67
|
+
@server.set_handler(context)
|
68
|
+
puts "Listening on #{connector.getHost}:#{connector.getPort}"
|
69
|
+
@server.start
|
70
|
+
|
71
|
+
# Stop the server when we get The Signal.
|
72
|
+
trap("SIGINT") { @server.stop and exit }
|
73
|
+
|
74
|
+
# Join with the server thread, so that currently open file
|
75
|
+
# descriptors don't get closed by accident.
|
76
|
+
# http://www.ruby-forum.com/topic/209252
|
77
|
+
@server.join unless options[:embedded]
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Shuts down an embedded Jetty instance.
|
82
|
+
#
|
83
|
+
def self.stop
|
84
|
+
@server.stop
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Register ourselves with Rack when this file gets loaded.
|
90
|
+
Rack::Handler.register 'mizuno', 'Mizuno::HttpServer'
|
@@ -0,0 +1,219 @@
|
|
1
|
+
#
|
2
|
+
# Wraps a Rack application in a Java servlet.
|
3
|
+
#
|
4
|
+
# Relevant documentation:
|
5
|
+
#
|
6
|
+
# http://rack.rubyforge.org/doc/SPEC.html
|
7
|
+
# http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax
|
8
|
+
# /servlet/http/HttpServlet.html
|
9
|
+
#
|
10
|
+
module Mizuno
|
11
|
+
include_class javax.servlet.http.HttpServlet
|
12
|
+
|
13
|
+
class RackServlet < HttpServlet
|
14
|
+
include_class java.io.FileInputStream
|
15
|
+
include_class org.eclipse.jetty.continuation.ContinuationSupport
|
16
|
+
|
17
|
+
#
|
18
|
+
# Sets the Rack application that handles requests sent to this
|
19
|
+
# servlet container.
|
20
|
+
#
|
21
|
+
def rackup(app)
|
22
|
+
@app = app
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Takes an incoming request (as a Java Servlet) and dispatches it to
|
27
|
+
# the rack application setup via [rackup]. All this really involves
|
28
|
+
# is translating the various bits of the Servlet API into the Rack
|
29
|
+
# API on the way in, and translating the response back on the way
|
30
|
+
# out.
|
31
|
+
#
|
32
|
+
# Also, we implement a common extension to the Rack api for
|
33
|
+
# asynchronous request processing. We supply an 'async.callback'
|
34
|
+
# parameter in env to the Rack application. If we catch an
|
35
|
+
# :async symbol thrown by the app, we initiate a Jetty continuation.
|
36
|
+
#
|
37
|
+
# When 'async.callback' gets a response with empty headers and an
|
38
|
+
# empty body, we declare the async response finished.
|
39
|
+
#
|
40
|
+
def service(request, response)
|
41
|
+
# Turn the ServletRequest into a Rack env hash
|
42
|
+
env = servlet_to_rack(request)
|
43
|
+
|
44
|
+
# Handle asynchronous responses via Servlet continuations.
|
45
|
+
continuation = ContinuationSupport.getContinuation(request)
|
46
|
+
|
47
|
+
# If this is an expired connection, do nothing.
|
48
|
+
return if continuation.isExpired
|
49
|
+
|
50
|
+
# We should never be re-dispatched.
|
51
|
+
raise("Request re-dispatched.") unless continuation.isInitial
|
52
|
+
|
53
|
+
# Add our own special bits to the rack environment so that
|
54
|
+
# Rack middleware can have access to the Java internals.
|
55
|
+
env['rack.java.servlet'] = true
|
56
|
+
env['rack.java.servlet.request'] = request
|
57
|
+
env['rack.java.servlet.response'] = response
|
58
|
+
env['rack.java.servlet.continuation'] = continuation
|
59
|
+
|
60
|
+
# Add an callback that can be used to add results to the
|
61
|
+
# response asynchronously.
|
62
|
+
env['async.callback'] = lambda do |rack_response|
|
63
|
+
servlet_response = continuation.getServletResponse
|
64
|
+
rack_to_servlet(rack_response, servlet_response) \
|
65
|
+
and continuation.complete
|
66
|
+
end
|
67
|
+
|
68
|
+
# Execute the Rack request.
|
69
|
+
catch(:async) do
|
70
|
+
rack_response = @app.call(env)
|
71
|
+
|
72
|
+
# For apps that don't throw :async.
|
73
|
+
unless(rack_response[0] == -1)
|
74
|
+
# Nope, nothing asynchronous here.
|
75
|
+
rack_to_servlet(rack_response, response)
|
76
|
+
return
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# If we got here, this is a continuation.
|
81
|
+
continuation.suspend(response)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
#
|
87
|
+
# Turns a Servlet request into a Rack request hash.
|
88
|
+
#
|
89
|
+
def servlet_to_rack(request)
|
90
|
+
# The Rack request that we will pass on.
|
91
|
+
env = Hash.new
|
92
|
+
|
93
|
+
# Map Servlet bits to Rack bits.
|
94
|
+
env['REQUEST_METHOD'] = request.getMethod
|
95
|
+
env['QUERY_STRING'] = request.getQueryString.to_s
|
96
|
+
env['SERVER_NAME'] = request.getServerName
|
97
|
+
env['SERVER_PORT'] = request.getServerPort.to_s
|
98
|
+
env['rack.version'] = Rack::VERSION
|
99
|
+
env['rack.url_scheme'] = request.getScheme
|
100
|
+
env['HTTP_VERSION'] = request.getProtocol
|
101
|
+
env["SERVER_PROTOCOL"] = request.getProtocol
|
102
|
+
env['REMOTE_ADDR'] = request.getRemoteAddr
|
103
|
+
env['REMOTE_HOST'] = request.getRemoteHost
|
104
|
+
|
105
|
+
# request.getPathInfo seems to be blank, so we're using the URI.
|
106
|
+
env['REQUEST_PATH'] = request.getRequestURI
|
107
|
+
env['PATH_INFO'] = request.getRequestURI
|
108
|
+
env['SCRIPT_NAME'] = ""
|
109
|
+
|
110
|
+
# Rack says URI, but it hands off a URL.
|
111
|
+
env['REQUEST_URI'] = request.getRequestURL.toString
|
112
|
+
|
113
|
+
# Java chops off the query string, but a Rack application will
|
114
|
+
# expect it, so we'll add it back if present
|
115
|
+
env['REQUEST_URI'] << "?#{env['QUERY_STRING']}" \
|
116
|
+
if env['QUERY_STRING']
|
117
|
+
|
118
|
+
# JRuby is like the matrix, only there's no spoon or fork().
|
119
|
+
env['rack.multiprocess'] = false
|
120
|
+
env['rack.multithread'] = true
|
121
|
+
env['rack.run_once'] = false
|
122
|
+
|
123
|
+
# Populate the HTTP headers.
|
124
|
+
request.getHeaderNames.each do |header_name|
|
125
|
+
header = header_name.upcase.tr('-', '_')
|
126
|
+
env["HTTP_#{header}"] = request.getHeader(header_name)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Rack Weirdness: HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH
|
130
|
+
# both need to have the HTTP_ part dropped.
|
131
|
+
env["CONTENT_TYPE"] = env.delete("HTTP_CONTENT_TYPE") \
|
132
|
+
if env["HTTP_CONTENT_TYPE"]
|
133
|
+
env["CONTENT_LENGTH"] = env.delete("HTTP_CONTENT_LENGTH") \
|
134
|
+
if env["HTTP_CONTENT_LENGTH"]
|
135
|
+
|
136
|
+
# The input stream is a wrapper around the Java InputStream.
|
137
|
+
env['rack.input'] = request.getInputStream.to_io
|
138
|
+
|
139
|
+
# The output stream defaults to stderr.
|
140
|
+
env['rack.errors'] ||= $stderr
|
141
|
+
|
142
|
+
# All done, hand back the Rack request.
|
143
|
+
return(env)
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
# Turns a Rack response into a Servlet response; can be called
|
148
|
+
# multiple times. Returns true if this is the full request (either
|
149
|
+
# a synchronous request or the last part of an async request),
|
150
|
+
# false otherwise.
|
151
|
+
#
|
152
|
+
# Note that keep-alive *only* happens if we get either a pathname
|
153
|
+
# (because we can find the length ourselves), or if we get a
|
154
|
+
# Content-Length header as part of the response. While we can
|
155
|
+
# readily buffer the response object to figure out how long it is,
|
156
|
+
# we have no guarantee that we aren't going to be buffering
|
157
|
+
# something *huge*.
|
158
|
+
#
|
159
|
+
# http://docstore.mik.ua/orelly/java-ent/servlet/ch05_03.htm
|
160
|
+
#
|
161
|
+
def rack_to_servlet(rack_response, response)
|
162
|
+
# Split apart the Rack response.
|
163
|
+
status, headers, body = rack_response
|
164
|
+
|
165
|
+
# We assume the request is finished if we got empty headers,
|
166
|
+
# an empty body, and we have a committed response.
|
167
|
+
finished = (headers.empty? and \
|
168
|
+
body.respond_to?(:empty?) and body.empty?)
|
169
|
+
return(true) if (finished and response.isCommitted)
|
170
|
+
|
171
|
+
# No need to send headers again if we've already shipped
|
172
|
+
# data out on an async request.
|
173
|
+
unless(response.isCommitted)
|
174
|
+
# Set the HTTP status code.
|
175
|
+
response.setStatus(status)
|
176
|
+
|
177
|
+
# Did we get a Content-Length header?
|
178
|
+
content_length = headers.delete('Content-Length')
|
179
|
+
response.setContentLength(content_length.to_i) \
|
180
|
+
if content_length
|
181
|
+
|
182
|
+
# Add all the result headers.
|
183
|
+
headers.each { |h, v| response.addHeader(h, v) }
|
184
|
+
end
|
185
|
+
|
186
|
+
# How else would we write output?
|
187
|
+
output = response.getOutputStream
|
188
|
+
|
189
|
+
# Turn the body into something nice and Java-y.
|
190
|
+
if(body.respond_to?(:to_path))
|
191
|
+
# We've been told to serve a file; use FileInputStream to
|
192
|
+
# stream the file directly to the servlet, because this
|
193
|
+
# is a lot faster than doing it with Ruby.
|
194
|
+
file = java.io.File.new(body.to_path)
|
195
|
+
|
196
|
+
# We set the content-length so we can use Keep-Alive,
|
197
|
+
# unless this is an async request.
|
198
|
+
response.setContentLength(file.length) \
|
199
|
+
unless content_length
|
200
|
+
|
201
|
+
# Stream the file directly.
|
202
|
+
buffer = Java::byte[4096].new
|
203
|
+
input_stream = FileInputStream.new(file)
|
204
|
+
while((count = input_stream.read(buffer)) != -1)
|
205
|
+
output.write(buffer, 0, count)
|
206
|
+
end
|
207
|
+
input_stream.close
|
208
|
+
else
|
209
|
+
body.each { |l| output.write(l.to_java_bytes) }
|
210
|
+
end
|
211
|
+
|
212
|
+
# Close the body if we're supposed to.
|
213
|
+
body.close if body.respond_to?(:close)
|
214
|
+
|
215
|
+
# All done.
|
216
|
+
output.flush
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
data/mizuno.gemspec
CHANGED
@@ -1,35 +1,34 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "mizuno"
|
3
|
-
spec.version = "0.
|
3
|
+
spec.version = "0.4.0"
|
4
4
|
spec.required_rubygems_version = Gem::Requirement.new(">= 1.2") \
|
5
|
-
|
5
|
+
if spec.respond_to?(:required_rubygems_version=)
|
6
6
|
spec.authors = [ "Don Werve" ]
|
7
7
|
spec.description = 'Jetty-powered running shoes for JRuby/Rack.'
|
8
8
|
spec.summary = 'Rack handler for Jetty 7 on JRuby. Features multithreading, event-driven I/O, and async support.'
|
9
9
|
spec.email = 'don@madwombat.com'
|
10
10
|
spec.executables = [ "mizuno" ]
|
11
|
-
spec.files =
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
"lib/rack/handler/mizuno.rb",
|
30
|
-
"bin/mizuno" ]
|
11
|
+
spec.files = %w( .gitignore
|
12
|
+
README.markdown
|
13
|
+
LICENSE
|
14
|
+
mizuno.gemspec
|
15
|
+
lib/java/jetty-continuation-7.3.0.v20110203.jar
|
16
|
+
lib/java/jetty-http-7.3.0.v20110203.jar
|
17
|
+
lib/java/jetty-io-7.3.0.v20110203.jar
|
18
|
+
lib/java/jetty-jmx-7.3.0.v20110203.jar
|
19
|
+
lib/java/jetty-security-7.3.0.v20110203.jar
|
20
|
+
lib/java/jetty-server-7.3.0.v20110203.jar
|
21
|
+
lib/java/jetty-servlet-7.3.0.v20110203.jar
|
22
|
+
lib/java/jetty-servlets-7.3.0.v20110203.jar
|
23
|
+
lib/java/jetty-util-7.3.0.v20110203.jar
|
24
|
+
lib/java/servlet-api-2.5.jar
|
25
|
+
lib/mizuno/http_server.rb
|
26
|
+
lib/mizuno/rack_servlet.rb
|
27
|
+
lib/mizuno.rb
|
28
|
+
bin/mizuno )
|
31
29
|
spec.homepage = 'http://github.com/matadon/mizuno'
|
32
30
|
spec.has_rdoc = false
|
33
31
|
spec.require_paths = [ "lib" ]
|
34
32
|
spec.rubygems_version = '1.3.6'
|
33
|
+
spec.add_dependency('rack', '>= 1.0.0')
|
35
34
|
end
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mizuno
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 3
|
8
|
-
- 6
|
9
|
-
version: 0.3.6
|
4
|
+
prerelease:
|
5
|
+
version: 0.4.0
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Don Werve
|
@@ -14,10 +10,20 @@ autorequire:
|
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date:
|
13
|
+
date: 2011-02-13 00:00:00 +09:00
|
18
14
|
default_executable:
|
19
|
-
dependencies:
|
20
|
-
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rack
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.0.0
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
21
27
|
description: Jetty-powered running shoes for JRuby/Rack.
|
22
28
|
email: don@madwombat.com
|
23
29
|
executables:
|
@@ -28,24 +34,22 @@ extra_rdoc_files: []
|
|
28
34
|
|
29
35
|
files:
|
30
36
|
- .gitignore
|
31
|
-
- README
|
37
|
+
- README.markdown
|
32
38
|
- LICENSE
|
33
39
|
- mizuno.gemspec
|
34
|
-
- lib/java/
|
35
|
-
- lib/java/
|
36
|
-
- lib/java/jetty-
|
37
|
-
- lib/java/jetty-
|
38
|
-
- lib/java/jetty-
|
39
|
-
- lib/java/jetty-
|
40
|
-
- lib/java/jetty-
|
41
|
-
- lib/java/jetty-
|
42
|
-
- lib/java/jetty-
|
43
|
-
- lib/java/jetty-servlets-7.0.2.v20100331.jar
|
44
|
-
- lib/java/jetty-util-7.0.2.v20100331.jar
|
40
|
+
- lib/java/jetty-continuation-7.3.0.v20110203.jar
|
41
|
+
- lib/java/jetty-http-7.3.0.v20110203.jar
|
42
|
+
- lib/java/jetty-io-7.3.0.v20110203.jar
|
43
|
+
- lib/java/jetty-jmx-7.3.0.v20110203.jar
|
44
|
+
- lib/java/jetty-security-7.3.0.v20110203.jar
|
45
|
+
- lib/java/jetty-server-7.3.0.v20110203.jar
|
46
|
+
- lib/java/jetty-servlet-7.3.0.v20110203.jar
|
47
|
+
- lib/java/jetty-servlets-7.3.0.v20110203.jar
|
48
|
+
- lib/java/jetty-util-7.3.0.v20110203.jar
|
45
49
|
- lib/java/servlet-api-2.5.jar
|
46
|
-
- lib/
|
47
|
-
- lib/
|
48
|
-
- lib/
|
50
|
+
- lib/mizuno/http_server.rb
|
51
|
+
- lib/mizuno/rack_servlet.rb
|
52
|
+
- lib/mizuno.rb
|
49
53
|
- bin/mizuno
|
50
54
|
has_rdoc: true
|
51
55
|
homepage: http://github.com/matadon/mizuno
|
@@ -61,22 +65,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
61
65
|
requirements:
|
62
66
|
- - ">="
|
63
67
|
- !ruby/object:Gem::Version
|
64
|
-
segments:
|
65
|
-
- 0
|
66
68
|
version: "0"
|
67
69
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
70
|
none: false
|
69
71
|
requirements:
|
70
72
|
- - ">="
|
71
73
|
- !ruby/object:Gem::Version
|
72
|
-
segments:
|
73
|
-
- 1
|
74
|
-
- 2
|
75
74
|
version: "1.2"
|
76
75
|
requirements: []
|
77
76
|
|
78
77
|
rubyforge_project:
|
79
|
-
rubygems_version: 1.
|
78
|
+
rubygems_version: 1.4.2
|
80
79
|
signing_key:
|
81
80
|
specification_version: 3
|
82
81
|
summary: Rack handler for Jetty 7 on JRuby. Features multithreading, event-driven I/O, and async support.
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/rack/handler/mizuno.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'rack/handler/mizuno/http_server'
|
@@ -1,64 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# A Rack handler for Jetty 7.
|
3
|
-
#
|
4
|
-
# Written by Don Werve <don@madwombat.com>
|
5
|
-
#
|
6
|
-
|
7
|
-
require 'java'
|
8
|
-
require 'rack'
|
9
|
-
|
10
|
-
# Load Jetty JARs.
|
11
|
-
jars = File.join(File.dirname(__FILE__), '..', '..', '..', 'java', '*.jar')
|
12
|
-
Dir[jars].each { |j| require j }
|
13
|
-
|
14
|
-
# Load the Rack/Servlet bridge.
|
15
|
-
require 'rack/handler/mizuno/rack_servlet'
|
16
|
-
|
17
|
-
# Have Jetty log to stdout for the time being.
|
18
|
-
java.lang.System.setProperty("org.eclipse.jetty.util.log.class",
|
19
|
-
"org.eclipse.jetty.util.log.StdErrLog")
|
20
|
-
|
21
|
-
module Rack::Handler::Mizuno
|
22
|
-
class HttpServer
|
23
|
-
include_class 'org.eclipse.jetty.server.Server'
|
24
|
-
include_class 'org.eclipse.jetty.servlet.ServletContextHandler'
|
25
|
-
include_class 'org.eclipse.jetty.servlet.ServletHolder'
|
26
|
-
include_class 'org.eclipse.jetty.server.nio.SelectChannelConnector'
|
27
|
-
include_class 'org.eclipse.jetty.util.thread.QueuedThreadPool'
|
28
|
-
|
29
|
-
def self.run(app, options = {})
|
30
|
-
# The Jetty server
|
31
|
-
server = Server.new
|
32
|
-
|
33
|
-
# Thread pool
|
34
|
-
thread_pool = QueuedThreadPool.new
|
35
|
-
thread_pool.min_threads = 5
|
36
|
-
thread_pool.max_threads = 50
|
37
|
-
server.set_thread_pool(thread_pool)
|
38
|
-
|
39
|
-
# Connector
|
40
|
-
connector = SelectChannelConnector.new
|
41
|
-
connector.setPort(options[:Port].to_i)
|
42
|
-
connector.setHost(options[:Host])
|
43
|
-
server.addConnector(connector)
|
44
|
-
|
45
|
-
# Servlet context.
|
46
|
-
context = ServletContextHandler.new(nil, "/",
|
47
|
-
ServletContextHandler::NO_SESSIONS)
|
48
|
-
|
49
|
-
# The servlet itself.
|
50
|
-
servlet = RackServlet.new
|
51
|
-
servlet.rackup(app)
|
52
|
-
holder = ServletHolder.new(servlet)
|
53
|
-
context.addServlet(holder, "/")
|
54
|
-
|
55
|
-
# Add the context to the server and start.
|
56
|
-
server.set_handler(context)
|
57
|
-
puts "Started Jetty on #{connector.getHost}:#{connector.getPort}"
|
58
|
-
server.start
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Register ourselves with Rack when this file gets loaded.
|
64
|
-
Rack::Handler.register 'mizuno', 'Rack::Handler::Mizuno::HttpServer'
|
@@ -1,218 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Wraps a Rack application in a Java servlet.
|
3
|
-
#
|
4
|
-
# Relevant documentation:
|
5
|
-
#
|
6
|
-
# http://rack.rubyforge.org/doc/SPEC.html
|
7
|
-
# http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/HttpServlet.html
|
8
|
-
#
|
9
|
-
module Rack::Handler::Mizuno
|
10
|
-
include_class javax.servlet.http.HttpServlet
|
11
|
-
|
12
|
-
class RackServlet < HttpServlet
|
13
|
-
include_class java.io.FileInputStream
|
14
|
-
include_class org.eclipse.jetty.continuation.ContinuationSupport
|
15
|
-
|
16
|
-
#
|
17
|
-
# Sets the Rack application that handles requests sent to this
|
18
|
-
# servlet container.
|
19
|
-
#
|
20
|
-
def rackup(app)
|
21
|
-
@app = app
|
22
|
-
end
|
23
|
-
|
24
|
-
#
|
25
|
-
# Takes an incoming request (as a Java Servlet) and dispatches it to
|
26
|
-
# the rack application setup via [rackup]. All this really involves
|
27
|
-
# is translating the various bits of the Servlet API into the Rack
|
28
|
-
# API on the way in, and translating the response back on the way
|
29
|
-
# out.
|
30
|
-
#
|
31
|
-
# Also, we implement a common extension to the Rack api for
|
32
|
-
# asynchronous request processing. We supply an 'async.callback'
|
33
|
-
# parameter in env to the Rack application. If we catch an
|
34
|
-
# :async symbol thrown by the app, we initiate a Jetty continuation.
|
35
|
-
#
|
36
|
-
# When 'async.callback' gets a response with empty headers and an
|
37
|
-
# empty body, we declare the async response finished.
|
38
|
-
#
|
39
|
-
def service(request, response)
|
40
|
-
# Turn the ServletRequest into a Rack env hash
|
41
|
-
env = servlet_to_rack(request)
|
42
|
-
|
43
|
-
# Handle asynchronous responses via Servlet continuations.
|
44
|
-
continuation = ContinuationSupport.getContinuation(request)
|
45
|
-
|
46
|
-
# If this is an expired connection, do nothing.
|
47
|
-
return if continuation.isExpired
|
48
|
-
|
49
|
-
# We should never be re-dispatched.
|
50
|
-
raise("Request re-dispatched.") unless continuation.isInitial
|
51
|
-
|
52
|
-
# Add our own special bits to the rack environment so that
|
53
|
-
# Rack middleware can have access to the Java internals.
|
54
|
-
env['rack.java.servlet'] = true
|
55
|
-
env['rack.java.servlet.request'] = request
|
56
|
-
env['rack.java.servlet.response'] = response
|
57
|
-
env['rack.java.servlet.continuation'] = continuation
|
58
|
-
|
59
|
-
# Add an callback that can be used to add results to the
|
60
|
-
# response asynchronously.
|
61
|
-
env['async.callback'] = lambda do |rack_response|
|
62
|
-
servlet_response = continuation.getServletResponse
|
63
|
-
rack_to_servlet(rack_response, servlet_response) \
|
64
|
-
and continuation.complete
|
65
|
-
end
|
66
|
-
|
67
|
-
# Execute the Rack request.
|
68
|
-
catch(:async) do
|
69
|
-
rack_response = @app.call(env)
|
70
|
-
|
71
|
-
# For apps that don't throw :async.
|
72
|
-
unless(rack_response[0] == -1)
|
73
|
-
# Nope, nothing asynchronous here.
|
74
|
-
rack_to_servlet(rack_response, response)
|
75
|
-
return
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# If we got here, this is a continuation.
|
80
|
-
continuation.suspend(response)
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
#
|
86
|
-
# Turns a Servlet request into a Rack request hash.
|
87
|
-
#
|
88
|
-
def servlet_to_rack(request)
|
89
|
-
# The Rack request that we will pass on.
|
90
|
-
env = Hash.new
|
91
|
-
|
92
|
-
# Map Servlet bits to Rack bits.
|
93
|
-
env['REQUEST_METHOD'] = request.getMethod
|
94
|
-
env['QUERY_STRING'] = request.getQueryString.to_s
|
95
|
-
env['SERVER_NAME'] = request.getServerName
|
96
|
-
env['SERVER_PORT'] = request.getServerPort.to_s
|
97
|
-
env['rack.version'] = Rack::VERSION
|
98
|
-
env['rack.url_scheme'] = request.getScheme
|
99
|
-
env['HTTP_VERSION'] = request.getProtocol
|
100
|
-
env["SERVER_PROTOCOL"] = request.getProtocol
|
101
|
-
env['REMOTE_ADDR'] = request.getRemoteAddr
|
102
|
-
env['REMOTE_HOST'] = request.getRemoteHost
|
103
|
-
|
104
|
-
# request.getPathInfo seems to be blank, so we're using the URI.
|
105
|
-
env['REQUEST_PATH'] = request.getRequestURI
|
106
|
-
env['PATH_INFO'] = request.getRequestURI
|
107
|
-
env['SCRIPT_NAME'] = ""
|
108
|
-
|
109
|
-
# Rack says URI, but it hands off a URL.
|
110
|
-
env['REQUEST_URI'] = request.getRequestURL.toString
|
111
|
-
|
112
|
-
# Java chops off the query string, but a Rack application will
|
113
|
-
# expect it, so we'll add it back if present
|
114
|
-
env['REQUEST_URI'] << "?#{env['QUERY_STRING']}" \
|
115
|
-
if env['QUERY_STRING']
|
116
|
-
|
117
|
-
# JRuby is like the matrix, only there's no spoon or fork().
|
118
|
-
env['rack.multiprocess'] = false
|
119
|
-
env['rack.multithread'] = true
|
120
|
-
env['rack.run_once'] = false
|
121
|
-
|
122
|
-
# Populate the HTTP headers.
|
123
|
-
request.getHeaderNames.each do |header_name|
|
124
|
-
header = header_name.upcase.tr('-', '_')
|
125
|
-
env["HTTP_#{header}"] = request.getHeader(header_name)
|
126
|
-
end
|
127
|
-
|
128
|
-
# Rack Weirdness: HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH
|
129
|
-
# both need to have the HTTP_ part dropped.
|
130
|
-
env["CONTENT_TYPE"] = env.delete("HTTP_CONTENT_TYPE") \
|
131
|
-
if env["HTTP_CONTENT_TYPE"]
|
132
|
-
env["CONTENT_LENGTH"] = env.delete("HTTP_CONTENT_LENGTH") \
|
133
|
-
if env["HTTP_CONTENT_LENGTH"]
|
134
|
-
|
135
|
-
# The input stream is a wrapper around the Java InputStream.
|
136
|
-
env['rack.input'] = request.getInputStream.to_io
|
137
|
-
|
138
|
-
# The output stream defaults to stderr.
|
139
|
-
env['rack.errors'] ||= $stderr
|
140
|
-
|
141
|
-
# All done, hand back the Rack request.
|
142
|
-
return(env)
|
143
|
-
end
|
144
|
-
|
145
|
-
#
|
146
|
-
# Turns a Rack response into a Servlet response; can be called
|
147
|
-
# multiple times. Returns true if this is the full request (either
|
148
|
-
# a synchronous request or the last part of an async request),
|
149
|
-
# false otherwise.
|
150
|
-
#
|
151
|
-
# Note that keep-alive *only* happens if we get either a pathname
|
152
|
-
# (because we can find the length ourselves), or if we get a
|
153
|
-
# Content-Length header as part of the response. While we can
|
154
|
-
# readily buffer the response object to figure out how long it is,
|
155
|
-
# we have no guarantee that we aren't going to be buffering
|
156
|
-
# something *huge*.
|
157
|
-
#
|
158
|
-
# http://docstore.mik.ua/orelly/java-ent/servlet/ch05_03.htm
|
159
|
-
#
|
160
|
-
def rack_to_servlet(rack_response, response)
|
161
|
-
# Split apart the Rack response.
|
162
|
-
status, headers, body = rack_response
|
163
|
-
|
164
|
-
# We assume the request is finished if we got empty headers,
|
165
|
-
# an empty body, and we have a committed response.
|
166
|
-
finished = (headers.empty? and \
|
167
|
-
body.respond_to?(:empty?) and body.empty?)
|
168
|
-
return(true) if (finished and response.isCommitted)
|
169
|
-
|
170
|
-
# No need to send headers again if we've already shipped
|
171
|
-
# data out on an async request.
|
172
|
-
unless(response.isCommitted)
|
173
|
-
# Set the HTTP status code.
|
174
|
-
response.setStatus(status)
|
175
|
-
|
176
|
-
# Did we get a Content-Length header?
|
177
|
-
content_length = headers.delete('Content-Length')
|
178
|
-
response.setContentLength(content_length.to_i) \
|
179
|
-
if content_length
|
180
|
-
|
181
|
-
# Add all the result headers.
|
182
|
-
headers.each { |h, v| response.addHeader(h, v) }
|
183
|
-
end
|
184
|
-
|
185
|
-
# How else would we write output?
|
186
|
-
output = response.getOutputStream
|
187
|
-
|
188
|
-
# Turn the body into something nice and Java-y.
|
189
|
-
if(body.respond_to?(:to_path))
|
190
|
-
# We've been told to serve a file; use FileInputStream to
|
191
|
-
# stream the file directly to the servlet, because this
|
192
|
-
# is a lot faster than doing it with Ruby.
|
193
|
-
file = java.io.File.new(body.to_path)
|
194
|
-
|
195
|
-
# We set the content-length so we can use Keep-Alive,
|
196
|
-
# unless this is an async request.
|
197
|
-
response.setContentLength(file.length) \
|
198
|
-
unless content_length
|
199
|
-
|
200
|
-
# Stream the file directly.
|
201
|
-
buffer = Java::byte[4096].new
|
202
|
-
input_stream = FileInputStream.new(file)
|
203
|
-
while((count = input_stream.read(buffer)) != -1)
|
204
|
-
output.write(buffer, 0, count)
|
205
|
-
end
|
206
|
-
input_stream.close
|
207
|
-
else
|
208
|
-
body.each { |l| output.write(l.to_java_bytes) }
|
209
|
-
end
|
210
|
-
|
211
|
-
# Close the body if we're supposed to.
|
212
|
-
body.close if body.respond_to?(:close)
|
213
|
-
|
214
|
-
# All done.
|
215
|
-
output.flush
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|