mongrel 0.3.6 → 0.3.7
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/README +28 -1
- data/Rakefile +2 -2
- data/bin/mongrel_rails +102 -65
- data/bin/mongrel_rails_service +16 -7
- data/bin/mongrel_rails_svc +184 -87
- data/doc/rdoc/classes/Mongrel.html +1 -0
- data/doc/rdoc/classes/Mongrel/Const.html +3 -3
- data/doc/rdoc/classes/Mongrel/HeaderOut.html +10 -10
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000028.html → M000014.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000029.html → M000015.html} +7 -7
- data/doc/rdoc/classes/Mongrel/HttpParser.html +35 -35
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000015.html → M000001.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000016.html → M000002.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000017.html → M000003.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000018.html → M000004.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000019.html → M000005.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000020.html → M000006.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000021.html → M000007.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpRequest.html +5 -5
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000041.html → M000029.html} +25 -25
- data/doc/rdoc/classes/Mongrel/HttpResponse.html +36 -36
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000034.html → M000016.html} +7 -7
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000035.html → M000017.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000036.html → M000018.html} +5 -5
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000037.html → M000019.html} +5 -5
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000038.html → M000020.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000039.html → M000021.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000040.html → M000022.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpServer.html +34 -35
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000008.html +36 -0
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000023.html → M000009.html} +43 -43
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000024.html → M000010.html} +31 -31
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000025.html → M000011.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000026.html → M000012.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000013.html +23 -0
- data/doc/rdoc/classes/{FactoryError.html → Mongrel/TimeoutWorker.html} +7 -34
- data/doc/rdoc/classes/Mongrel/URIClassifier.html +63 -20
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000023.html +18 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000024.html +18 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000030.html → M000025.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000031.html → M000026.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000032.html → M000027.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000033.html → M000028.html} +0 -0
- data/doc/rdoc/created.rid +1 -1
- data/doc/rdoc/files/README.html +35 -2
- data/doc/rdoc/files/lib/mongrel_rb.html +4 -1
- data/doc/rdoc/fr_class_index.html +1 -2
- data/doc/rdoc/fr_file_index.html +0 -1
- data/doc/rdoc/fr_method_index.html +29 -41
- data/lib/mongrel.rb +37 -9
- data/lib/mongrel/command.rb +13 -34
- data/lib/mongrel/plugins.rb +156 -0
- data/lib/mongrel/rails.rb +70 -0
- data/test/plugins/commands/test1.rb +19 -0
- data/test/test_plugins.rb +45 -0
- data/test/test_uriclassifier.rb +5 -1
- metadata +38 -49
- data/doc/rdoc/classes/FactoryError.src/M000001.html +0 -23
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000022.html +0 -33
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000027.html +0 -19
- data/doc/rdoc/classes/PluginFactory.html +0 -409
- data/doc/rdoc/classes/PluginFactory.src/M000002.html +0 -18
- data/doc/rdoc/classes/PluginFactory.src/M000003.html +0 -18
- data/doc/rdoc/classes/PluginFactory.src/M000004.html +0 -22
- data/doc/rdoc/classes/PluginFactory.src/M000005.html +0 -22
- data/doc/rdoc/classes/PluginFactory.src/M000006.html +0 -33
- data/doc/rdoc/classes/PluginFactory.src/M000007.html +0 -32
- data/doc/rdoc/classes/PluginFactory.src/M000008.html +0 -18
- data/doc/rdoc/classes/PluginFactory.src/M000009.html +0 -24
- data/doc/rdoc/classes/PluginFactory.src/M000010.html +0 -40
- data/doc/rdoc/classes/PluginFactory.src/M000011.html +0 -39
- data/doc/rdoc/classes/PluginFactory.src/M000012.html +0 -24
- data/doc/rdoc/classes/PluginFactory.src/M000013.html +0 -70
- data/doc/rdoc/classes/PluginFactory.src/M000014.html +0 -34
- data/doc/rdoc/files/lib/pluginfactory_rb.html +0 -132
- data/lib/pluginfactory.rb +0 -384
data/lib/mongrel.rb
CHANGED
|
@@ -4,16 +4,38 @@ require 'thread'
|
|
|
4
4
|
require 'stringio'
|
|
5
5
|
require 'mongrel/cgi'
|
|
6
6
|
require 'mongrel/handlers'
|
|
7
|
+
require 'mongrel/command'
|
|
8
|
+
require 'mongrel/plugins'
|
|
9
|
+
require 'timeout'
|
|
7
10
|
|
|
8
11
|
# Mongrel module containing all of the classes (include C extensions) for running
|
|
9
12
|
# a Mongrel web server. It contains a minimalist HTTP server with just enough
|
|
10
13
|
# functionality to service web application requests fast as possible.
|
|
11
14
|
module Mongrel
|
|
12
15
|
|
|
16
|
+
class URIClassifier
|
|
17
|
+
# Returns the URIs that have been registered with this classifier so far.
|
|
18
|
+
# The URIs returned should not be modified as this will cause a memory leak.
|
|
19
|
+
# You can use this to inspect the contents of the URIClassifier.
|
|
20
|
+
def uris
|
|
21
|
+
@handler_map.keys
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Simply does an inspect that looks like a Hash inspect.
|
|
25
|
+
def inspect
|
|
26
|
+
@handler_map.inspect
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
13
31
|
# Used to stop the HttpServer via Thread.raise.
|
|
14
32
|
class StopServer < Exception
|
|
15
33
|
end
|
|
16
34
|
|
|
35
|
+
# Used to timeout worker threads that have taken too long
|
|
36
|
+
class TimeoutWorker < Exception
|
|
37
|
+
end
|
|
38
|
+
|
|
17
39
|
# Every standard HTTP code mapped to the appropriate message. These are
|
|
18
40
|
# used so frequently that they are placed directly in Mongrel for easy
|
|
19
41
|
# access rather than Mongrel::Const.
|
|
@@ -118,7 +140,7 @@ module Mongrel
|
|
|
118
140
|
SERVER_SOFTWARE='SERVER_SOFTWARE'
|
|
119
141
|
|
|
120
142
|
# Current Mongrel version (used for SERVER_SOFTWARE and other response headers).
|
|
121
|
-
MONGREL_VERSION='Mongrel 0.3.
|
|
143
|
+
MONGREL_VERSION='Mongrel 0.3.7'
|
|
122
144
|
|
|
123
145
|
# The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
|
|
124
146
|
ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: #{MONGREL_VERSION}\r\n\r\nNOT FOUND"
|
|
@@ -320,24 +342,26 @@ module Mongrel
|
|
|
320
342
|
# systems. If you find that you overload Mongrel too much
|
|
321
343
|
# try changing it higher. If you find that responses are way too slow
|
|
322
344
|
# try lowering it (after you've tuned your stuff of course).
|
|
323
|
-
# Future versions of Mongrel will make this more dynamic (hopefully).
|
|
324
345
|
def initialize(host, port, num_processors=20, timeout=120)
|
|
325
|
-
@socket = TCPServer.new(host, port)
|
|
346
|
+
@socket = TCPServer.new(host, port)
|
|
326
347
|
|
|
327
348
|
@classifier = URIClassifier.new
|
|
328
349
|
@req_queue = Queue.new
|
|
329
350
|
@host = host
|
|
330
351
|
@port = port
|
|
331
352
|
@processors = []
|
|
332
|
-
@timeout = timeout
|
|
333
353
|
|
|
334
|
-
|
|
354
|
+
# create the worker threads
|
|
355
|
+
num_processors.times do |i|
|
|
335
356
|
@processors << Thread.new do
|
|
336
357
|
while client = @req_queue.deq
|
|
337
|
-
|
|
358
|
+
Timeout::timeout(timeout) do
|
|
359
|
+
process_client(client)
|
|
360
|
+
end
|
|
338
361
|
end
|
|
339
362
|
end
|
|
340
|
-
|
|
363
|
+
end
|
|
364
|
+
|
|
341
365
|
end
|
|
342
366
|
|
|
343
367
|
|
|
@@ -440,8 +464,12 @@ module Mongrel
|
|
|
440
464
|
# Stops the acceptor thread and then causes the worker threads to finish
|
|
441
465
|
# off the request queue before finally exiting.
|
|
442
466
|
def stop
|
|
443
|
-
|
|
444
|
-
|
|
467
|
+
stopper = Thread.new do
|
|
468
|
+
@acceptor[:stopped] = true
|
|
469
|
+
exc = StopServer.new
|
|
470
|
+
@acceptor.raise(exc)
|
|
471
|
+
end
|
|
472
|
+
stopper.priority = 10
|
|
445
473
|
end
|
|
446
474
|
|
|
447
475
|
end
|
data/lib/mongrel/command.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'singleton'
|
|
2
2
|
require 'optparse'
|
|
3
|
-
require '
|
|
4
|
-
|
|
3
|
+
require 'mongrel/plugins'
|
|
5
4
|
|
|
6
5
|
module Mongrel
|
|
7
6
|
|
|
@@ -10,17 +9,10 @@ module Mongrel
|
|
|
10
9
|
|
|
11
10
|
module Command
|
|
12
11
|
|
|
13
|
-
|
|
14
12
|
# A Command pattern implementation used to create the set of command available to the user
|
|
15
13
|
# from Mongrel. The script uses objects which implement this interface to do the
|
|
16
14
|
# user's bidding.
|
|
17
|
-
|
|
18
|
-
# Creating a new command is very easy, and you can do it without modifying the source
|
|
19
|
-
# of Mongrel thanks to PluginFactory. What you do is the following:
|
|
20
|
-
#
|
|
21
|
-
# 1.
|
|
22
|
-
class Command
|
|
23
|
-
include PluginFactory
|
|
15
|
+
module Base
|
|
24
16
|
|
|
25
17
|
attr_reader :valid, :done_validating
|
|
26
18
|
|
|
@@ -39,11 +31,13 @@ module Mongrel
|
|
|
39
31
|
|
|
40
32
|
# Called by the subclass to setup the command and parse the argv arguments.
|
|
41
33
|
# The call is destructive on argv since it uses the OptionParser#parse! function.
|
|
42
|
-
def initialize(
|
|
34
|
+
def initialize(options={})
|
|
35
|
+
argv = options[:argv]
|
|
43
36
|
@opt = OptionParser.new
|
|
44
37
|
@valid = true
|
|
45
38
|
# this is retarded, but it has to be done this way because -h and -v exit
|
|
46
39
|
@done_validating = false
|
|
40
|
+
@original_args = argv.dup
|
|
47
41
|
|
|
48
42
|
configure
|
|
49
43
|
|
|
@@ -61,13 +55,7 @@ module Mongrel
|
|
|
61
55
|
end
|
|
62
56
|
end
|
|
63
57
|
|
|
64
|
-
@opt.parse! argv
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Tells the PluginFactory where to look for additional commands. By default
|
|
68
|
-
# it's just a "plugins" directory wherever we are located.
|
|
69
|
-
def self.derivativeDirs
|
|
70
|
-
return ["plugins"]
|
|
58
|
+
@opt.parse! options[:argv]
|
|
71
59
|
end
|
|
72
60
|
|
|
73
61
|
# Returns true/false depending on whether the command is configured properly.
|
|
@@ -118,8 +106,6 @@ module Mongrel
|
|
|
118
106
|
end
|
|
119
107
|
end
|
|
120
108
|
|
|
121
|
-
|
|
122
|
-
|
|
123
109
|
# A Singleton class that manages all of the available commands
|
|
124
110
|
# and handles running them.
|
|
125
111
|
class Registry
|
|
@@ -127,15 +113,9 @@ module Mongrel
|
|
|
127
113
|
|
|
128
114
|
# Builds a list of possible commands from the Command derivates list
|
|
129
115
|
def commands
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
results = []
|
|
134
|
-
list.keys.each do |key|
|
|
135
|
-
results << key.to_s unless match.match(key.to_s)
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
return results.sort
|
|
116
|
+
pmgr = PluginManager.instance
|
|
117
|
+
list = pmgr.available["/commands"]
|
|
118
|
+
return list.sort
|
|
139
119
|
end
|
|
140
120
|
|
|
141
121
|
# Prints a list of available commands.
|
|
@@ -143,7 +123,7 @@ module Mongrel
|
|
|
143
123
|
puts "Available commands are:\n\n"
|
|
144
124
|
|
|
145
125
|
self.commands.each do |name|
|
|
146
|
-
puts " - #{name}\n"
|
|
126
|
+
puts " - #{name[1 .. -1]}\n"
|
|
147
127
|
end
|
|
148
128
|
|
|
149
129
|
puts "\nEach command takes -h as an option to get help."
|
|
@@ -154,9 +134,8 @@ module Mongrel
|
|
|
154
134
|
# Runs the args against the first argument as the command name.
|
|
155
135
|
# If it has any errors it returns a false, otherwise it return true.
|
|
156
136
|
def run(args)
|
|
157
|
-
# find the command
|
|
137
|
+
# find the command
|
|
158
138
|
cmd_name = args.shift
|
|
159
|
-
$0 = "#{cmd_name}"
|
|
160
139
|
|
|
161
140
|
if !cmd_name or cmd_name == "?" or cmd_name == "help"
|
|
162
141
|
print_command_list
|
|
@@ -165,8 +144,8 @@ module Mongrel
|
|
|
165
144
|
|
|
166
145
|
# command exists, set it up and validate it
|
|
167
146
|
begin
|
|
168
|
-
command =
|
|
169
|
-
rescue
|
|
147
|
+
command = PluginManager.instance.create("/commands/#{cmd_name}", :argv => args)
|
|
148
|
+
rescue
|
|
170
149
|
STDERR.puts "INVALID COMMAND: #$!"
|
|
171
150
|
print_command_list
|
|
172
151
|
return
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
|
|
3
|
+
module Mongrel
|
|
4
|
+
|
|
5
|
+
# Implements the main method of managing plugins for Mongrel.
|
|
6
|
+
# "Plugins" in this sense are any classes which get registered
|
|
7
|
+
# with Mongrel for possible use when it's operating. These can
|
|
8
|
+
# be Handlers, Commands, or other classes. When you create a
|
|
9
|
+
# Plugin you register it into a URI-like namespace that makes
|
|
10
|
+
# it easy for you (and others) to reference it later during
|
|
11
|
+
# configuration.
|
|
12
|
+
#
|
|
13
|
+
# PluginManager is used as nothing more than a holder of all the
|
|
14
|
+
# plugins that have registered themselves. Let's say you have:
|
|
15
|
+
#
|
|
16
|
+
# class StopNow < Plugin "/commands"
|
|
17
|
+
# ...
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# Then you can get at this plugin with:
|
|
21
|
+
#
|
|
22
|
+
# cmd = PluginManager.create("/commands/stopnow")
|
|
23
|
+
#
|
|
24
|
+
# The funky syntax for StopNow is a weird trick borrowed from
|
|
25
|
+
# the Camping framework. See the Mongrel::Plugin *function* (yes,
|
|
26
|
+
# function). What this basically does is register it
|
|
27
|
+
# into the namespace for plugins at /commands. You could go
|
|
28
|
+
# as arbitrarily nested as you like.
|
|
29
|
+
#
|
|
30
|
+
# Why this strange almost second namespace? Why not just use
|
|
31
|
+
# the ObjectSpace and/or Modules? The main reason is speed and
|
|
32
|
+
# to avoid cluttering the Ruby namespace with what is really a
|
|
33
|
+
# configuration statement. This lets implementors put code
|
|
34
|
+
# into the Ruby structuring they need, and still have Plugins
|
|
35
|
+
# available to Mongrel via simple URI-like names.
|
|
36
|
+
#
|
|
37
|
+
# The alternative (as pluginfactory does it) is to troll through
|
|
38
|
+
# ObjectSpace looking for stuff that *might* be plugins every time
|
|
39
|
+
# one is needed. This alternative also means that you are stuck
|
|
40
|
+
# naming your commands in specific ways and putting them in specific
|
|
41
|
+
# modules in order to configure how Mongrel should use them.
|
|
42
|
+
#
|
|
43
|
+
# One downside to this is that you need to subclass plugin to
|
|
44
|
+
# make it work. In this case use mixins to add other functionality.
|
|
45
|
+
class PluginManager
|
|
46
|
+
include Singleton
|
|
47
|
+
|
|
48
|
+
def initialize
|
|
49
|
+
@plugins = URIClassifier.new
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Tell the PluginManager to scan the given path (recursively)
|
|
53
|
+
# and load the *.rb files found there. This is how you'd
|
|
54
|
+
# setup your own plugin directory.
|
|
55
|
+
def load(path)
|
|
56
|
+
Dir.chdir(path) do
|
|
57
|
+
Dir["**/*.rb"].each do |rbfile|
|
|
58
|
+
STDERR.puts "Loading plugins from #{rbfile}"
|
|
59
|
+
require rbfile
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Not necessary for you to call directly, but this is
|
|
65
|
+
# how Mongrel::PluginBase.inherited actually adds a
|
|
66
|
+
# plugin to a category.
|
|
67
|
+
def register(category, name, klass)
|
|
68
|
+
cat, ignored, map = @plugins.resolve(category)
|
|
69
|
+
|
|
70
|
+
if not cat or ignored.length > 0
|
|
71
|
+
map = {name => klass}
|
|
72
|
+
@plugins.register(category, map)
|
|
73
|
+
elsif not map
|
|
74
|
+
raise "Unknown category #{category}"
|
|
75
|
+
else
|
|
76
|
+
map[name] = klass
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Resolves the given name (should include /category/name) to
|
|
81
|
+
# find the plugin class and create an instance. It uses
|
|
82
|
+
# the same URIClassifier that the rest of Mongrel does so it
|
|
83
|
+
# is fast.
|
|
84
|
+
def create(name, options = {})
|
|
85
|
+
category, plugin, map = @plugins.resolve(name)
|
|
86
|
+
|
|
87
|
+
if category and plugin and plugin.length > 0
|
|
88
|
+
map[plugin].new(options)
|
|
89
|
+
else
|
|
90
|
+
raise "Plugin #{name} does not exist"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Returns a map of URIs->[handlers] that you can
|
|
95
|
+
# use to investigate available handlers.
|
|
96
|
+
def available
|
|
97
|
+
map = {}
|
|
98
|
+
@plugins.uris.each do |u|
|
|
99
|
+
cat, name, plugins = @plugins.resolve(u)
|
|
100
|
+
map[cat] ||= []
|
|
101
|
+
map[cat] += plugins.keys
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
return map
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# This base class for plugins reallys does nothing
|
|
110
|
+
# more than wire up the new class into the right category.
|
|
111
|
+
# It is not thread-safe yet but will be soon.
|
|
112
|
+
class PluginBase
|
|
113
|
+
|
|
114
|
+
attr_reader :options
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# See Mongrel::Plugin for an explanation.
|
|
118
|
+
def PluginBase.inherited(klass)
|
|
119
|
+
name = "/" + klass.to_s.downcase
|
|
120
|
+
PluginManager.instance.register(@@category, name, klass)
|
|
121
|
+
@@category = nil
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# See Mongrel::Plugin for an explanation.
|
|
125
|
+
def PluginBase.category=(category)
|
|
126
|
+
@@category = category
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def initialize(options = {})
|
|
130
|
+
@options = options
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# This nifty function works with the PluginBase to give you
|
|
136
|
+
# the syntax:
|
|
137
|
+
#
|
|
138
|
+
# class MyThing < Plugin "/things"
|
|
139
|
+
# ...
|
|
140
|
+
# end
|
|
141
|
+
#
|
|
142
|
+
# What it does is temporarily sets the PluginBase.category, and then
|
|
143
|
+
# returns PluginBase. Since the next immediate thing Ruby does is
|
|
144
|
+
# use this returned class to create the new class, PluginBase.inherited
|
|
145
|
+
# gets called. PluginBase.inherited then uses the set category, class name,
|
|
146
|
+
# and class to register the plugin in the right way.
|
|
147
|
+
def Mongrel::Plugin(c)
|
|
148
|
+
PluginBase.category = c
|
|
149
|
+
PluginBase
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'mongrel'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# Implements a handler that can run Rails and serve files out of the
|
|
5
|
+
# Rails application's public directory. This lets you run your Rails
|
|
6
|
+
# application with Mongrel during development and testing, then use it
|
|
7
|
+
# also in production behind a server that's better at serving the
|
|
8
|
+
# static files.
|
|
9
|
+
#
|
|
10
|
+
# The RailsHandler takes a mime_map parameter which is a simple suffix=mimetype
|
|
11
|
+
# mapping that it should add to the list of valid mime types.
|
|
12
|
+
#
|
|
13
|
+
# It also supports page caching directly and will try to resolve a request
|
|
14
|
+
# in the following order:
|
|
15
|
+
#
|
|
16
|
+
# * If the requested exact PATH_INFO exists as a file then serve it.
|
|
17
|
+
# * If it exists at PATH_INFO+".html" exists then serve that.
|
|
18
|
+
# * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispath to have Rails go.
|
|
19
|
+
#
|
|
20
|
+
# This means that if you are using page caching it will actually work with Mongrel
|
|
21
|
+
# and you should see a decent speed boost (but not as fast as if you use lighttpd).
|
|
22
|
+
class RailsHandler < Mongrel::HttpHandler
|
|
23
|
+
def initialize(dir, mime_map = {})
|
|
24
|
+
@files = Mongrel::DirHandler.new(dir,false)
|
|
25
|
+
@guard = Mutex.new
|
|
26
|
+
|
|
27
|
+
# register the requested mime types
|
|
28
|
+
mime_map.each {|k,v| Mongrel::DirHandler::add_mime_type(k,v) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Attempts to resolve the request as follows:
|
|
32
|
+
#
|
|
33
|
+
#
|
|
34
|
+
# * If the requested exact PATH_INFO exists as a file then serve it.
|
|
35
|
+
# * If it exists at PATH_INFO+".html" exists then serve that.
|
|
36
|
+
# * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispath to have Rails go.
|
|
37
|
+
def process(request, response)
|
|
38
|
+
return if response.socket.closed?
|
|
39
|
+
|
|
40
|
+
path_info = request.params["PATH_INFO"]
|
|
41
|
+
page_cached = request.params["PATH_INFO"] + ".html"
|
|
42
|
+
|
|
43
|
+
if @files.can_serve(path_info)
|
|
44
|
+
# File exists as-is so serve it up
|
|
45
|
+
@files.process(request,response)
|
|
46
|
+
elsif @files.can_serve(page_cached)
|
|
47
|
+
# possible cached page, serve it up
|
|
48
|
+
request.params["PATH_INFO"] = page_cached
|
|
49
|
+
@files.process(request,response)
|
|
50
|
+
else
|
|
51
|
+
cgi = Mongrel::CGIWrapper.new(request, response)
|
|
52
|
+
|
|
53
|
+
begin
|
|
54
|
+
@guard.synchronize do
|
|
55
|
+
# Rails is not thread safe so must be run entirely within synchronize
|
|
56
|
+
Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# This finalizes the output using the proper HttpResponse way
|
|
60
|
+
cgi.out {""}
|
|
61
|
+
rescue Errno::EPIPE
|
|
62
|
+
# ignored
|
|
63
|
+
rescue Object => rails_error
|
|
64
|
+
STDERR.puts "Error calling Dispatcher.dispatch #{rails_error.inspect}"
|
|
65
|
+
STDERR.puts rails_error.backtrace.join("\n")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
class First < Mongrel::Plugin "/commands"
|
|
3
|
+
def initialize(options = {})
|
|
4
|
+
puts "First with options: #{options.inspect}"
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class Second < Mongrel::Plugin "/commands"
|
|
9
|
+
def initialize(options = {})
|
|
10
|
+
puts "Second with options: #{options.inspect}"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Last < Mongrel::Plugin "/commands"
|
|
15
|
+
def initialize(options = {})
|
|
16
|
+
puts "Last with options: #{options.inspect}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|