rack-jetty 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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