rack-jetty 0.1.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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Graham Batty
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/README.rdoc ADDED
@@ -0,0 +1,29 @@
1
+ = rack-jetty
2
+
3
+ Provides a nice simple Rack Adapter for Jetty under JRuby. Once installed, you can use rackup to start it with:
4
+
5
+ jruby -S rackup -s Jetty myapp.ru # the -S tells it to search your bin paths for rackup
6
+
7
+ Or with Rails:
8
+
9
+ jruby script/server Jetty # no -S needed since it's a relative path
10
+
11
+ The code for this is intended to be very easy to understand and is entirely done in Ruby, without the help of jruby-rack, so it should be pretty hackable.
12
+
13
+ Note that if you want to run this as a real server (or for benchmarking), you'll probably want to run jruby with --server so it actually does JIT optimization and the like.
14
+
15
+ Inspiration credit for this project goes out to Vladimir Dobriakov of Vodafone who wrote jetty-rackup, which wasn't quite what I needed but gave me a hell of a starting point for making this go. Thanks, Vladimir!
16
+
17
+ == Note on Patches/Pull Requests
18
+
19
+ * Fork the project.
20
+ * Make your feature addition or bug fix.
21
+ * Add tests for it. This is important so I don't break it in a
22
+ future version unintentionally.
23
+ * Commit, do not mess with rakefile, version, or history.
24
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
25
+ * Send me a pull request. Bonus points for topic branches.
26
+
27
+ == Copyright
28
+
29
+ Copyright (c) 2010 Graham Batty. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rack-jetty"
8
+ gem.summary = %Q{Very simple (mostly Ruby) implementation of jetty as a pure Rack adapter.}
9
+ gem.description = %Q{Allows you to use Jetty as a Rack adapter in JRuby. Compatible with rackup and rails' Rack support.}
10
+ gem.email = "graham@stormbrew.ca"
11
+ gem.homepage = "http://github.com/stormbrew/rack-jetty"
12
+ gem.authors = ["Graham Batty"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_dependency "rack", ">= 1.0.0"
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'spec/rake/spectask'
23
+ Spec::Rake::SpecTask.new(:spec) do |spec|
24
+ spec.libs << 'lib' << 'spec'
25
+ spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.pattern = 'spec/**/*_spec.rb'
31
+ spec.rcov = true
32
+ end
33
+
34
+ task :spec => :check_dependencies
35
+
36
+ task :default => :spec
37
+
38
+ require 'rake/rdoctask'
39
+ Rake::RDocTask.new do |rdoc|
40
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = "rack-jetty #{version}"
44
+ rdoc.rdoc_files.include('README*')
45
+ rdoc.rdoc_files.include('lib/**/*.rb')
46
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,47 @@
1
+ require 'rack_jetty/java_input'
2
+ require 'rack_jetty/servlet_handler'
3
+
4
+ module Rack
5
+ module Handler
6
+ class Jetty
7
+ attr_reader :app
8
+ attr_reader :options
9
+
10
+ def initialize(app, options={})
11
+ @app = app
12
+ @options = options
13
+ end
14
+
15
+ def self.run(app, options = {})
16
+ new(app,options).run()
17
+ end
18
+
19
+ def run()
20
+ @connector = Java::org.mortbay.jetty.bio.SocketConnector.new
21
+ @connector.set_host(options[:Host])
22
+ @connector.set_port(options[:Port].to_i)
23
+
24
+ @jetty = Java::org.mortbay.jetty.Server.new
25
+ @jetty.addConnector(@connector)
26
+
27
+ bridge = RackJetty::ServletHandler.new
28
+ bridge.handler = self
29
+
30
+ @jetty.set_handler(bridge)
31
+ @jetty.start
32
+ end
33
+
34
+ def running?
35
+ @jetty && @jetty.is_started
36
+ end
37
+
38
+ def stopped?
39
+ !@jetty || @jetty.is_stopped
40
+ end
41
+
42
+ def stop()
43
+ @jetty && @jetty.stop
44
+ end
45
+ end
46
+ end
47
+ end
Binary file
Binary file
Binary file
@@ -0,0 +1,48 @@
1
+ module RackJetty
2
+ class JavaInput
3
+ def initialize(input)
4
+ @input = input
5
+ end
6
+
7
+ # reads count bytes into into_buffer, returns nil at EOF, otherwise
8
+ # returns into_buffer.
9
+ def read_bytes(count, into_buffer)
10
+ data = "\0" * count
11
+ data = data.to_java_bytes
12
+ count = @input.read(data, 0, count)
13
+ if (count == -1)
14
+ return nil
15
+ end
16
+ into_buffer << String.from_java_bytes(data[0,count])
17
+ return into_buffer
18
+ end
19
+
20
+ # Reads the entire string into_buffer
21
+ def read_all(into_buffer)
22
+ while (read_bytes(4096, into_buffer))
23
+ # work is in the loop condition.
24
+ end
25
+ return into_buffer
26
+ end
27
+
28
+ # If count is nil, reads the entire input into the buffer. Otherwise,
29
+ # reads up to count bytes from the stream and puts them into buffer.
30
+ # either way, returns buffer.
31
+ def read(count = nil, buffer = "")
32
+ if (count.nil?)
33
+ read_all(buffer)
34
+ else
35
+ buffer = read_bytes(count, buffer)
36
+ end
37
+ return buffer
38
+ end
39
+ alias_method :gets, :read
40
+
41
+ # Reads the input as chunked data and yields it piece by piece.
42
+ def each
43
+ while (s = read_bytes(4096, ""))
44
+ yield s
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,72 @@
1
+ require 'rack'
2
+ require 'rack/rewindable_input'
3
+
4
+ Dir[::File.join(::File.dirname(__FILE__), 'jars', '*.jar')].each { |jar| require jar }
5
+
6
+ module RackJetty
7
+ class ServletHandler < Java::org.mortbay.jetty.handler.AbstractHandler
8
+ attr_accessor :handler
9
+
10
+ DefaultRackEnv = {
11
+ 'rack.version' => ::Rack::VERSION,
12
+ 'rack.multithread' => true,
13
+ 'rack.multiprocess' => false,
14
+ 'rack.run_once' => false,
15
+ 'rack.errors' => $stderr,
16
+ 'jruby.version' => JRUBY_VERSION,
17
+ 'SCRIPT_NAME' => '',
18
+ }
19
+
20
+ def handle(target, request, response, dispatch)
21
+ begin
22
+ env = DefaultRackEnv.merge({
23
+ 'rack.input' => Rack::RewindableInput.new(JavaInput.new(request.get_input_stream)),
24
+ 'rack.url_scheme' => request.get_scheme,
25
+ 'CONTENT_TYPE' => request.get_content_type.to_s,
26
+ 'CONTENT_LENGTH' => request.get_content_length, # some post-processing done below
27
+ 'REQUEST_METHOD' => request.get_method || "GET",
28
+ 'REQUEST_URI' => request.getRequestURI,
29
+ 'PATH_INFO' => request.get_path_info,
30
+ 'QUERY_STRING' => request.get_query_string || "",
31
+ 'SERVER_NAME' => request.get_server_name || "",
32
+ 'REMOTE_HOST' => request.get_remote_host || "",
33
+ 'REMOTE_ADDR' => request.get_remote_addr || "",
34
+ 'REMOTE_USER' => request.get_remote_user || "",
35
+ 'SERVER_PORT' => request.get_server_port.to_s
36
+ })
37
+ env['CONTENT_LENGTH'] = env['CONTENT_LENGTH'] >= 0? env['CONTENT_LENGTH'].to_s : "0"
38
+ request.get_header_names.each do |h|
39
+ next if h =~ /^Content-(Type|Length)$/i
40
+ k = "HTTP_#{h.upcase.gsub(/-/, '_')}"
41
+ env[k] = request.getHeader(h) unless env.has_key?(k)
42
+ end
43
+
44
+ status, headers, output = handler.app.call(env)
45
+
46
+ if (match = %r{^([0-9]{3,3}) +([[:print:]]+)$}.match(status.to_s))
47
+ response.set_status(match[1].to_i, match[2].to_s)
48
+ else
49
+ response.set_status(status.to_i)
50
+ end
51
+
52
+ headers.each do |k, v|
53
+ case k
54
+ when 'Content-Type'
55
+ response.set_content_type(v)
56
+ when 'Content-Length'
57
+ response.set_content_length(v.to_i)
58
+ else
59
+ response.set_header(k, v)
60
+ end
61
+ end
62
+
63
+ buffer = response.get_output_stream
64
+ output.each do |s|
65
+ buffer.print(s)
66
+ end
67
+ ensure
68
+ request.set_handled(true)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,62 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'rack/handler/jetty'
3
+ require 'rack/lint'
4
+
5
+ describe Rack::Handler::Jetty do
6
+ include TestRequest::Helpers
7
+
8
+ before :all do
9
+ @server = Rack::Handler::Jetty.new(Rack::Lint.new(TestRequest.new), :Host => @host='0.0.0.0',:Port => @port=9204)
10
+ Thread.new do
11
+ @server.run
12
+ end
13
+ Thread.pass until @server.running?
14
+ end
15
+
16
+ after :all do
17
+ @server.stop
18
+ Thread.pass until @server.stopped?
19
+ end
20
+
21
+ it "should respond to a simple get request" do
22
+ GET "/"
23
+ status.should == 200
24
+ end
25
+
26
+ it "should have CGI headers on GET" do
27
+ GET("/")
28
+ response["REQUEST_METHOD"].should == "GET"
29
+ response["SCRIPT_NAME"].should == ''
30
+ response["PATH_INFO"].should == "/"
31
+ response["QUERY_STRING"].should == ""
32
+ response["test.postdata"].should == ""
33
+
34
+ GET("/test/foo?quux=1")
35
+ response["REQUEST_METHOD"].should == "GET"
36
+ response["SCRIPT_NAME"].should == ''
37
+ response["REQUEST_URI"].should == "/test/foo"
38
+ response["PATH_INFO"].should == "/test/foo"
39
+ response["QUERY_STRING"].should == "quux=1"
40
+ end
41
+
42
+ it "should have CGI headers on POST" do
43
+ POST("/", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
44
+ status.should == 200
45
+ response["REQUEST_METHOD"].should == "POST"
46
+ response["REQUEST_URI"].should == "/"
47
+ response["QUERY_STRING"].should == ""
48
+ response["HTTP_X_TEST_HEADER"].should == "42"
49
+ response["test.postdata"].should == "rack-form-data=23"
50
+ end
51
+
52
+ it "should support HTTP auth" do
53
+ GET("/test", {:user => "ruth", :passwd => "secret"})
54
+ response["HTTP_AUTHORIZATION"].should == "Basic cnV0aDpzZWNyZXQ="
55
+ end
56
+
57
+ it "should set status" do
58
+ GET("/test?secret")
59
+ status.should == 403
60
+ response["rack.url_scheme"].should == "http"
61
+ end
62
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,70 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rubygems'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+ require 'yaml'
7
+ require 'net/http'
8
+
9
+ Spec::Runner.configure do |config|
10
+
11
+ end
12
+
13
+ # Borrowed from Rack's own specs.
14
+ class TestRequest
15
+ def call(env)
16
+ status = env["QUERY_STRING"] =~ /secret/ ? 403 : 200
17
+ env["test.postdata"] = env["rack.input"].read
18
+ body = env.to_yaml
19
+ size = body.respond_to?(:bytesize) ? body.bytesize : body.size
20
+ [status, {"Content-Type" => "text/yaml", "Content-Length" => size.to_s}, [body]]
21
+ end
22
+
23
+ module Helpers
24
+ attr_reader :status, :response
25
+
26
+ ROOT = File.expand_path(File.dirname(__FILE__) + "/..")
27
+ ENV["RUBYOPT"] = "-I#{ROOT}/lib -rubygems"
28
+
29
+ def root
30
+ ROOT
31
+ end
32
+
33
+ def rackup
34
+ "#{ROOT}/bin/rackup"
35
+ end
36
+
37
+ def GET(path, header={})
38
+ Net::HTTP.start(@host, @port) { |http|
39
+ user = header.delete(:user)
40
+ passwd = header.delete(:passwd)
41
+
42
+ get = Net::HTTP::Get.new(path, header)
43
+ get.basic_auth user, passwd if user && passwd
44
+ http.request(get) { |response|
45
+ @status = response.code.to_i
46
+ begin
47
+ @response = YAML.load(response.body)
48
+ rescue ArgumentError
49
+ @response = nil
50
+ end
51
+ }
52
+ }
53
+ end
54
+
55
+ def POST(path, formdata={}, header={})
56
+ Net::HTTP.start(@host, @port) { |http|
57
+ user = header.delete(:user)
58
+ passwd = header.delete(:passwd)
59
+
60
+ post = Net::HTTP::Post.new(path, header)
61
+ post.form_data = formdata
62
+ post.basic_auth user, passwd if user && passwd
63
+ http.request(post) { |response|
64
+ @status = response.code.to_i
65
+ @response = YAML.load(response.body)
66
+ }
67
+ }
68
+ end
69
+ end
70
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-jetty
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Graham Batty
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-13 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
31
+ version: 1.2.9
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rack
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 0
44
+ - 0
45
+ version: 1.0.0
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ description: Allows you to use Jetty as a Rack adapter in JRuby. Compatible with rackup and rails' Rack support.
49
+ email: graham@stormbrew.ca
50
+ executables: []
51
+
52
+ extensions: []
53
+
54
+ extra_rdoc_files:
55
+ - LICENSE
56
+ - README.rdoc
57
+ files:
58
+ - .document
59
+ - .gitignore
60
+ - LICENSE
61
+ - README.rdoc
62
+ - Rakefile
63
+ - VERSION
64
+ - lib/rack/handler/jetty.rb
65
+ - lib/rack_jetty/jars/core-3.1.1.jar
66
+ - lib/rack_jetty/jars/jetty-6.1.14.jar
67
+ - lib/rack_jetty/jars/jetty-plus-6.1.14.jar
68
+ - lib/rack_jetty/jars/jetty-util-6.1.14.jar
69
+ - lib/rack_jetty/jars/jsp-2.1.jar
70
+ - lib/rack_jetty/jars/jsp-api-2.1.jar
71
+ - lib/rack_jetty/jars/servlet-api-2.5-6.1.14.jar
72
+ - lib/rack_jetty/java_input.rb
73
+ - lib/rack_jetty/servlet_handler.rb
74
+ - spec/rack_handler_jetty_spec.rb
75
+ - spec/spec.opts
76
+ - spec/spec_helper.rb
77
+ has_rdoc: true
78
+ homepage: http://github.com/stormbrew/rack-jetty
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --charset=UTF-8
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project:
103
+ rubygems_version: 1.3.6
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Very simple (mostly Ruby) implementation of jetty as a pure Rack adapter.
107
+ test_files:
108
+ - spec/rack_handler_jetty_spec.rb
109
+ - spec/spec_helper.rb