mongrel 0.3.12.4 → 0.3.13
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +44 -33
- data/bin/mongrel_rails +67 -34
- data/doc/rdoc/classes/IO.html +10 -10
- data/doc/rdoc/classes/IO.src/{M000005.html → M000001.html} +5 -5
- data/doc/rdoc/classes/IO.src/{M000006.html → M000002.html} +5 -5
- data/doc/rdoc/classes/Kernel.html +10 -10
- data/doc/rdoc/classes/Kernel.src/{M000025.html → M000020.html} +5 -5
- data/doc/rdoc/classes/Kernel.src/M000021.html +23 -0
- data/doc/rdoc/classes/Mongrel.html +25 -4
- data/doc/rdoc/classes/Mongrel/CGIWrapper.html +383 -0
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000096.html +11 -5
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000097.html +34 -5
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000098.html +21 -6
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000093.html → M000099.html} +13 -13
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000094.html → M000100.html} +11 -11
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000095.html → M000101.html} +4 -4
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000102.html +18 -0
- data/doc/rdoc/classes/Mongrel/{URIClassifier.src/M000084.html → CGIWrapper.src/M000103.html} +5 -5
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000104.html +19 -0
- data/doc/rdoc/classes/Mongrel/Camping.html +5 -5
- data/doc/rdoc/classes/Mongrel/Camping.src/M000046.html +22 -0
- data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.html +10 -10
- data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.src/{M000049.html → M000047.html} +4 -4
- data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.src/M000048.html +51 -0
- data/doc/rdoc/classes/Mongrel/Command.html +13 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.html +95 -50
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000024.html +24 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000025.html +42 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000026.html +18 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000027.html +18 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000028.html +18 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000029.html +5 -11
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000030.html +9 -28
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000031.html +5 -5
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000032.html +5 -5
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000033.html +5 -5
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000034.html +11 -9
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000035.html +11 -5
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000036.html +5 -5
- data/doc/rdoc/classes/Mongrel/Command/Registry.html +15 -15
- data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000037.html +20 -0
- data/doc/rdoc/classes/Mongrel/Command/Registry.src/{M000040.html → M000038.html} +11 -11
- data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000039.html +37 -7
- data/doc/rdoc/classes/Mongrel/Configurator.html +651 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000105.html +16 -20
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000106.html +18 -5
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000107.html +7 -11
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000108.html +7 -6
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000109.html +10 -9
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000110.html +5 -8
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000111.html +21 -5
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000112.html +6 -15
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000113.html +17 -5
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000114.html +20 -33
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000115.html +5 -5
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000116.html +24 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000117.html +19 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000118.html +22 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000119.html +25 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000120.html +18 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000121.html +35 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000122.html +18 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000123.html +33 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000124.html +18 -0
- data/doc/rdoc/classes/Mongrel/Const.html +39 -7
- data/doc/rdoc/classes/Mongrel/DeflateFilter.html +181 -0
- data/doc/rdoc/classes/Mongrel/DeflateFilter.src/M000094.html +19 -0
- data/doc/rdoc/classes/Mongrel/DeflateFilter.src/M000095.html +28 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.html +48 -33
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000056.html +21 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000057.html +43 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000058.html +29 -7
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000059.html +50 -29
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000060.html +26 -27
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000061.html +5 -38
- data/doc/rdoc/classes/Mongrel/Error404Handler.html +171 -0
- data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000116.html → M000125.html} +4 -4
- data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000117.html → M000126.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HeaderOut.html +185 -0
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000072.html → M000069.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000073.html → M000070.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HttpHandler.html +170 -0
- data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000074.html → M000075.html} +3 -3
- data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.html +20 -10
- data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000027.html → M000022.html} +5 -4
- data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000028.html → M000023.html} +3 -3
- data/doc/rdoc/classes/Mongrel/HttpParser.html +41 -36
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000056.html → M000049.html} +6 -5
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000057.html → M000050.html} +7 -6
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000051.html +7 -6
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000052.html +37 -7
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000053.html +5 -7
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000054.html +6 -22
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000055.html +6 -5
- data/doc/rdoc/classes/Mongrel/HttpRequest.html +239 -0
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000130.html +52 -0
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000119.html → M000131.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000120.html → M000132.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000121.html → M000133.html} +18 -18
- data/doc/rdoc/classes/Mongrel/HttpResponse.html +439 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000076.html +12 -7
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000077.html +7 -12
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000078.html +12 -9
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000079.html +9 -9
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000080.html +9 -10
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000081.html +9 -5
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000082.html +18 -7
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000083.html +8 -5
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000084.html +20 -0
- data/doc/rdoc/classes/Mongrel/{HttpServer.src/M000069.html → HttpResponse.src/M000085.html} +7 -5
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000086.html +20 -0
- data/doc/rdoc/classes/Mongrel/{Configurator.src/M000101.html → HttpResponse.src/M000087.html} +5 -5
- data/doc/rdoc/classes/Mongrel/HttpServer.html +68 -59
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000062.html +25 -0
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000063.html +83 -0
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000064.html +13 -11
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000065.html +50 -53
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000066.html +21 -11
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000067.html +5 -47
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000068.html +9 -15
- data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.html +16 -16
- data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/M000040.html +39 -0
- data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/{M000043.html → M000041.html} +11 -11
- data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/M000042.html +13 -22
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.html +17 -17
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000043.html +22 -0
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000044.html +51 -0
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000045.html +10 -9
- data/doc/rdoc/classes/Mongrel/StatisticsFilter.html +211 -0
- data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/M000127.html +24 -0
- data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/M000128.html +24 -0
- data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/M000129.html +18 -0
- data/doc/rdoc/classes/{Class.html → Mongrel/StatusHandler.html} +42 -45
- data/doc/rdoc/classes/Mongrel/StatusHandler.src/M000071.html +18 -0
- data/doc/rdoc/classes/Mongrel/StatusHandler.src/M000072.html +24 -0
- data/doc/rdoc/classes/Mongrel/StatusHandler.src/M000073.html +42 -0
- data/doc/rdoc/classes/Mongrel/StatusHandler.src/M000074.html +20 -0
- data/doc/rdoc/classes/Mongrel/StopServer.html +117 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.html +314 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000088.html +5 -23
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000089.html +5 -70
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000086.html → M000090.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000087.html → M000091.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000092.html +36 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000093.html +83 -0
- data/doc/rdoc/classes/MongrelDbg.html +25 -25
- data/doc/rdoc/classes/MongrelDbg.src/{M000020.html → M000015.html} +5 -5
- data/doc/rdoc/classes/MongrelDbg.src/{M000021.html → M000016.html} +6 -6
- data/doc/rdoc/classes/MongrelDbg.src/{M000022.html → M000017.html} +8 -8
- data/doc/rdoc/classes/MongrelDbg.src/{M000023.html → M000018.html} +7 -7
- data/doc/rdoc/classes/MongrelDbg.src/{M000024.html → M000019.html} +4 -4
- data/doc/rdoc/classes/ObjectTracker.html +10 -40
- data/doc/rdoc/classes/ObjectTracker.src/M000013.html +27 -0
- data/doc/rdoc/classes/ObjectTracker.src/M000014.html +44 -0
- data/doc/rdoc/classes/RequestLog.html +115 -0
- data/doc/rdoc/classes/RequestLog/Access.html +151 -0
- data/doc/rdoc/classes/RequestLog/Access.src/{M000122.html → M000134.html} +5 -5
- data/doc/rdoc/classes/RequestLog/Files.html +144 -0
- data/doc/rdoc/classes/RequestLog/Files.src/{M000123.html → M000135.html} +5 -5
- data/doc/rdoc/classes/RequestLog/Objects.html +144 -0
- data/doc/rdoc/classes/RequestLog/Objects.src/{M000124.html → M000137.html} +5 -5
- data/doc/rdoc/classes/RequestLog/Params.html +144 -0
- data/doc/rdoc/classes/RequestLog/Params.src/{M000125.html → M000138.html} +5 -5
- data/doc/rdoc/classes/RequestLog/Threads.html +144 -0
- data/doc/rdoc/classes/RequestLog/Threads.src/M000136.html +34 -0
- data/doc/rdoc/classes/Stats.html +54 -36
- data/doc/rdoc/classes/Stats.src/{M000013.html → M000005.html} +6 -5
- data/doc/rdoc/classes/Stats.src/M000006.html +23 -0
- data/doc/rdoc/classes/Stats.src/M000007.html +26 -0
- data/doc/rdoc/classes/Stats.src/M000008.html +18 -0
- data/doc/rdoc/classes/Stats.src/M000009.html +5 -6
- data/doc/rdoc/classes/Stats.src/M000010.html +5 -10
- data/doc/rdoc/classes/Stats.src/M000011.html +10 -13
- data/doc/rdoc/classes/Stats.src/M000012.html +7 -5
- data/doc/rdoc/classes/TCPServer.html +9 -9
- data/doc/rdoc/classes/TCPServer.src/M000003.html +19 -0
- data/doc/rdoc/created.rid +1 -1
- data/doc/rdoc/files/COPYING.html +1 -1
- data/doc/rdoc/files/LICENSE.html +1 -1
- data/doc/rdoc/files/README.html +1 -1
- data/doc/rdoc/files/ext/http11/http11_c.html +1 -1
- data/doc/rdoc/files/lib/mongrel/camping_rb.html +28 -1
- data/doc/rdoc/files/lib/mongrel/cgi_rb.html +28 -1
- data/doc/rdoc/files/lib/mongrel/command_rb.html +28 -1
- data/doc/rdoc/files/lib/mongrel/debug_rb.html +28 -1
- data/doc/rdoc/files/lib/mongrel/handlers_rb.html +3 -3
- data/doc/rdoc/files/lib/mongrel/init_rb.html +28 -1
- data/doc/rdoc/files/lib/mongrel/rails_rb.html +28 -1
- data/doc/rdoc/files/lib/mongrel/stats_rb.html +21 -10
- data/doc/rdoc/files/lib/mongrel/tcphack_rb.html +23 -4
- data/doc/rdoc/files/lib/mongrel_rb.html +33 -1
- data/doc/rdoc/fr_class_index.html +65 -0
- data/doc/rdoc/fr_file_index.html +40 -0
- data/doc/rdoc/fr_method_index.html +164 -0
- data/doc/rdoc/index.html +24 -0
- data/examples/camping/blog.rb +1 -1
- data/examples/camping/tepee.rb +4 -3
- data/examples/simpletest.rb +15 -14
- data/ext/http11/http11.c +52 -18
- data/ext/http11/http11_parser.c +194 -177
- data/ext/http11/http11_parser.h +23 -5
- data/lib/mongrel.rb +295 -134
- data/lib/mongrel/camping.rb +48 -6
- data/lib/mongrel/cgi.rb +20 -2
- data/lib/mongrel/command.rb +76 -27
- data/lib/mongrel/debug.rb +42 -13
- data/lib/mongrel/handlers.rb +218 -59
- data/lib/mongrel/init.rb +18 -0
- data/lib/mongrel/rails.rb +61 -44
- data/lib/mongrel/stats.rb +30 -2
- data/lib/mongrel/tcphack.rb +18 -0
- data/setup.rb +799 -574
- data/test/mime.yaml +3 -0
- data/test/mongrel.conf +1 -0
- data/test/test_command.rb +101 -0
- data/test/test_conditional.rb +124 -0
- data/test/test_configurator.rb +56 -22
- data/test/test_debug.rb +18 -2
- data/test/test_handlers.rb +105 -0
- data/test/test_http11.rb +27 -9
- data/test/test_response.rb +38 -0
- data/test/test_stats.rb +21 -2
- data/test/test_uriclassifier.rb +18 -0
- data/test/test_ws.rb +105 -19
- data/test/testhelp.rb +36 -0
- data/tools/rakehelp.rb +52 -46
- data/tools/trickletest.rb +37 -0
- metadata +127 -76
- data/doc/rdoc/classes/Class.src/M000001.html +0 -24
- data/doc/rdoc/classes/Class.src/M000002.html +0 -62
- data/doc/rdoc/classes/Class.src/M000003.html +0 -21
- data/doc/rdoc/classes/Class.src/M000004.html +0 -20
- data/doc/rdoc/classes/Kernel.src/M000026.html +0 -25
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000090.html +0 -24
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000091.html +0 -47
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000092.html +0 -34
- data/doc/rdoc/classes/Mongrel/Camping.src/M000048.html +0 -22
- data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.src/M000050.html +0 -27
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000037.html +0 -18
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000038.html +0 -18
- data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000041.html +0 -46
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000099.html +0 -24
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000100.html +0 -23
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000102.html +0 -32
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000103.html +0 -19
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000104.html +0 -31
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000062.html +0 -40
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000063.html +0 -18
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000118.html +0 -28
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000075.html +0 -26
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000070.html +0 -22
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000071.html +0 -18
- data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/M000044.html +0 -32
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000046.html +0 -48
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000047.html +0 -23
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000085.html +0 -18
- data/doc/rdoc/classes/ObjectTracker.src/M000016.html +0 -22
- data/doc/rdoc/classes/ObjectTracker.src/M000017.html +0 -18
- data/doc/rdoc/classes/ObjectTracker.src/M000018.html +0 -18
- data/doc/rdoc/classes/ObjectTracker.src/M000019.html +0 -44
- data/doc/rdoc/classes/Stats.src/M000014.html +0 -19
- data/doc/rdoc/classes/Stats.src/M000015.html +0 -20
- data/doc/rdoc/classes/TCPServer.src/M000007.html +0 -19
- data/lib/mongrel/#rails.rb# +0 -178
data/lib/mongrel/camping.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
# Mongrel Web Server - A Mostly Ruby Webserver and Library
|
2
|
+
#
|
3
|
+
# Copyright (C) 2005 Zed A. Shaw zedshaw AT zedshaw dot com
|
4
|
+
#
|
5
|
+
# This library 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; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library 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 library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18
|
+
|
1
19
|
require 'mongrel'
|
2
20
|
|
3
21
|
|
@@ -32,15 +50,39 @@ module Mongrel
|
|
32
50
|
end
|
33
51
|
|
34
52
|
def process(request, response)
|
35
|
-
|
36
|
-
|
37
|
-
response.
|
38
|
-
|
53
|
+
controller = @klass.run(request.body, request.params)
|
54
|
+
sendfile, clength = nil
|
55
|
+
response.status = controller.status
|
56
|
+
controller.headers.each do |k, v|
|
57
|
+
if k =~ /^X-SENDFILE$/i
|
58
|
+
sendfile = v
|
59
|
+
elsif k =~ /^CONTENT-LENGTH$/i
|
60
|
+
clength = v.to_i
|
61
|
+
else
|
39
62
|
[*v].each do |vi|
|
40
|
-
|
63
|
+
response.header[k] = vi
|
41
64
|
end
|
42
65
|
end
|
43
|
-
|
66
|
+
end
|
67
|
+
|
68
|
+
if sendfile
|
69
|
+
response.send_status(File.size(sendfile))
|
70
|
+
response.send_header
|
71
|
+
response.send_file(sendfile)
|
72
|
+
elsif controller.body.respond_to? :read
|
73
|
+
response.send_status(clength)
|
74
|
+
response.send_header
|
75
|
+
while chunk = controller.body.read(16384)
|
76
|
+
response.write(chunk)
|
77
|
+
end
|
78
|
+
if controller.body.respond_to? :close
|
79
|
+
controller.body.close
|
80
|
+
end
|
81
|
+
else
|
82
|
+
body = controller.body.to_s
|
83
|
+
response.send_status(body.length)
|
84
|
+
response.send_header
|
85
|
+
response.write(body)
|
44
86
|
end
|
45
87
|
end
|
46
88
|
end
|
data/lib/mongrel/cgi.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
# Mongrel Web Server - A Mostly Ruby Webserver and Library
|
2
|
+
#
|
3
|
+
# Copyright (C) 2005 Zed A. Shaw zedshaw AT zedshaw dot com
|
4
|
+
#
|
5
|
+
# This library 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; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library 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 library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18
|
+
|
1
19
|
require 'cgi'
|
2
20
|
|
3
21
|
module Mongrel
|
@@ -10,7 +28,7 @@ module Mongrel
|
|
10
28
|
# The CGIWrapper.handler attribute is normally not set and is available for
|
11
29
|
# frameworks that need to get back to the handler. Rails uses this to give
|
12
30
|
# people access to the RailsHandler#files (DirHandler really) so they can
|
13
|
-
# look-up paths and do other things
|
31
|
+
# look-up paths and do other things with the files managed there.
|
14
32
|
#
|
15
33
|
# In Rails you can get the real file for a request with:
|
16
34
|
#
|
@@ -35,7 +53,7 @@ module Mongrel
|
|
35
53
|
@request = request
|
36
54
|
@response = response
|
37
55
|
@args = *args
|
38
|
-
@input =
|
56
|
+
@input = request.body
|
39
57
|
@head = {}
|
40
58
|
@out_called = false
|
41
59
|
super(*args)
|
data/lib/mongrel/command.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
# Mongrel Web Server - A Mostly Ruby Webserver and Library
|
2
|
+
#
|
3
|
+
# Copyright (C) 2005 Zed A. Shaw zedshaw AT zedshaw dot com
|
4
|
+
#
|
5
|
+
# This library 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; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library 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 library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18
|
+
|
1
19
|
require 'rubygems'
|
2
20
|
require 'singleton'
|
3
21
|
require 'optparse'
|
@@ -10,11 +28,13 @@ module Mongrel
|
|
10
28
|
|
11
29
|
module Command
|
12
30
|
|
31
|
+
BANNER = "Usage: mongrel_rails <command> [options]"
|
32
|
+
|
13
33
|
# A Command pattern implementation used to create the set of command available to the user
|
14
34
|
# from Mongrel. The script uses objects which implement this interface to do the
|
15
35
|
# user's bidding.
|
16
36
|
module Base
|
17
|
-
|
37
|
+
|
18
38
|
attr_reader :valid, :done_validating, :original_args
|
19
39
|
|
20
40
|
# Called by the implemented command to set the options for that command.
|
@@ -35,6 +55,7 @@ module Mongrel
|
|
35
55
|
def initialize(options={})
|
36
56
|
argv = options[:argv] || []
|
37
57
|
@opt = OptionParser.new
|
58
|
+
@opt.banner = Mongrel::Command::BANNER
|
38
59
|
@valid = true
|
39
60
|
# this is retarded, but it has to be done this way because -h and -v exit
|
40
61
|
@done_validating = false
|
@@ -47,35 +68,39 @@ module Mongrel
|
|
47
68
|
@done_validating = true
|
48
69
|
puts @opt
|
49
70
|
end
|
50
|
-
|
51
|
-
# I need to add my own -v definition to prevent the -
|
71
|
+
|
72
|
+
# I need to add my own -v definition to prevent the -v from exiting by default as well.
|
52
73
|
@opt.on_tail("--version", "Show version") do
|
53
74
|
@done_validating = true
|
54
75
|
if VERSION
|
55
|
-
puts "Version #{MONGREL_VERSION}"
|
76
|
+
puts "Version #{Mongrel::Const::MONGREL_VERSION}"
|
56
77
|
end
|
57
78
|
end
|
58
|
-
|
79
|
+
|
59
80
|
@opt.parse! argv
|
60
81
|
end
|
61
|
-
|
82
|
+
|
83
|
+
def configure
|
84
|
+
options []
|
85
|
+
end
|
86
|
+
|
62
87
|
# Returns true/false depending on whether the command is configured properly.
|
63
88
|
def validate
|
64
89
|
return @valid
|
65
90
|
end
|
66
|
-
|
91
|
+
|
67
92
|
# Returns a help message. Defaults to OptionParser#help which should be good.
|
68
93
|
def help
|
69
94
|
@opt.help
|
70
95
|
end
|
71
|
-
|
96
|
+
|
72
97
|
# Runs the command doing it's job. You should implement this otherwise it will
|
73
98
|
# throw a NotImplementedError as a reminder.
|
74
99
|
def run
|
75
100
|
raise NotImplementedError
|
76
101
|
end
|
77
|
-
|
78
|
-
|
102
|
+
|
103
|
+
|
79
104
|
# Validates the given expression is true and prints the message if not, exiting.
|
80
105
|
def valid?(exp, message)
|
81
106
|
if not @done_validating and (not exp)
|
@@ -89,29 +114,49 @@ module Mongrel
|
|
89
114
|
def valid_exists?(file, message)
|
90
115
|
valid?(file != nil && File.exist?(file), message)
|
91
116
|
end
|
92
|
-
|
93
|
-
|
117
|
+
|
118
|
+
|
94
119
|
# Validates that the file is a file and not a directory or something else.
|
95
120
|
def valid_file?(file, message)
|
96
121
|
valid?(file != nil && File.file?(file), message)
|
97
122
|
end
|
98
|
-
|
123
|
+
|
99
124
|
# Validates that the given directory exists
|
100
125
|
def valid_dir?(file, message)
|
101
126
|
valid?(file != nil && File.directory?(file), message)
|
102
127
|
end
|
103
128
|
|
129
|
+
def valid_user?(user)
|
130
|
+
valid?(@group, "You must also specify a group.")
|
131
|
+
begin
|
132
|
+
Etc.getpwnam(user)
|
133
|
+
rescue
|
134
|
+
failure "User does not exist: #{user}"
|
135
|
+
@valid = false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def valid_group?(group)
|
140
|
+
valid?(@user, "You must also specify a user.")
|
141
|
+
begin
|
142
|
+
Etc.getgrnam(group)
|
143
|
+
rescue
|
144
|
+
failure "Group does not exist: #{group}"
|
145
|
+
@valid = false
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
104
149
|
# Just a simple method to display failure until something better is developed.
|
105
150
|
def failure(message)
|
106
151
|
STDERR.puts "!!! #{message}"
|
107
152
|
end
|
108
153
|
end
|
109
|
-
|
154
|
+
|
110
155
|
# A Singleton class that manages all of the available commands
|
111
156
|
# and handles running them.
|
112
157
|
class Registry
|
113
158
|
include Singleton
|
114
|
-
|
159
|
+
|
115
160
|
# Builds a list of possible commands from the Command derivates list
|
116
161
|
def commands
|
117
162
|
pmgr = GemPlugin::Manager.instance
|
@@ -121,51 +166,55 @@ module Mongrel
|
|
121
166
|
|
122
167
|
# Prints a list of available commands.
|
123
168
|
def print_command_list
|
124
|
-
puts "
|
125
|
-
|
169
|
+
puts "#{Mongrel::Command::BANNER}\nAvailable commands are:\n\n"
|
170
|
+
|
126
171
|
self.commands.each do |name|
|
127
172
|
puts " - #{name[1 .. -1]}\n"
|
128
173
|
end
|
129
|
-
|
174
|
+
|
130
175
|
puts "\nEach command takes -h as an option to get help."
|
131
|
-
|
176
|
+
|
132
177
|
end
|
133
|
-
|
134
|
-
|
178
|
+
|
179
|
+
|
135
180
|
# Runs the args against the first argument as the command name.
|
136
181
|
# If it has any errors it returns a false, otherwise it return true.
|
137
182
|
def run(args)
|
138
183
|
# find the command
|
139
184
|
cmd_name = args.shift
|
140
|
-
|
185
|
+
|
141
186
|
if !cmd_name or cmd_name == "?" or cmd_name == "help"
|
142
187
|
print_command_list
|
143
188
|
return true
|
189
|
+
elsif cmd_name == "--version"
|
190
|
+
STDERR.puts "Mongrel Web Server #{Mongrel::Const::MONGREL_VERSION}"
|
191
|
+
return true
|
144
192
|
end
|
145
|
-
|
193
|
+
|
146
194
|
# command exists, set it up and validate it
|
147
195
|
begin
|
148
196
|
command = GemPlugin::Manager.instance.create("/commands/#{cmd_name}", :argv => args)
|
149
197
|
rescue
|
150
198
|
STDERR.puts "INVALID COMMAND: #$!"
|
151
199
|
print_command_list
|
152
|
-
return
|
200
|
+
return false
|
153
201
|
end
|
154
|
-
|
202
|
+
|
155
203
|
# Normally the command is NOT valid right after being created
|
156
204
|
# but sometimes (like with -h or -v) there's no further processing
|
157
205
|
# needed so the command is already valid so we can skip it.
|
158
206
|
if not command.done_validating
|
159
207
|
if not command.validate
|
160
|
-
STDERR.puts "#{cmd_name} reported an error. Use -h to get help."
|
208
|
+
STDERR.puts "#{cmd_name} reported an error. Use mongrel_rails #{cmd_name} -h to get help."
|
161
209
|
return false
|
162
210
|
else
|
163
211
|
command.run
|
164
212
|
end
|
165
213
|
end
|
214
|
+
|
166
215
|
return true
|
167
216
|
end
|
168
|
-
|
217
|
+
|
169
218
|
end
|
170
219
|
end
|
171
220
|
end
|
data/lib/mongrel/debug.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
# Mongrel Web Server - A Mostly Ruby Webserver and Library
|
2
|
+
#
|
3
|
+
# Copyright (C) 2005 Zed A. Shaw zedshaw AT zedshaw dot com
|
4
|
+
#
|
5
|
+
# This library 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; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library 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 library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18
|
+
|
1
19
|
require 'logger'
|
2
20
|
require 'set'
|
3
21
|
require 'socket'
|
@@ -48,7 +66,12 @@ module ObjectTracker
|
|
48
66
|
@active_objects = Set.new
|
49
67
|
|
50
68
|
ObjectSpace.each_object do |obj|
|
51
|
-
|
69
|
+
begin
|
70
|
+
# believe it or not, some idiots actually alter the object_id method
|
71
|
+
@active_objects << obj.object_id
|
72
|
+
rescue Object
|
73
|
+
# skip this one, he's an idiot
|
74
|
+
end
|
52
75
|
end
|
53
76
|
end
|
54
77
|
|
@@ -56,12 +79,14 @@ module ObjectTracker
|
|
56
79
|
ospace = Set.new
|
57
80
|
counts = {}
|
58
81
|
|
59
|
-
# Strings can't be tracked easily and are so numerous that they drown out all else
|
60
|
-
# so we just ignore them in the counts.
|
61
82
|
ObjectSpace.each_object do |obj|
|
62
|
-
|
63
|
-
|
64
|
-
|
83
|
+
begin
|
84
|
+
ospace << obj.object_id
|
85
|
+
counts[obj.class] ||= 0
|
86
|
+
counts[obj.class] += 1
|
87
|
+
rescue Object
|
88
|
+
# skip since object_id can magically get parameters
|
89
|
+
end
|
65
90
|
end
|
66
91
|
|
67
92
|
dead_objects = @active_objects - ospace
|
@@ -171,15 +196,19 @@ module RequestLog
|
|
171
196
|
def process(request, response)
|
172
197
|
MongrelDbg::trace(:threads, "#{Time.now} REQUEST #{request.params['PATH_INFO']}")
|
173
198
|
ObjectSpace.each_object do |obj|
|
174
|
-
|
175
|
-
|
199
|
+
begin
|
200
|
+
if obj.class == Mongrel::HttpServer
|
201
|
+
worker_list = obj.workers.list
|
176
202
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
203
|
+
if worker_list.length > 0
|
204
|
+
keys = "-----\n\tKEYS:"
|
205
|
+
worker_list.each {|t| keys << "\n\t\t-- #{t}: #{t.keys.inspect}" }
|
206
|
+
end
|
181
207
|
|
182
|
-
|
208
|
+
MongrelDbg::trace(:threads, "#{obj.host}:#{obj.port} -- THREADS: #{worker_list.length} #{keys}")
|
209
|
+
end
|
210
|
+
rescue Object
|
211
|
+
# ignore since obj.class can sometimes take parameters
|
183
212
|
end
|
184
213
|
end
|
185
214
|
end
|
data/lib/mongrel/handlers.rb
CHANGED
@@ -1,11 +1,23 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
require 'mongrel/stats'
|
2
|
+
require 'zlib'
|
3
|
+
|
4
|
+
# Mongrel Web Server - A Mostly Ruby Webserver and Library
|
5
|
+
#
|
6
|
+
# Copyright (C) 2005 Zed A. Shaw zedshaw AT zedshaw dot com
|
7
|
+
#
|
8
|
+
# This library is free software; you can redistribute it and/or
|
9
|
+
# modify it under the terms of the GNU Lesser General Public
|
10
|
+
# License as published by the Free Software Foundation; either
|
11
|
+
# version 2.1 of the License, or (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This library is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
16
|
+
# Lesser General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU Lesser General Public
|
19
|
+
# License along with this library; if not, write to the Free Software
|
20
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
9
21
|
|
10
22
|
module Mongrel
|
11
23
|
|
@@ -19,6 +31,8 @@ module Mongrel
|
|
19
31
|
# should be implemented using the HttpHandlerPlugin mixin.
|
20
32
|
#
|
21
33
|
class HttpHandler
|
34
|
+
attr_reader :header_only
|
35
|
+
attr_accessor :listener
|
22
36
|
|
23
37
|
def process(request, response)
|
24
38
|
end
|
@@ -31,9 +45,12 @@ module Mongrel
|
|
31
45
|
# the process method later.
|
32
46
|
module HttpHandlerPlugin
|
33
47
|
attr_reader :options
|
48
|
+
attr_reader :header_only
|
49
|
+
attr_accessor :listener
|
34
50
|
|
35
51
|
def initialize(options={})
|
36
52
|
@options = options
|
53
|
+
@header_only = false
|
37
54
|
end
|
38
55
|
|
39
56
|
def process(request, response)
|
@@ -52,7 +69,7 @@ module Mongrel
|
|
52
69
|
def initialize(msg)
|
53
70
|
@response = Const::ERROR_404_RESPONSE + msg
|
54
71
|
end
|
55
|
-
|
72
|
+
|
56
73
|
# Just kicks back the standard 404 response with your special message.
|
57
74
|
def process(request, response)
|
58
75
|
response.socket.write(@response)
|
@@ -104,26 +121,27 @@ module Mongrel
|
|
104
121
|
|
105
122
|
# Checks if the given path can be served and returns the full path (or nil if not).
|
106
123
|
def can_serve(path_info)
|
107
|
-
|
124
|
+
# TODO: investigate freezing the path_info to prevent double escaping
|
125
|
+
req_path = File.expand_path(File.join(@path,HttpRequest.unescape(path_info)), @path)
|
108
126
|
|
109
|
-
if
|
127
|
+
if req_path.index(@path) == 0 and File.exist? req_path
|
110
128
|
# it exists and it's in the right location
|
111
|
-
if File.directory?
|
129
|
+
if File.directory? req_path
|
112
130
|
# the request is for a directory
|
113
|
-
index = File.join(
|
131
|
+
index = File.join(req_path, @index_html)
|
114
132
|
if File.exist? index
|
115
133
|
# serve the index
|
116
134
|
return index
|
117
135
|
elsif @listing_allowed
|
118
136
|
# serve the directory
|
119
|
-
|
137
|
+
return req_path
|
120
138
|
else
|
121
139
|
# do not serve anything
|
122
140
|
return nil
|
123
141
|
end
|
124
142
|
else
|
125
143
|
# it's a file and it's there
|
126
|
-
return
|
144
|
+
return req_path
|
127
145
|
end
|
128
146
|
else
|
129
147
|
# does not exist or isn't in the right spot
|
@@ -138,6 +156,7 @@ module Mongrel
|
|
138
156
|
# object to send the results on.
|
139
157
|
def send_dir_listing(base, dir, response)
|
140
158
|
# take off any trailing / so the links come out right
|
159
|
+
base = HttpRequest.unescape(base)
|
141
160
|
base.chop! if base[-1] == "/"[-1]
|
142
161
|
|
143
162
|
if @listing_allowed
|
@@ -145,12 +164,13 @@ module Mongrel
|
|
145
164
|
head[Const::CONTENT_TYPE] = "text/html"
|
146
165
|
out << "<html><head><title>Directory Listing</title></head><body>"
|
147
166
|
Dir.entries(dir).each do |child|
|
167
|
+
child = HttpRequest.unescape(child)
|
148
168
|
next if child == "."
|
149
169
|
|
150
170
|
if child == ".."
|
151
171
|
out << "<a href=\"#{base}/#{child}\">Up to parent..</a><br/>"
|
152
172
|
else
|
153
|
-
out << "<a href=\"#{base}/#{child}
|
173
|
+
out << "<a href=\"#{base}/#{child}/\">#{child}</a><br/>"
|
154
174
|
end
|
155
175
|
end
|
156
176
|
out << "</body></html>"
|
@@ -162,72 +182,81 @@ module Mongrel
|
|
162
182
|
end
|
163
183
|
end
|
164
184
|
|
165
|
-
|
185
|
+
|
166
186
|
# Sends the contents of a file back to the user. Not terribly efficient since it's
|
167
187
|
# opening and closing the file for each read.
|
168
|
-
def send_file(
|
188
|
+
def send_file(req_path, request, response, header_only=false)
|
169
189
|
|
170
|
-
|
171
|
-
response.status = 200
|
172
|
-
stat = File.stat(req)
|
173
|
-
header = response.header
|
190
|
+
stat = File.stat(req_path)
|
174
191
|
|
175
192
|
# Set the last modified times as well and etag for all files
|
176
|
-
|
193
|
+
mtime = stat.mtime
|
177
194
|
# Calculated the same as apache, not sure how well the works on win32
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
195
|
+
etag = Const::ETAG_FORMAT % [mtime.to_i, stat.size, stat.ino]
|
196
|
+
|
197
|
+
unmodified_since = request.params[Const::HTTP_IF_UNMODIFIED_SINCE]
|
198
|
+
none_match = request.params[Const::HTTP_IF_NONE_MATCH]
|
199
|
+
|
200
|
+
# test to see if this is a conditional request, and test if
|
201
|
+
# the response would be identical to the last response
|
202
|
+
same_response = case
|
203
|
+
when unmodified_since && !last_response_time = Time.httpdate(unmodified_since) rescue nil : false
|
204
|
+
when unmodified_since && last_response_time > Time.now : false
|
205
|
+
when unmodified_since && mtime > last_response_time : false
|
206
|
+
when none_match && none_match == '*' : false
|
207
|
+
when none_match && !none_match.strip.split(/\s*,\s*/).include?(etag) : false
|
208
|
+
else unmodified_since || none_match # validation successful if we get this far and at least one of the header exists
|
209
|
+
end
|
210
|
+
|
211
|
+
header = response.header
|
212
|
+
header[Const::ETAG] = etag
|
185
213
|
|
186
|
-
|
187
|
-
|
188
|
-
response.send_header
|
189
|
-
|
190
|
-
if not header_only
|
191
|
-
begin
|
192
|
-
if $mongrel_has_sendfile
|
193
|
-
File.open(req, "rb") { |f| response.socket.sendfile(f) }
|
194
|
-
else
|
195
|
-
File.open(req, "rb") { |f| response.socket.write(f.read) }
|
196
|
-
end
|
197
|
-
rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
|
198
|
-
# ignore these since it means the client closed off early
|
199
|
-
STDERR.puts "Client closed socket requesting file #{req}: #$!"
|
200
|
-
end
|
214
|
+
if same_response
|
215
|
+
response.start(304) {}
|
201
216
|
else
|
202
|
-
|
217
|
+
# first we setup the headers and status then we do a very fast send on the socket directly
|
218
|
+
response.status = 200
|
219
|
+
header[Const::LAST_MODIFIED] = mtime.httpdate
|
220
|
+
|
221
|
+
# set the mime type from our map based on the ending
|
222
|
+
dot_at = req_path.rindex('.')
|
223
|
+
if dot_at
|
224
|
+
header[Const::CONTENT_TYPE] = MIME_TYPES[req_path[dot_at .. -1]] || @default_content_type
|
225
|
+
end
|
226
|
+
|
227
|
+
# send a status with out content length
|
228
|
+
response.send_status(stat.size)
|
229
|
+
response.send_header
|
230
|
+
|
231
|
+
if not header_only
|
232
|
+
response.send_file(req_path)
|
233
|
+
end
|
203
234
|
end
|
204
235
|
end
|
205
236
|
|
206
|
-
|
207
237
|
# Process the request to either serve a file or a directory listing
|
208
|
-
# if allowed (based on the listing_allowed
|
238
|
+
# if allowed (based on the listing_allowed parameter to the constructor).
|
209
239
|
def process(request, response)
|
210
240
|
req_method = request.params[Const::REQUEST_METHOD] || Const::GET
|
211
|
-
|
212
|
-
if not
|
241
|
+
req_path = can_serve request.params[Const::PATH_INFO]
|
242
|
+
if not req_path
|
213
243
|
# not found, return a 404
|
214
244
|
response.start(404) do |head,out|
|
215
245
|
out << "File not found"
|
216
246
|
end
|
217
247
|
else
|
218
248
|
begin
|
219
|
-
if File.directory?
|
220
|
-
send_dir_listing(request.params[Const::REQUEST_URI],
|
249
|
+
if File.directory? req_path
|
250
|
+
send_dir_listing(request.params[Const::REQUEST_URI], req_path, response)
|
221
251
|
elsif req_method == Const::HEAD
|
222
|
-
send_file(
|
223
|
-
|
224
|
-
send_file(
|
225
|
-
|
226
|
-
|
252
|
+
send_file(req_path, request, response, true)
|
253
|
+
elsif req_method == Const::GET
|
254
|
+
send_file(req_path, request, response, false)
|
255
|
+
else
|
256
|
+
response.start(403) {|head,out| out.write(ONLY_HEAD_GET) }
|
227
257
|
end
|
228
258
|
rescue => details
|
229
|
-
STDERR.puts "Error
|
230
|
-
STDERR.puts details.backtrace.join("\n")
|
259
|
+
STDERR.puts "Error sending file #{req_path}: #{details}"
|
231
260
|
end
|
232
261
|
end
|
233
262
|
end
|
@@ -239,4 +268,134 @@ module Mongrel
|
|
239
268
|
end
|
240
269
|
|
241
270
|
end
|
271
|
+
|
272
|
+
|
273
|
+
# When added to a config script (-S in mongrel_rails) it will
|
274
|
+
# look at the client's allowed response types and then gzip
|
275
|
+
# compress anything that is going out.
|
276
|
+
#
|
277
|
+
# Valid option is :always_deflate => false which tells the handler to
|
278
|
+
# deflate everything even if the client can't handle it.
|
279
|
+
class DeflateFilter < HttpHandler
|
280
|
+
HTTP_ACCEPT_ENCODING = "HTTP_ACCEPT_ENCODING"
|
281
|
+
|
282
|
+
def initialize(ops={})
|
283
|
+
@options = ops
|
284
|
+
@always_deflate = ops[:always_deflate] || false
|
285
|
+
end
|
286
|
+
|
287
|
+
def process(request, response)
|
288
|
+
accepts = request.params[HTTP_ACCEPT_ENCODING]
|
289
|
+
# only process if they support compression
|
290
|
+
if @always_deflate or (accepts and (accepts.include? "deflate" and not response.body_sent))
|
291
|
+
response.header["Content-Encoding"] = "deflate"
|
292
|
+
# we can't just rewind the body and gzip it since the body could be an attached file
|
293
|
+
response.body.rewind
|
294
|
+
gzout = StringIO.new(Zlib::Deflate.deflate(response.body.read))
|
295
|
+
gzout.rewind
|
296
|
+
response.body.close
|
297
|
+
response.body = gzout
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
# Implements a few basic statistics for a particular URI. Register it anywhere
|
304
|
+
# you want in the request chain and it'll quickly gather some numbers for you
|
305
|
+
# to analyze. It is pretty fast, but don't put it out in production.
|
306
|
+
#
|
307
|
+
# You should pass the filter to StatusHandler as StatusHandler.new(:stats_filter => stats).
|
308
|
+
# This lets you then hit the status URI you want and get these stats from a browser.
|
309
|
+
#
|
310
|
+
# StatisticsFilter takes an option of :sample_rate. This is a number that's passed to
|
311
|
+
# rand and if that number gets hit then a sample is taken. This helps reduce the load
|
312
|
+
# and keeps the statistics valid (since sampling is a part of how they work).
|
313
|
+
#
|
314
|
+
# The exception to :sample_rate is that inter-request time is sampled on every request.
|
315
|
+
# If this wasn't done then it wouldn't be accurate as a measure of time between requests.
|
316
|
+
class StatisticsFilter < HttpHandler
|
317
|
+
attr_reader :stats
|
318
|
+
|
319
|
+
def initialize(ops={})
|
320
|
+
@sample_rate = ops[:sample_rate] || 300
|
321
|
+
|
322
|
+
@processors = Stats.new("processors")
|
323
|
+
@reqsize = Stats.new("request Kb")
|
324
|
+
@headcount = Stats.new("req param count")
|
325
|
+
@respsize = Stats.new("response Kb")
|
326
|
+
@interreq = Stats.new("inter-request time")
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
def process(request, response)
|
331
|
+
if rand(@sample_rate)+1 == @sample_rate
|
332
|
+
@processors.sample(listener.workers.list.length)
|
333
|
+
@headcount.sample(request.params.length)
|
334
|
+
@reqsize.sample(request.body.length / 1024.0)
|
335
|
+
@respsize.sample((response.body.length + response.header.out.length) / 1024.0)
|
336
|
+
end
|
337
|
+
@interreq.tick
|
338
|
+
end
|
339
|
+
|
340
|
+
def dump
|
341
|
+
"#{@processors.to_s}\n#{@reqsize.to_s}\n#{@headcount.to_s}\n#{@respsize.to_s}\n#{@interreq.to_s}"
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
|
346
|
+
# The :stats_filter is basically any configured stats filter that you've added to this same
|
347
|
+
# URI. This lets the status handler print out statistics on how Mongrel is doing.
|
348
|
+
class StatusHandler < HttpHandler
|
349
|
+
def initialize(ops={})
|
350
|
+
@stats = ops[:stats_filter]
|
351
|
+
end
|
352
|
+
|
353
|
+
def table(title, rows)
|
354
|
+
results = "<table border=\"1\"><tr><th colspan=\"#{rows[0].length}\">#{title}</th></tr>"
|
355
|
+
rows.each do |cols|
|
356
|
+
results << "<tr>"
|
357
|
+
cols.each {|col| results << "<td>#{col}</td>" }
|
358
|
+
results << "</tr>"
|
359
|
+
end
|
360
|
+
results + "</table>"
|
361
|
+
end
|
362
|
+
|
363
|
+
def describe_listener
|
364
|
+
results = ""
|
365
|
+
results << "<h1>Listener #{listener.host}:#{listener.port}</h1>"
|
366
|
+
results << table("settings", [
|
367
|
+
["host",listener.host],
|
368
|
+
["port",listener.port],
|
369
|
+
["timeout",listener.timeout],
|
370
|
+
["workers max",listener.num_processors],
|
371
|
+
])
|
372
|
+
|
373
|
+
if @stats
|
374
|
+
results << "<h2>Statistics</h2><p>N means the number of samples, pay attention to MEAN, SD, MIN and MAX."
|
375
|
+
results << "<pre>#{@stats.dump}</pre>"
|
376
|
+
end
|
377
|
+
|
378
|
+
results << "<h2>Registered Handlers</h2>"
|
379
|
+
uris = listener.classifier.handler_map
|
380
|
+
results << table("handlers", uris.map {|uri,handlers|
|
381
|
+
[uri,
|
382
|
+
"<pre>" +
|
383
|
+
handlers.map {|h| h.class.to_s }.join("\n") +
|
384
|
+
"</pre>"
|
385
|
+
]
|
386
|
+
})
|
387
|
+
|
388
|
+
results
|
389
|
+
end
|
390
|
+
|
391
|
+
def process(request, response)
|
392
|
+
response.start do |head,out|
|
393
|
+
out.write <<-END
|
394
|
+
<html><body><title>Mongrel Server Status</title>
|
395
|
+
#{describe_listener}
|
396
|
+
</body></html>
|
397
|
+
END
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
242
401
|
end
|