remi-rails-rack-adapter 1.0.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/COPYING +18 -0
- data/README.rdoc +17 -0
- data/Rakefile +57 -0
- data/VERSION.yml +4 -0
- data/lib/rack/adapter/rails.rb +167 -0
- data/lib/rails-rack-adapter.rb +9 -0
- metadata +61 -0
data/COPYING
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2008 Marc-Andre Cournoyer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= Rails Rack Adapter
|
2
|
+
|
3
|
+
This is the Rack::Adapter::Rails from Thin, extracted out
|
4
|
+
|
5
|
+
See COPYING for the original license (c) 2008 Marc-Andre Cournoyer
|
6
|
+
|
7
|
+
Often times, I've needed this adapter but haven't needed Thin (even though Thin absolutely ROCKS)
|
8
|
+
|
9
|
+
sooooo ... now you should be able to:
|
10
|
+
|
11
|
+
sudo gem install remi-rails-rack-adapter
|
12
|
+
|
13
|
+
>> require 'rails-rack-adapter'
|
14
|
+
>> Rack::Hander::Foo.run Rack::Rails::Adapter.new :root => 'some/dir', :environment => 'development'
|
15
|
+
|
16
|
+
Hopefully this won't be necessary for Rails 2.3, which is finally built on Rack, but it's
|
17
|
+
very helpful for Rails < 2.3
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |s|
|
9
|
+
s.name = "rails-rack-adapter"
|
10
|
+
s.summary = "Thin's Rack::Adapter::Rails extracted to its own gem"
|
11
|
+
s.email = "remi@remitaylor.com"
|
12
|
+
s.homepage = "http://github.com/remi/rails-rack-adapter"
|
13
|
+
s.description = "Thin's Rack::Adapter::Rails extracted to its own gem"
|
14
|
+
s.authors = %w( remi )
|
15
|
+
s.files = FileList["[A-Z]*", "{lib,spec,examples,rails_generators}/**/*"]
|
16
|
+
# s.executables = "neato"
|
17
|
+
# s.add_dependency 'person-project'
|
18
|
+
end
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
21
|
+
end
|
22
|
+
|
23
|
+
Spec::Rake::SpecTask.new do |t|
|
24
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Run all examples with RCov"
|
28
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
29
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
30
|
+
t.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
Rake::RDocTask.new do |rdoc|
|
34
|
+
rdoc.rdoc_dir = 'rdoc'
|
35
|
+
rdoc.title = 'rails-rack-adapter'
|
36
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
37
|
+
rdoc.rdoc_files.include('README*')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Confirm that gemspec is $SAFE'
|
42
|
+
task :safe do
|
43
|
+
require 'yaml'
|
44
|
+
require 'rubygems/specification'
|
45
|
+
data = File.read('rails-rack-adapter.gemspec')
|
46
|
+
spec = nil
|
47
|
+
if data !~ %r{!ruby/object:Gem::Specification}
|
48
|
+
Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
|
49
|
+
else
|
50
|
+
spec = YAML.load(data)
|
51
|
+
end
|
52
|
+
spec.validate
|
53
|
+
puts spec
|
54
|
+
puts "OK"
|
55
|
+
end
|
56
|
+
|
57
|
+
task :default => :spec
|
data/VERSION.yml
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
# Adapter to run a Rails app with any supported Rack handler.
|
4
|
+
# By default it will try to load the Rails application in the
|
5
|
+
# current directory in the development environment.
|
6
|
+
#
|
7
|
+
# Options:
|
8
|
+
# root: Root directory of the Rails app
|
9
|
+
# environment: Rails environment to run in (development [default], production or test)
|
10
|
+
# prefix: Set the relative URL root.
|
11
|
+
#
|
12
|
+
# Based on http://fuzed.rubyforge.org/ Rails adapter
|
13
|
+
module Rack
|
14
|
+
module Adapter
|
15
|
+
class Rails
|
16
|
+
FILE_METHODS = %w(GET HEAD).freeze
|
17
|
+
|
18
|
+
def initialize(options={})
|
19
|
+
@root = options[:root] || Dir.pwd
|
20
|
+
@env = options[:environment] || 'development'
|
21
|
+
@prefix = options[:prefix]
|
22
|
+
|
23
|
+
load_application
|
24
|
+
|
25
|
+
@file_server = Rack::File.new(::File.join(RAILS_ROOT, "public"))
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_application
|
29
|
+
ENV['RAILS_ENV'] = @env
|
30
|
+
|
31
|
+
require "#{@root}/config/environment"
|
32
|
+
require 'dispatcher'
|
33
|
+
|
34
|
+
ActionController::AbstractRequest.relative_url_root = @prefix if @prefix
|
35
|
+
end
|
36
|
+
|
37
|
+
# TODO refactor this in File#can_serve?(path) ??
|
38
|
+
def file_exist?(path)
|
39
|
+
full_path = ::File.join(@file_server.root, Utils.unescape(path))
|
40
|
+
::File.file?(full_path) && ::File.readable_real?(full_path)
|
41
|
+
end
|
42
|
+
|
43
|
+
def serve_file(env)
|
44
|
+
@file_server.call(env)
|
45
|
+
end
|
46
|
+
|
47
|
+
def serve_rails(env)
|
48
|
+
request = Request.new(env)
|
49
|
+
response = Response.new
|
50
|
+
|
51
|
+
session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS
|
52
|
+
cgi = CGIWrapper.new(request, response)
|
53
|
+
|
54
|
+
Dispatcher.dispatch(cgi, session_options, response)
|
55
|
+
|
56
|
+
response.finish
|
57
|
+
end
|
58
|
+
|
59
|
+
def call(env)
|
60
|
+
path = env['PATH_INFO'].chomp('/')
|
61
|
+
method = env['REQUEST_METHOD']
|
62
|
+
cached_path = (path.empty? ? 'index' : path) + ActionController::Base.page_cache_extension
|
63
|
+
|
64
|
+
if FILE_METHODS.include?(method)
|
65
|
+
if file_exist?(path) # Serve the file if it's there
|
66
|
+
return serve_file(env)
|
67
|
+
elsif file_exist?(cached_path) # Serve the page cache if it's there
|
68
|
+
env['PATH_INFO'] = cached_path
|
69
|
+
return serve_file(env)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# No static file, let Rails handle it
|
74
|
+
serve_rails(env)
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
class CGIWrapper < ::CGI
|
80
|
+
def initialize(request, response, *args)
|
81
|
+
@request = request
|
82
|
+
@response = response
|
83
|
+
@args = *args
|
84
|
+
@input = request.body
|
85
|
+
|
86
|
+
super *args
|
87
|
+
end
|
88
|
+
|
89
|
+
def header(options = "text/html")
|
90
|
+
if options.is_a?(String)
|
91
|
+
@response['Content-Type'] = options unless @response['Content-Type']
|
92
|
+
else
|
93
|
+
@response['Content-Length'] = options.delete('Content-Length').to_s if options['Content-Length']
|
94
|
+
|
95
|
+
@response['Content-Type'] = options.delete('type') || "text/html"
|
96
|
+
@response['Content-Type'] += "; charset=" + options.delete('charset') if options['charset']
|
97
|
+
|
98
|
+
@response['Content-Language'] = options.delete('language') if options['language']
|
99
|
+
@response['Expires'] = options.delete('expires') if options['expires']
|
100
|
+
|
101
|
+
@response.status = options.delete('Status') if options['Status']
|
102
|
+
|
103
|
+
# Convert 'cookie' header to 'Set-Cookie' headers.
|
104
|
+
# Because Set-Cookie header can appear more the once in the response body,
|
105
|
+
# we store it in a line break seperated string that will be translated to
|
106
|
+
# multiple Set-Cookie header by the handler.
|
107
|
+
if cookie = options.delete('cookie')
|
108
|
+
cookies = []
|
109
|
+
|
110
|
+
case cookie
|
111
|
+
when Array then cookie.each { |c| cookies << c.to_s }
|
112
|
+
when Hash then cookie.each { |_, c| cookies << c.to_s }
|
113
|
+
else cookies << cookie.to_s
|
114
|
+
end
|
115
|
+
|
116
|
+
@output_cookies.each { |c| cookies << c.to_s } if @output_cookies
|
117
|
+
|
118
|
+
@response['Set-Cookie'] = [@response['Set-Cookie'], cookies].compact
|
119
|
+
# See http://groups.google.com/group/rack-devel/browse_thread/thread/e8759b91a82c5a10/a8dbd4574fe97d69?#a8dbd4574fe97d69
|
120
|
+
if Thin.ruby_18?
|
121
|
+
@response['Set-Cookie'].flatten!
|
122
|
+
else
|
123
|
+
@response['Set-Cookie'] = @response['Set-Cookie'].join("\n")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
options.each { |k,v| @response[k] = v }
|
128
|
+
end
|
129
|
+
|
130
|
+
""
|
131
|
+
end
|
132
|
+
|
133
|
+
def params
|
134
|
+
@params ||= @request.params
|
135
|
+
end
|
136
|
+
|
137
|
+
def cookies
|
138
|
+
@request.cookies
|
139
|
+
end
|
140
|
+
|
141
|
+
def query_string
|
142
|
+
@request.query_string
|
143
|
+
end
|
144
|
+
|
145
|
+
# Used to wrap the normal args variable used inside CGI.
|
146
|
+
def args
|
147
|
+
@args
|
148
|
+
end
|
149
|
+
|
150
|
+
# Used to wrap the normal env_table variable used inside CGI.
|
151
|
+
def env_table
|
152
|
+
@request.env
|
153
|
+
end
|
154
|
+
|
155
|
+
# Used to wrap the normal stdinput variable used inside CGI.
|
156
|
+
def stdinput
|
157
|
+
@input
|
158
|
+
end
|
159
|
+
|
160
|
+
def stdoutput
|
161
|
+
STDERR.puts "stdoutput should not be used."
|
162
|
+
@response.body
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: remi-rails-rack-adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- remi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-10 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Thin's Rack::Adapter::Rails extracted to its own gem
|
17
|
+
email: remi@remitaylor.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- Rakefile
|
26
|
+
- VERSION.yml
|
27
|
+
- COPYING
|
28
|
+
- README.rdoc
|
29
|
+
- lib/rack
|
30
|
+
- lib/rack/adapter
|
31
|
+
- lib/rack/adapter/rails.rb
|
32
|
+
- lib/rails-rack-adapter.rb
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://github.com/remi/rails-rack-adapter
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options:
|
37
|
+
- --inline-source
|
38
|
+
- --charset=UTF-8
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.2.0
|
57
|
+
signing_key:
|
58
|
+
specification_version: 2
|
59
|
+
summary: Thin's Rack::Adapter::Rails extracted to its own gem
|
60
|
+
test_files: []
|
61
|
+
|