ajp-rails 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +504 -0
- data/Install.en +231 -0
- data/Install.ja +250 -0
- data/NEWS.en +6 -0
- data/NEWS.ja +6 -0
- data/README.en +80 -0
- data/README.ja +77 -0
- data/Rakefile +22 -0
- data/ajp-rails.gemspec +24 -0
- data/bin/ajp-rails.rb +4 -0
- data/example/example.config.yml +5 -0
- data/example/example.htaccess +30 -0
- data/example/example.workers.proerties +11 -0
- data/lib/ajp-rails/ajp_rails_dispatcher.rb +40 -0
- data/lib/ajp-rails/rails-runner.rb +162 -0
- data/lib/ajp-rails/rails-wrapper.rb +289 -0
- data/setup.rb +1585 -0
- metadata +64 -0
data/bin/ajp-rails.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
# Assumes that follwing are set in ServerConfig or VirtualHost
|
3
|
+
# JkMount /ajp-mounted/* ajprails
|
4
|
+
# JkEnvVar SERVER_SOFTWARE NONE
|
5
|
+
|
6
|
+
|
7
|
+
Options +FollowSymLinks
|
8
|
+
|
9
|
+
# If you don't want Rails to look in certain directories,
|
10
|
+
# use the following rewrite rules so that Apache won't rewrite certain requests
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# RewriteCond %{REQUEST_URI} ^/notrails.*
|
14
|
+
# RewriteRule .* - [L]
|
15
|
+
|
16
|
+
# Redirect all requests not available on the filesystem to Rails
|
17
|
+
RewriteEngine On
|
18
|
+
RewriteBase /example
|
19
|
+
RewriteRule ^$ index.html [QSA]
|
20
|
+
RewriteRule ^([^.]+)$ $1.html [QSA]
|
21
|
+
RewriteCond %{REQUEST_FILENAME} !-f
|
22
|
+
RewriteRule ^(.*)$ /ajp-mounted/$1 [QSA,L]
|
23
|
+
|
24
|
+
# In case Rails experiences terminal errors
|
25
|
+
# Instead of displaying this message you can supply a file here which will be rendered instead
|
26
|
+
#
|
27
|
+
# Example:
|
28
|
+
# ErrorDocument 500 /500.html
|
29
|
+
|
30
|
+
ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'dispatcher'
|
2
|
+
require 'net/ajp13/server'
|
3
|
+
require File.dirname(__FILE__) + File::SEPARATOR + 'rails-wrapper.rb'
|
4
|
+
|
5
|
+
class AjpRailsDispatcher < Dispatcher
|
6
|
+
class << self
|
7
|
+
# Dispatch the given AJP request, using the given session options, and
|
8
|
+
# returns the response object.
|
9
|
+
#--
|
10
|
+
# Be sure to handle the exceptions it raises
|
11
|
+
# on multipart requests (EOFError and ArgumentError).
|
12
|
+
#++
|
13
|
+
def dispatch(ajp_req, session_options, server_environments)
|
14
|
+
request = AjpRailsRequest.new(ajp_req, session_options, server_environments)
|
15
|
+
response = AjpRailsResponse.new
|
16
|
+
prepare_application
|
17
|
+
ActionController::Routing::Routes.recognize!(request).process(request, response).to_ajp_response(ajp_req.output_cookies)
|
18
|
+
rescue Object => exception
|
19
|
+
puts exception.message + ":" + exception.backtrace.join("\n")
|
20
|
+
failsafe_response(500) do
|
21
|
+
ActionController::Base.process_with_exception(request, AjpRailsResponse.new, exception).to_ajp_response(ajp_req.output_cookies)
|
22
|
+
end
|
23
|
+
ensure
|
24
|
+
# Do not give a failsafe response here.
|
25
|
+
reset_after_dispatch
|
26
|
+
end
|
27
|
+
|
28
|
+
# If the block raises, send status code as a last-ditch response.
|
29
|
+
def failsafe_response(status)
|
30
|
+
yield
|
31
|
+
rescue Object
|
32
|
+
begin
|
33
|
+
Net::AJP13::Response.new(status)
|
34
|
+
rescue Object
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
@@ -0,0 +1,162 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 Yugui <yugui@yugui.sakura.ne.jp>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or
|
5
|
+
# modify it under the terms of the GNU Lesser General Public
|
6
|
+
# License as published by the Free Software Foundation; version 2.1
|
7
|
+
# of the License
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this program; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
#++
|
18
|
+
require 'rubygems' rescue nil
|
19
|
+
require 'optparse'
|
20
|
+
require File.dirname(__FILE__) + File::SEPARATOR + 'ajp_rails_dispatcher.rb'
|
21
|
+
|
22
|
+
#
|
23
|
+
# AJP server that dispatches AJP requests into Rails.
|
24
|
+
#
|
25
|
+
class RailsRunner < Net::AJP13::Server
|
26
|
+
# +option+:: Hash which contains server-wide options.
|
27
|
+
def initialize(options)
|
28
|
+
super(options['BIND_IP'], options['AJP_PORT'])
|
29
|
+
@environment_options = options
|
30
|
+
end
|
31
|
+
|
32
|
+
# Dispatches +request+ into Rails and returns Net::AJP13::Response object
|
33
|
+
# which contains the result of Rails processing.
|
34
|
+
#
|
35
|
+
# +request+:: Net::AJP13::Request object
|
36
|
+
def process_request(request)
|
37
|
+
logger.debug("processing #{request.path}")
|
38
|
+
response = AjpRailsDispatcher.dispatch(request, AjpRailsRequest::DEFAULT_SESSION_OPTIONS, @environment_options)
|
39
|
+
logger.debug("processed #{request.path}: #{response.code} #{response.message}")
|
40
|
+
response
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Maps long option names to internal hash keys.
|
45
|
+
OPTION_NAMES_TO_INTERNAL_NAMES = {
|
46
|
+
'port' => 'AJP_PORT',
|
47
|
+
'host' => 'BIND_IP',
|
48
|
+
'environment' => 'RAILS_ENV',
|
49
|
+
'location' => 'APP_LOCATION',
|
50
|
+
'directory' => 'APP_DIRECTORY',
|
51
|
+
'prefix' => 'DISPATCHER_PREFIX',
|
52
|
+
'suffix' => 'DISPATCHER_SUFFIX',
|
53
|
+
'daemon' => 'IS_DAEMON'
|
54
|
+
}
|
55
|
+
|
56
|
+
DEFAULT_OPTIONS = {
|
57
|
+
OPTION_NAMES_TO_INTERNAL_NAMES['environment'] =>
|
58
|
+
ENV['RAILS_ENV'] || 'production',
|
59
|
+
OPTION_NAMES_TO_INTERNAL_NAMES['port'] => Net::AJP13::Constants::DEFAULT_PORT,
|
60
|
+
OPTION_NAMES_TO_INTERNAL_NAMES['host'] => '127.0.0.1',
|
61
|
+
OPTION_NAMES_TO_INTERNAL_NAMES['location'] => '/',
|
62
|
+
OPTION_NAMES_TO_INTERNAL_NAMES['directory'] => '.'
|
63
|
+
}
|
64
|
+
|
65
|
+
# Parses command line options.
|
66
|
+
#
|
67
|
+
# Merges external configuration file into DEFAULT_OPTIONS if a file specified,
|
68
|
+
# and merges command line options, and returns merged options.
|
69
|
+
#
|
70
|
+
def parse_options
|
71
|
+
opts = DEFAULT_OPTIONS.dup
|
72
|
+
|
73
|
+
cmd_opts = {}
|
74
|
+
parser = OptionParser.new
|
75
|
+
parser.on('-p PORT', '--port=PORT',
|
76
|
+
"Listens to the specified port.\n" +
|
77
|
+
"Default: #{opts[OPTION_NAMES_TO_INTERNAL_NAMES['port']]}") { |v|
|
78
|
+
cmd_opts[OPTION_NAMES_TO_INTERNAL_NAMES['port']] = v
|
79
|
+
}
|
80
|
+
parser.on('-h IP', '--host=IP',
|
81
|
+
"Binds rails to the specified ip.\n" +
|
82
|
+
"Default: #{opts[OPTION_NAMES_TO_INTERNAL_NAMES['host']]}") {
|
83
|
+
cmd_opts[OPTION_NAMES_TO_INTERNAL_NAMES['host']] = v
|
84
|
+
}
|
85
|
+
parser.on('-e RAILS_ENV', '--environment=RAILS_ENV',
|
86
|
+
"Specifies the environment to run this server under (test/development/production).\n" +
|
87
|
+
"Default: ENV['RAILS_ENV'] || 'production'") { |v|
|
88
|
+
cmd_opts[OPTION_NAMES_TO_INTERNAL_NAMES['environment']] = v
|
89
|
+
}
|
90
|
+
parser.on('-l LOCATION', '--location=LOCATION',
|
91
|
+
"The base of the application's virtual path.\n" +
|
92
|
+
"Default: /") { |v|
|
93
|
+
cmd_opts[OPTION_NAMES_TO_INTERNAL_NAMES['location']] = v
|
94
|
+
}
|
95
|
+
parser.on('-d DIRECTORY', '--directory=DIRECTORY',
|
96
|
+
"The base of the application's physical path\n" +
|
97
|
+
"Default: #{opts[OPTION_NAMES_TO_INTERNAL_NAMES['directory']]}") { |v|
|
98
|
+
cmd_opts[OPTION_NAMES_TO_INTERNAL_NAMES['directory']] = v
|
99
|
+
}
|
100
|
+
parser.on('--prefix=PREFIX',
|
101
|
+
"The prefix of the ajp-mounted URLs.") { |v|
|
102
|
+
cmd_opts[OPTION_NAMES_TO_INTERNAL_NAMES['prefix']] = v
|
103
|
+
}
|
104
|
+
parser.on('--suffix=SUFFIX',
|
105
|
+
"The suffix of the ajp-mounted URLs.") { |v|
|
106
|
+
cmd_opts[OPTION_NAMES_TO_INTERNAL_NAMES['suffix']] = v
|
107
|
+
}
|
108
|
+
parser.on('--daemon', "Makes Rails run as a daemon") {|v|
|
109
|
+
cmd_opts[OPTION_NAMES_TO_INTERNAL_NAMES['daemon']] = v
|
110
|
+
}
|
111
|
+
|
112
|
+
parser.on('-c FILE', '--config=FILE',
|
113
|
+
'Reads options from the specified file. ' +
|
114
|
+
'The file must be YAML file.') {|value|
|
115
|
+
cmd_opts['config'] = value
|
116
|
+
}
|
117
|
+
parser.parse(ARGV)
|
118
|
+
|
119
|
+
if path = cmd_opts['config']
|
120
|
+
cmd_opts.delete('config')
|
121
|
+
if FileTest::file? path then
|
122
|
+
require 'yaml'
|
123
|
+
YAML.load_file(path).each do |key, value|
|
124
|
+
name = OPTION_NAMES_TO_INTERNAL_NAMES[key]
|
125
|
+
opts[name || key] = value
|
126
|
+
end
|
127
|
+
else
|
128
|
+
warn("Not a exsiting regular file: #{path}")
|
129
|
+
exit(1)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
opts.merge(cmd_opts)
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
options = parse_options
|
138
|
+
|
139
|
+
if is_daemon = options[OPTION_NAMES_TO_INTERNAL_NAMES['daemon']]
|
140
|
+
options.delete(OPTION_NAMES_TO_INTERNAL_NAMES['daemon'])
|
141
|
+
|
142
|
+
exit if Process.fork
|
143
|
+
Process.setsid
|
144
|
+
exit if Process.fork
|
145
|
+
File.umask(0)
|
146
|
+
end
|
147
|
+
|
148
|
+
raise if defined?(RAILS_ENV)
|
149
|
+
::RAILS_ENV = options['RAILS_ENV'].dup
|
150
|
+
|
151
|
+
Dir.chdir options[OPTION_NAMES_TO_INTERNAL_NAMES['directory']]
|
152
|
+
require 'config/environment'
|
153
|
+
|
154
|
+
if is_daemon
|
155
|
+
Dir.chdir('/')
|
156
|
+
STDIN.reopen('/dev/null')
|
157
|
+
STDOUT.reopen('/dev/null', 'w')
|
158
|
+
STDERR.reopen('/dev/null', 'w')
|
159
|
+
end
|
160
|
+
|
161
|
+
runner = RailsRunner.new(options)
|
162
|
+
runner.start
|
@@ -0,0 +1,289 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2004 David Heinemeier Hansson
|
3
|
+
# Copyright (c) 2006 Yugui <yugui@yugui.sakura.ne.jp>
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; version 2.1
|
8
|
+
# of the License
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this program; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18
|
+
#
|
19
|
+
#--
|
20
|
+
#
|
21
|
+
# AjpRailsRequest is based on lib/action_controller/cgi_process.rb which is
|
22
|
+
# distributed as a port of actionpack 1.1.12.
|
23
|
+
# The original file is avaiable here;
|
24
|
+
# http://rubyforge.org/frs/?group_id=249&release_id=3791
|
25
|
+
#
|
26
|
+
# The following is the permission notice of the original
|
27
|
+
# lib/action_controller/cgi_process.rb, not for this script.
|
28
|
+
#
|
29
|
+
# --
|
30
|
+
# Copyright (c) 2004 David Heinemeier Hansson
|
31
|
+
#
|
32
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
33
|
+
# a copy of this software and associated documentation files (the
|
34
|
+
# "Software"), to deal in the Software without restriction, including
|
35
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
36
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
37
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
38
|
+
# the following conditions:
|
39
|
+
#
|
40
|
+
# The above copyright notice and this permission notice shall be
|
41
|
+
# included in all copies or substantial portions of the Software.
|
42
|
+
#
|
43
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
44
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
45
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
46
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
47
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
48
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
49
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
50
|
+
#++
|
51
|
+
|
52
|
+
require 'forwardable'
|
53
|
+
require 'action_controller/cgi_ext/cgi_methods'
|
54
|
+
|
55
|
+
class Net::AJP13::Request
|
56
|
+
def cookies
|
57
|
+
unless @cookies
|
58
|
+
@cookies = {}
|
59
|
+
cookie_strings = self.get_fields('cookie')
|
60
|
+
cookie_strings.each do |cookie_string|
|
61
|
+
@cookies.update(CGI::Cookie::parse(cookie_string))
|
62
|
+
end if cookie_strings
|
63
|
+
@cookies.freeze
|
64
|
+
end
|
65
|
+
@cookies
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_reader :output_cookies
|
69
|
+
end
|
70
|
+
|
71
|
+
# Wraps Net::AJP13::Request to adapt it to request object in rails.
|
72
|
+
class AjpRailsRequest < ActionController::AbstractRequest
|
73
|
+
DEFAULT_SESSION_OPTIONS = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.merge('session_key' => 'JSESSIONID')
|
74
|
+
|
75
|
+
extend Forwardable
|
76
|
+
|
77
|
+
def initialize(ajp_request, session_options, server_environments)
|
78
|
+
@req = ajp_request
|
79
|
+
@session_options = session_options
|
80
|
+
@server_environments = server_environments
|
81
|
+
@session_options['session_path'] ||= @server_environments['APP_LOCATION']
|
82
|
+
|
83
|
+
# simulates environment hash.
|
84
|
+
@env = self.class.instance_method(:environment).bind(self)
|
85
|
+
# Object#method is overridden by AbstractRequest#method
|
86
|
+
|
87
|
+
class << @env
|
88
|
+
def include?(key) !call(key).nil? end
|
89
|
+
alias :key? :include?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
attr_reader :env
|
93
|
+
|
94
|
+
attr_accessor :session_options
|
95
|
+
|
96
|
+
def method
|
97
|
+
@req.method.downcase.to_sym
|
98
|
+
end
|
99
|
+
|
100
|
+
def environment(name)
|
101
|
+
case name
|
102
|
+
when /^\AHTTP_(\w+)\Z/
|
103
|
+
name = $1.tr('_', '-')
|
104
|
+
@req[name]
|
105
|
+
else
|
106
|
+
@req[name] or @server_environments[name]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def raw_post
|
111
|
+
if @req.body
|
112
|
+
@req.body
|
113
|
+
elsif @req.body_stream
|
114
|
+
stream = @req.body_stream
|
115
|
+
@req.body_stream = nil
|
116
|
+
@req.body = stream.read
|
117
|
+
else
|
118
|
+
''
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def path
|
123
|
+
path = @req.path
|
124
|
+
path = path.sub(%r!\A#{Regexp.escape(@server_environments['DISPATCHER_PREFIX'])}!, '') if @server_environments['DISPATCHER_PREFIX']
|
125
|
+
path = path.sub(%r!#{Regexp.escape(@server_environments['DISPATCHER_SUFFIX'])}\Z!, '') if @server_environments['DISPATCHER_SUFFIX']
|
126
|
+
path
|
127
|
+
end
|
128
|
+
|
129
|
+
def request_uri
|
130
|
+
if @request_uri
|
131
|
+
@request_uri
|
132
|
+
else
|
133
|
+
uri = path
|
134
|
+
qs = query_string
|
135
|
+
uri << '?' << qs[0] if qs
|
136
|
+
@request_uri = uri
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def_delegators :@req, :ssl?, :cookies
|
141
|
+
|
142
|
+
def server_software
|
143
|
+
val = @req.get_attributes('server_software')
|
144
|
+
val and val[0] and /([A-Za-z]+)/ =~ val[0] and $1.downcase
|
145
|
+
end
|
146
|
+
|
147
|
+
def query_string
|
148
|
+
val = @req.get_attributes('query_string')
|
149
|
+
val and val[0]
|
150
|
+
end
|
151
|
+
|
152
|
+
def query_parameters
|
153
|
+
(qs = self.query_string).blank? ? {} : CGIMethods.parse_query_parameters(qs)
|
154
|
+
end
|
155
|
+
|
156
|
+
def post_params
|
157
|
+
@post_params ||= CGI.parse(raw_post)
|
158
|
+
@post_params
|
159
|
+
end
|
160
|
+
|
161
|
+
def request_parameters
|
162
|
+
if formatted_post?
|
163
|
+
CGIMethods.parse_formatted_request_parameters(post_format, raw_post)
|
164
|
+
else
|
165
|
+
CGIMethods.parse_request_parameters(self.post_params)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def host
|
170
|
+
@req['x-forwarded-host'] ||
|
171
|
+
($1 if @req.server_name and /\A(.*):\d+\Z/ =~ @req.server_name) ||
|
172
|
+
(@req.server_name and @req.server_name.split(':').first) ||
|
173
|
+
($1 if @req['host'] and /\A(.*):\d+\Z/ =~ @req['host']) ||
|
174
|
+
(@req['host'] and @req['host'].split(':').first) ||
|
175
|
+
''
|
176
|
+
end
|
177
|
+
def port
|
178
|
+
@req['x-forwarded-host'] ? standard_port : (port_from_http_host || @req.server_port)
|
179
|
+
end
|
180
|
+
|
181
|
+
def port_from_http_host
|
182
|
+
$1.to_i if @req['host'] && /:(\d+)$/ =~ @req['host']
|
183
|
+
end
|
184
|
+
|
185
|
+
def session
|
186
|
+
unless @session
|
187
|
+
if @session_options == false
|
188
|
+
@session = Hash.new
|
189
|
+
else
|
190
|
+
stale_session_check! do
|
191
|
+
if session_options_with_string_keys['new_session'] == true
|
192
|
+
@session = new_session
|
193
|
+
else
|
194
|
+
@session = CGI::Session.new(@req, session_options_with_string_keys)
|
195
|
+
end
|
196
|
+
@session['__valid_session']
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
@session
|
201
|
+
end
|
202
|
+
|
203
|
+
def reset_session
|
204
|
+
@session.delete if CGI::Session === @session
|
205
|
+
@session = new_session
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
# Delete an old session if it exists then create a new one.
|
210
|
+
def new_session
|
211
|
+
if @session_options == false
|
212
|
+
Hash.new
|
213
|
+
else
|
214
|
+
CGI::Session.new(@req, session_options_with_string_keys.merge("new_session" => false)).delete rescue nil
|
215
|
+
CGI::Session.new(@req, session_options_with_string_keys.merge("new_session" => true))
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def stale_session_check!
|
220
|
+
yield
|
221
|
+
rescue ArgumentError => argument_error
|
222
|
+
if argument_error.message =~ %r{undefined class/module (\w+)}
|
223
|
+
begin
|
224
|
+
Module.const_missing($1)
|
225
|
+
rescue LoadError, NameError => const_error
|
226
|
+
raise ActionController::SessionRestoreError, <<end_msg
|
227
|
+
Session contains objects whose class definition isn't available.
|
228
|
+
Remember to require the classes for all objects kept in the session.
|
229
|
+
(Original exception: #{const_error.message} [#{const_error.class}])
|
230
|
+
end_msg
|
231
|
+
end
|
232
|
+
retry
|
233
|
+
else
|
234
|
+
raise
|
235
|
+
end
|
236
|
+
end
|
237
|
+
def session_options_with_string_keys
|
238
|
+
@session_options_with_string_keys ||= DEFAULT_SESSION_OPTIONS.merge(@session_options).inject({}) { |options, (k,v)| options[k.to_s] = v; options }
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
class AjpRailsResponse < ActionController::AbstractResponse
|
243
|
+
def to_ajp_response(extra_cookies = nil)
|
244
|
+
raise "Unrecognized status line #{headers['Status']}" unless
|
245
|
+
md = /\A(\d{3})(?: (.+))?/.match(headers['Status'])
|
246
|
+
|
247
|
+
res = md[2] ?
|
248
|
+
Net::AJP13::Response.new(md[1].to_i, :reason_phrase => md[2]) :
|
249
|
+
Net::AJP13::Response.new(md[1])
|
250
|
+
|
251
|
+
@headers.each do |key, value|
|
252
|
+
case key.downcase
|
253
|
+
when 'status'
|
254
|
+
# do nothing
|
255
|
+
when 'expires'
|
256
|
+
res.add_field(key, CGI::rfc1123_date(options.delete(key)))
|
257
|
+
when 'cookie'
|
258
|
+
case value
|
259
|
+
when String
|
260
|
+
res.add_field('Set-Cookie', value)
|
261
|
+
when CGI::Cookie
|
262
|
+
res.add_field('Set-Cookie', value.to_s)
|
263
|
+
when Array
|
264
|
+
value.each {|cookie| res.add_field('Set-Cookie', cookie) }
|
265
|
+
when Hash
|
266
|
+
value.each_value {|cookie| res.add_field('Set-Cookie', cookie) }
|
267
|
+
end
|
268
|
+
else
|
269
|
+
res.add_field(key, value.to_s) if key != 'Status'
|
270
|
+
end
|
271
|
+
end
|
272
|
+
res['content-type'] ||= 'text/html'
|
273
|
+
if extra_cookies
|
274
|
+
extra_cookies.each do |cookie|
|
275
|
+
res.add_field('Set-Cookie', cookie.to_s)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
if @body.respond_to?(:call)
|
280
|
+
buf = ''
|
281
|
+
@body.call(self, StringIO.new(buf))
|
282
|
+
res.body = buf
|
283
|
+
else
|
284
|
+
res.body = self.body
|
285
|
+
end
|
286
|
+
|
287
|
+
return res
|
288
|
+
end
|
289
|
+
end
|