mongrel 0.3.12.4 → 0.3.13
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/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/ext/http11/http11_parser.h
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
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
|
+
*/
|
|
19
|
+
|
|
1
20
|
#ifndef http11_parser_h
|
|
2
21
|
#define http11_parser_h
|
|
3
22
|
|
|
@@ -12,11 +31,11 @@ typedef void (*field_cb)(void *data, const char *field, size_t flen, const char
|
|
|
12
31
|
|
|
13
32
|
typedef struct http_parser {
|
|
14
33
|
int cs;
|
|
15
|
-
|
|
34
|
+
size_t body_start;
|
|
16
35
|
int content_len;
|
|
17
36
|
size_t nread;
|
|
18
|
-
|
|
19
|
-
|
|
37
|
+
size_t mark;
|
|
38
|
+
size_t field_start;
|
|
20
39
|
size_t field_len;
|
|
21
40
|
|
|
22
41
|
void *data;
|
|
@@ -32,10 +51,9 @@ typedef struct http_parser {
|
|
|
32
51
|
|
|
33
52
|
int http_parser_init(http_parser *parser);
|
|
34
53
|
int http_parser_finish(http_parser *parser);
|
|
35
|
-
size_t http_parser_execute(http_parser *parser, const char *data, size_t len );
|
|
54
|
+
size_t http_parser_execute(http_parser *parser, const char *data, size_t len, size_t off);
|
|
36
55
|
int http_parser_has_error(http_parser *parser);
|
|
37
56
|
int http_parser_is_finished(http_parser *parser);
|
|
38
|
-
void http_parser_destroy(http_parser *parser);
|
|
39
57
|
|
|
40
58
|
#define http_parser_nread(parser) (parser)->nread
|
|
41
59
|
|
data/lib/mongrel.rb
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
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 'socket'
|
|
2
20
|
require 'http11'
|
|
21
|
+
require 'tempfile'
|
|
3
22
|
require 'thread'
|
|
4
23
|
require 'stringio'
|
|
5
24
|
require 'mongrel/cgi'
|
|
@@ -8,6 +27,17 @@ require 'mongrel/command'
|
|
|
8
27
|
require 'mongrel/tcphack'
|
|
9
28
|
require 'yaml'
|
|
10
29
|
require 'time'
|
|
30
|
+
require 'rubygems'
|
|
31
|
+
require 'etc'
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
require 'sendfile'
|
|
36
|
+
STDERR.puts "** You have sendfile installed, will use that to serve files."
|
|
37
|
+
rescue Object
|
|
38
|
+
# do nothing
|
|
39
|
+
end
|
|
40
|
+
|
|
11
41
|
|
|
12
42
|
# Mongrel module containing all of the classes (include C extensions) for running
|
|
13
43
|
# a Mongrel web server. It contains a minimalist HTTP server with just enough
|
|
@@ -15,6 +45,8 @@ require 'time'
|
|
|
15
45
|
module Mongrel
|
|
16
46
|
|
|
17
47
|
class URIClassifier
|
|
48
|
+
attr_reader :handler_map
|
|
49
|
+
|
|
18
50
|
# Returns the URIs that have been registered with this classifier so far.
|
|
19
51
|
# The URIs returned should not be modified as this will cause a memory leak.
|
|
20
52
|
# You can use this to inspect the contents of the URIClassifier.
|
|
@@ -77,7 +109,7 @@ module Mongrel
|
|
|
77
109
|
505 => 'HTTP Version not supported'
|
|
78
110
|
}
|
|
79
111
|
|
|
80
|
-
|
|
112
|
+
|
|
81
113
|
|
|
82
114
|
# Frequently used constants when constructing requests or responses. Many times
|
|
83
115
|
# the constant just refers to a string with the same contents. Using these constants
|
|
@@ -93,13 +125,16 @@ module Mongrel
|
|
|
93
125
|
# This is the part of the path after the SCRIPT_NAME. URIClassifier will determine this.
|
|
94
126
|
PATH_INFO="PATH_INFO".freeze
|
|
95
127
|
|
|
96
|
-
# This is the
|
|
128
|
+
# This is the initial part that your handler is identified as by URIClassifier.
|
|
97
129
|
SCRIPT_NAME="SCRIPT_NAME".freeze
|
|
98
130
|
|
|
99
131
|
# The original URI requested by the client. Passed to URIClassifier to build PATH_INFO and SCRIPT_NAME.
|
|
100
132
|
REQUEST_URI='REQUEST_URI'.freeze
|
|
101
133
|
|
|
102
|
-
MONGREL_VERSION="0.3.
|
|
134
|
+
MONGREL_VERSION="0.3.13".freeze
|
|
135
|
+
|
|
136
|
+
# TODO: this use of a base for tempfiles needs to be looked at for security problems
|
|
137
|
+
MONGREL_TMP_BASE="mongrel".freeze
|
|
103
138
|
|
|
104
139
|
# The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
|
|
105
140
|
ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: #{MONGREL_VERSION}\r\n\r\nNOT FOUND".freeze
|
|
@@ -116,6 +151,9 @@ module Mongrel
|
|
|
116
151
|
# this, but we'd also like to do this as well.
|
|
117
152
|
MAX_HEADER=1024 * (80 + 32)
|
|
118
153
|
|
|
154
|
+
# Maximum request body size before it is moved out of memory and into a tempfile for reading.
|
|
155
|
+
MAX_BODY=MAX_HEADER
|
|
156
|
+
|
|
119
157
|
# A frozen format for this is about 15% faster
|
|
120
158
|
STATUS_FORMAT = "HTTP/1.1 %d %s\r\nContent-Length: %d\r\nConnection: close\r\n".freeze
|
|
121
159
|
CONTENT_TYPE = "Content-Type".freeze
|
|
@@ -131,6 +169,8 @@ module Mongrel
|
|
|
131
169
|
LINE_END="\r\n".freeze
|
|
132
170
|
REMOTE_ADDR="REMOTE_ADDR".freeze
|
|
133
171
|
HTTP_X_FORWARDED_FOR="HTTP_X_FORWARDED_FOR".freeze
|
|
172
|
+
HTTP_IF_UNMODIFIED_SINCE="HTTP_IF_UNMODIFIED_SINCE".freeze
|
|
173
|
+
HTTP_IF_NONE_MATCH="HTTP_IF_NONE_MATCH".freeze
|
|
134
174
|
end
|
|
135
175
|
|
|
136
176
|
|
|
@@ -140,30 +180,58 @@ module Mongrel
|
|
|
140
180
|
# HttpRequest.params Hash that matches common CGI params, and a HttpRequest.body
|
|
141
181
|
# which is a string containing the request body (raw for now).
|
|
142
182
|
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
# uploads.
|
|
183
|
+
# The HttpRequest.initialize method will convert any request that is larger than
|
|
184
|
+
# Const::MAX_BODY into a Tempfile and use that as the body. Otherwise it uses
|
|
185
|
+
# a StringIO object. To be safe, you should assume it works like a file.
|
|
147
186
|
class HttpRequest
|
|
148
187
|
attr_reader :body, :params
|
|
149
188
|
|
|
150
189
|
# You don't really call this. It's made for you.
|
|
151
190
|
# Main thing it does is hook up the params, and store any remaining
|
|
152
191
|
# body data into the HttpRequest.body attribute.
|
|
192
|
+
#
|
|
193
|
+
# TODO: Implement tempfile removal when the request is done.
|
|
153
194
|
def initialize(params, initial_body, socket)
|
|
154
|
-
@body = initial_body || ""
|
|
155
195
|
@params = params
|
|
156
196
|
@socket = socket
|
|
157
197
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
clen
|
|
161
|
-
|
|
162
|
-
@body
|
|
198
|
+
clen = params[Const::CONTENT_LENGTH].to_i - initial_body.length
|
|
199
|
+
|
|
200
|
+
if clen > Const::MAX_BODY
|
|
201
|
+
@body = Tempfile.new(Const::MONGREL_TMP_BASE)
|
|
202
|
+
@body.binmode
|
|
203
|
+
else
|
|
204
|
+
@body = StringIO.new
|
|
163
205
|
end
|
|
164
206
|
|
|
207
|
+
begin
|
|
208
|
+
@body.write(initial_body)
|
|
209
|
+
|
|
210
|
+
# write the odd sized chunk first
|
|
211
|
+
clen -= @body.write(@socket.read(clen % Const::CHUNK_SIZE))
|
|
212
|
+
|
|
213
|
+
# then stream out nothing but perfectly sized chunks
|
|
214
|
+
while clen > 0
|
|
215
|
+
data = @socket.read(Const::CHUNK_SIZE)
|
|
216
|
+
# have to do it this way since @socket.eof? causes it to block
|
|
217
|
+
raise "Socket closed or read failure" if not data or data.length != Const::CHUNK_SIZE
|
|
218
|
+
clen -= @body.write(data)
|
|
219
|
+
# ASSUME: we are writing to a disk and these writes always write the requested amount
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# rewind to keep the world happy
|
|
223
|
+
@body.rewind
|
|
224
|
+
rescue Object
|
|
225
|
+
# any errors means we should delete the file, including if the file is dumped
|
|
226
|
+
STDERR.puts "Error reading request: #$!"
|
|
227
|
+
@body.delete if @body.class == Tempfile
|
|
228
|
+
@body = nil # signals that there was a problem
|
|
229
|
+
end
|
|
165
230
|
end
|
|
166
231
|
|
|
232
|
+
# Performs URI escaping so that you can construct proper
|
|
233
|
+
# query strings faster. Use this rather than the cgi.rb
|
|
234
|
+
# version since it's faster. (Stolen from Camping).
|
|
167
235
|
def self.escape(s)
|
|
168
236
|
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
|
169
237
|
'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
|
@@ -171,13 +239,17 @@ module Mongrel
|
|
|
171
239
|
end
|
|
172
240
|
|
|
173
241
|
|
|
242
|
+
# Unescapes a URI escaped string. (Stolen from Camping).
|
|
174
243
|
def self.unescape(s)
|
|
175
244
|
s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
|
176
245
|
[$1.delete('%')].pack('H*')
|
|
177
246
|
}
|
|
178
247
|
end
|
|
179
248
|
|
|
180
|
-
|
|
249
|
+
# Parses a query string by breaking it up at the '&'
|
|
250
|
+
# and ';' characters. You can also use this to parse
|
|
251
|
+
# cookies by changing the characters used in the second
|
|
252
|
+
# parameter (which defaults to '&;'.
|
|
181
253
|
def self.query_parse(qs, d = '&;')
|
|
182
254
|
params = {}
|
|
183
255
|
(qs||'').split(/[#{d}] */n).inject(params) { |h,p|
|
|
@@ -195,8 +267,6 @@ module Mongrel
|
|
|
195
267
|
|
|
196
268
|
return params
|
|
197
269
|
end
|
|
198
|
-
|
|
199
|
-
|
|
200
270
|
end
|
|
201
271
|
|
|
202
272
|
|
|
@@ -218,7 +288,6 @@ module Mongrel
|
|
|
218
288
|
def[]=(key,value)
|
|
219
289
|
@out.write(Const::HEADER_FORMAT % [key, value])
|
|
220
290
|
end
|
|
221
|
-
|
|
222
291
|
end
|
|
223
292
|
|
|
224
293
|
# Writes and controls your response to the client using the HTTP/1.1 specification.
|
|
@@ -253,13 +322,14 @@ module Mongrel
|
|
|
253
322
|
class HttpResponse
|
|
254
323
|
attr_reader :socket
|
|
255
324
|
attr_reader :body
|
|
325
|
+
attr_writer :body
|
|
256
326
|
attr_reader :header
|
|
257
327
|
attr_reader :status
|
|
258
328
|
attr_writer :status
|
|
259
329
|
attr_reader :body_sent
|
|
260
330
|
attr_reader :header_sent
|
|
261
331
|
attr_reader :status_sent
|
|
262
|
-
|
|
332
|
+
|
|
263
333
|
def initialize(socket)
|
|
264
334
|
@socket = socket
|
|
265
335
|
@body = StringIO.new
|
|
@@ -301,8 +371,8 @@ module Mongrel
|
|
|
301
371
|
|
|
302
372
|
def send_status(content_length=nil)
|
|
303
373
|
if not @status_sent
|
|
304
|
-
|
|
305
|
-
|
|
374
|
+
content_length ||= @body.length
|
|
375
|
+
write(Const::STATUS_FORMAT % [status, HTTP_STATUS_CODES[@status], content_length])
|
|
306
376
|
@status_sent = true
|
|
307
377
|
end
|
|
308
378
|
end
|
|
@@ -310,7 +380,7 @@ module Mongrel
|
|
|
310
380
|
def send_header
|
|
311
381
|
if not @header_sent
|
|
312
382
|
@header.out.rewind
|
|
313
|
-
|
|
383
|
+
write(@header.out.read + Const::LINE_END)
|
|
314
384
|
@header_sent = true
|
|
315
385
|
end
|
|
316
386
|
end
|
|
@@ -318,14 +388,47 @@ module Mongrel
|
|
|
318
388
|
def send_body
|
|
319
389
|
if not @body_sent
|
|
320
390
|
@body.rewind
|
|
321
|
-
|
|
322
|
-
@socket.write(@body.read)
|
|
391
|
+
write(@body.read)
|
|
323
392
|
@body_sent = true
|
|
324
393
|
end
|
|
325
394
|
end
|
|
326
395
|
|
|
396
|
+
# Appends the contents of +path+ to the response stream. The file is opened for binary
|
|
397
|
+
# reading and written in chunks to the socket. If the
|
|
398
|
+
# <a href="http://rubyforge.org/projects/ruby-sendfile">sendfile</a> library is found,
|
|
399
|
+
# it is used to send the file, often with greater speed and less memory/cpu usage.
|
|
400
|
+
#
|
|
401
|
+
# The presence of ruby-sendfile is determined by @socket.response_to? :sendfile, which means
|
|
402
|
+
# that if you have your own sendfile implementation you can use it without changing this function,
|
|
403
|
+
# just make sure it follows the ruby-sendfile signature.
|
|
404
|
+
def send_file(path)
|
|
405
|
+
File.open(path, "rb") do |f|
|
|
406
|
+
if @socket.respond_to? :sendfile
|
|
407
|
+
begin
|
|
408
|
+
@socket.sendfile(f)
|
|
409
|
+
rescue => details
|
|
410
|
+
socket_error(details)
|
|
411
|
+
end
|
|
412
|
+
else
|
|
413
|
+
while chunk = f.read(Const::CHUNK_SIZE) and chunk.length > 0
|
|
414
|
+
write(chunk)
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
@body_send = true
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def socket_error(details)
|
|
422
|
+
# ignore these since it means the client closed off early
|
|
423
|
+
@socket.close unless @socket.closed?
|
|
424
|
+
done = true
|
|
425
|
+
raise details
|
|
426
|
+
end
|
|
427
|
+
|
|
327
428
|
def write(data)
|
|
328
429
|
@socket.write(data)
|
|
430
|
+
rescue => details
|
|
431
|
+
socket_error(details)
|
|
329
432
|
end
|
|
330
433
|
|
|
331
434
|
# This takes whatever has been done to header and body and then writes it in the
|
|
@@ -336,14 +439,19 @@ module Mongrel
|
|
|
336
439
|
send_body
|
|
337
440
|
end
|
|
338
441
|
|
|
442
|
+
# Used during error conditions to mark the response as "done" so there isn't any more processing
|
|
443
|
+
# sent to the client.
|
|
444
|
+
def done=(val)
|
|
445
|
+
@status_sent = true
|
|
446
|
+
@header_sent = true
|
|
447
|
+
@body_sent = true
|
|
448
|
+
end
|
|
449
|
+
|
|
339
450
|
def done
|
|
340
451
|
(@status_sent and @header_sent and @body_sent)
|
|
341
452
|
end
|
|
342
453
|
|
|
343
454
|
end
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
455
|
|
|
348
456
|
# This is the main driver of Mongrel, while the Mognrel::HttpParser and Mongrel::URIClassifier
|
|
349
457
|
# make up the majority of how the server functions. It's a very simple class that just
|
|
@@ -353,7 +461,7 @@ module Mongrel
|
|
|
353
461
|
# You use it by doing the following:
|
|
354
462
|
#
|
|
355
463
|
# server = HttpServer.new("0.0.0.0", 3000)
|
|
356
|
-
# server.register("/stuff",
|
|
464
|
+
# server.register("/stuff", MyNiftyHandler.new)
|
|
357
465
|
# server.run.join
|
|
358
466
|
#
|
|
359
467
|
# The last line can be just server.run if you don't want to join the thread used.
|
|
@@ -369,6 +477,8 @@ module Mongrel
|
|
|
369
477
|
attr_reader :classifier
|
|
370
478
|
attr_reader :host
|
|
371
479
|
attr_reader :port
|
|
480
|
+
attr_reader :timeout
|
|
481
|
+
attr_reader :num_processors
|
|
372
482
|
|
|
373
483
|
# Creates a working server on host:port (strange things happen if port isn't a Number).
|
|
374
484
|
# Use HttpServer::run to start the server and HttpServer.acceptor.join to
|
|
@@ -383,6 +493,8 @@ module Mongrel
|
|
|
383
493
|
# The timeout parameter is a sleep timeout (in hundredths of a second) that is placed between
|
|
384
494
|
# socket.accept calls in order to give the server a cheap throttle time. It defaults to 0 and
|
|
385
495
|
# actually if it is 0 then the sleep is not done at all.
|
|
496
|
+
#
|
|
497
|
+
# TODO: Find out if anyone actually uses the timeout option since it seems to cause problems on FBSD.
|
|
386
498
|
def initialize(host, port, num_processors=(2**30-1), timeout=0)
|
|
387
499
|
@socket = TCPServer.new(host, port)
|
|
388
500
|
@classifier = URIClassifier.new
|
|
@@ -393,7 +505,7 @@ module Mongrel
|
|
|
393
505
|
@num_processors = num_processors
|
|
394
506
|
@death_time = 60
|
|
395
507
|
end
|
|
396
|
-
|
|
508
|
+
|
|
397
509
|
|
|
398
510
|
# Does the majority of the IO processing. It has been written in Ruby using
|
|
399
511
|
# about 7 different IO processing strategies and no matter how it's done
|
|
@@ -406,9 +518,14 @@ module Mongrel
|
|
|
406
518
|
params = {}
|
|
407
519
|
|
|
408
520
|
data = client.readpartial(Const::CHUNK_SIZE)
|
|
521
|
+
nparsed = 0
|
|
409
522
|
|
|
410
|
-
|
|
411
|
-
|
|
523
|
+
# Assumption: nparsed will always be less since data will get filled with more
|
|
524
|
+
# after each parsing. If it doesn't get more then there was a problem
|
|
525
|
+
# with the read operation on the client socket. Effect is to stop processing when the
|
|
526
|
+
# socket can't fill the buffer for further parsing.
|
|
527
|
+
while nparsed < data.length
|
|
528
|
+
nparsed = parser.execute(params, data, nparsed)
|
|
412
529
|
|
|
413
530
|
if parser.finished?
|
|
414
531
|
script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_URI])
|
|
@@ -418,44 +535,49 @@ module Mongrel
|
|
|
418
535
|
params[Const::SCRIPT_NAME] = script_name
|
|
419
536
|
params[Const::REMOTE_ADDR] = params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last
|
|
420
537
|
|
|
421
|
-
|
|
538
|
+
# TODO: Find a faster/better way to carve out the range, preferably without copying.
|
|
539
|
+
request = HttpRequest.new(params, data[nparsed ... data.length] || "", client)
|
|
540
|
+
|
|
541
|
+
# in the case of large file uploads the user could close the socket, so skip those requests
|
|
542
|
+
break if request.body == nil # nil signals from HttpRequest::initialize that the request was aborted
|
|
543
|
+
|
|
544
|
+
# request is good so far, continue processing the response
|
|
422
545
|
response = HttpResponse.new(client)
|
|
423
|
-
|
|
546
|
+
|
|
547
|
+
# Process each handler in registered order until we run out or one finalizes the response.
|
|
424
548
|
handlers.each do |handler|
|
|
425
549
|
handler.process(request, response)
|
|
426
|
-
break if response.done
|
|
550
|
+
break if response.done or client.closed?
|
|
427
551
|
end
|
|
428
552
|
|
|
429
|
-
if
|
|
553
|
+
# And finally, if nobody closed the response off, we finalize it.
|
|
554
|
+
unless response.done or client.closed?
|
|
430
555
|
response.finished
|
|
431
556
|
end
|
|
432
|
-
|
|
433
557
|
else
|
|
558
|
+
# Didn't find it, return a stock 404 response.
|
|
559
|
+
# TODO: Implement customer 404 files (but really they should use a real web server).
|
|
434
560
|
client.write(Const::ERROR_404_RESPONSE)
|
|
435
561
|
end
|
|
436
|
-
|
|
562
|
+
|
|
437
563
|
break #done
|
|
438
564
|
else
|
|
439
|
-
#
|
|
440
|
-
|
|
565
|
+
# Parser is not done, queue up more data to read and continue parsing
|
|
566
|
+
data << client.readpartial(Const::CHUNK_SIZE)
|
|
441
567
|
if data.length >= Const::MAX_HEADER
|
|
442
568
|
raise HttpParserError.new("HEADER is longer than allowed, aborting client early.")
|
|
443
569
|
end
|
|
444
|
-
|
|
445
|
-
parser.reset
|
|
446
|
-
data << client.readpartial(Const::CHUNK_SIZE)
|
|
447
570
|
end
|
|
448
571
|
end
|
|
449
|
-
rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL
|
|
572
|
+
rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
|
|
450
573
|
# ignored
|
|
451
574
|
rescue HttpParserError
|
|
452
|
-
STDERR.puts "BAD CLIENT (#{client.peeraddr.last}): #$!"
|
|
453
|
-
STDERR.puts "REQUEST DATA: #{data}"
|
|
575
|
+
STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
|
|
454
576
|
rescue => details
|
|
455
|
-
STDERR.puts "ERROR: #$!"
|
|
577
|
+
STDERR.puts "#{Time.now}: ERROR: #$!"
|
|
456
578
|
STDERR.puts details.backtrace.join("\n")
|
|
457
579
|
ensure
|
|
458
|
-
client.close
|
|
580
|
+
client.close unless client.closed?
|
|
459
581
|
end
|
|
460
582
|
end
|
|
461
583
|
|
|
@@ -473,7 +595,7 @@ module Mongrel
|
|
|
473
595
|
end
|
|
474
596
|
end
|
|
475
597
|
end
|
|
476
|
-
|
|
598
|
+
|
|
477
599
|
|
|
478
600
|
# Runs the thing. It returns the thread used so you can "join" it. You can also
|
|
479
601
|
# access the HttpServer::acceptor attribute to get the thread later.
|
|
@@ -494,15 +616,14 @@ module Mongrel
|
|
|
494
616
|
thread = Thread.new do
|
|
495
617
|
process_client(client)
|
|
496
618
|
end
|
|
497
|
-
|
|
619
|
+
|
|
498
620
|
thread[:started_on] = Time.now
|
|
499
621
|
thread.priority=1
|
|
500
622
|
@workers.add(thread)
|
|
501
|
-
|
|
623
|
+
|
|
502
624
|
sleep @timeout/100 if @timeout > 0
|
|
503
625
|
end
|
|
504
626
|
rescue StopServer
|
|
505
|
-
STDERR.puts "Server stopped. Exiting."
|
|
506
627
|
@socket.close if not @socket.closed?
|
|
507
628
|
break
|
|
508
629
|
rescue Errno::EMFILE
|
|
@@ -511,13 +632,11 @@ module Mongrel
|
|
|
511
632
|
end
|
|
512
633
|
end
|
|
513
634
|
|
|
514
|
-
#
|
|
515
|
-
#
|
|
516
|
-
|
|
517
|
-
# finally we wait until the queue is empty (but only about 10 seconds)
|
|
635
|
+
# troll through the threads that are waiting and kill any that take too long
|
|
636
|
+
# TODO: Allow for death time to be set if people ask for it.
|
|
518
637
|
@death_time = 10
|
|
519
638
|
shutdown_start = Time.now
|
|
520
|
-
|
|
639
|
+
|
|
521
640
|
while @workers.list.length > 0
|
|
522
641
|
waited_for = (Time.now - shutdown_start).ceil
|
|
523
642
|
STDERR.print "Shutdown waited #{waited_for} for #{@workers.list.length} requests, could take #{@death_time + @timeout} seconds.\r" if @workers.list.length > 0
|
|
@@ -529,12 +648,13 @@ module Mongrel
|
|
|
529
648
|
return @acceptor
|
|
530
649
|
end
|
|
531
650
|
|
|
532
|
-
|
|
651
|
+
|
|
533
652
|
# Simply registers a handler with the internal URIClassifier. When the URI is
|
|
534
653
|
# found in the prefix of a request then your handler's HttpHandler::process method
|
|
535
654
|
# is called. See Mongrel::URIClassifier#register for more information.
|
|
536
655
|
#
|
|
537
656
|
# If you set in_front=true then the passed in handler will be put in front in the list.
|
|
657
|
+
# Otherwise it's placed at the end of the list.
|
|
538
658
|
def register(uri, handler, in_front=false)
|
|
539
659
|
script_name, path_info, handlers = @classifier.resolve(uri)
|
|
540
660
|
|
|
@@ -551,6 +671,8 @@ module Mongrel
|
|
|
551
671
|
@classifier.register(uri, [handler])
|
|
552
672
|
end
|
|
553
673
|
end
|
|
674
|
+
|
|
675
|
+
handler.listener = self
|
|
554
676
|
end
|
|
555
677
|
|
|
556
678
|
# Removes any handlers registered at the given URI. See Mongrel::URIClassifier#unregister
|
|
@@ -601,6 +723,8 @@ module Mongrel
|
|
|
601
723
|
# A major thing about Configurator is that it actually lets you configure
|
|
602
724
|
# multiple listeners for any hosts and ports you want. These are kept in a
|
|
603
725
|
# map config.listeners so you can get to them.
|
|
726
|
+
#
|
|
727
|
+
# * :pid_file => Where to write the process ID.
|
|
604
728
|
class Configurator
|
|
605
729
|
attr_reader :listeners
|
|
606
730
|
attr_reader :defaults
|
|
@@ -608,31 +732,68 @@ module Mongrel
|
|
|
608
732
|
|
|
609
733
|
# You pass in initial defaults and then a block to continue configuring.
|
|
610
734
|
def initialize(defaults={}, &blk)
|
|
735
|
+
@listener = nil
|
|
736
|
+
@listener_name = nil
|
|
611
737
|
@listeners = {}
|
|
612
738
|
@defaults = defaults
|
|
613
739
|
@needs_restart = false
|
|
740
|
+
@pid_file = defaults[:pid_file]
|
|
741
|
+
|
|
742
|
+
change_privilege(@defaults[:user], @defaults[:group])
|
|
614
743
|
|
|
615
744
|
if blk
|
|
616
745
|
cloaker(&blk).bind(self).call
|
|
617
746
|
end
|
|
618
747
|
end
|
|
619
748
|
|
|
749
|
+
# Change privilege of the process to specified user and group.
|
|
750
|
+
def change_privilege(user, group)
|
|
751
|
+
begin
|
|
752
|
+
if group
|
|
753
|
+
log "Changing group to #{group}."
|
|
754
|
+
Process::GID.change_privilege(Etc.getgrnam(group).gid)
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
if user
|
|
758
|
+
log "Changing user to #{user}."
|
|
759
|
+
Process::UID.change_privilege(Etc.getpwnam(user).uid)
|
|
760
|
+
end
|
|
761
|
+
rescue Errno::EPERM
|
|
762
|
+
log "FAILED to change user:group #{user}:#{group}: #$!"
|
|
763
|
+
exit 1
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# Writes the PID file but only if we're on windows.
|
|
768
|
+
def write_pid_file
|
|
769
|
+
if RUBY_PLATFORM !~ /mswin/
|
|
770
|
+
open(@pid_file,"w") {|f| f.write(Process.pid) }
|
|
771
|
+
end
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
# generates a class for cloaking the current self and making the DSL nicer
|
|
775
|
+
def cloaking_class
|
|
776
|
+
class << self
|
|
777
|
+
self
|
|
778
|
+
end
|
|
779
|
+
end
|
|
780
|
+
|
|
620
781
|
# Do not call this. You were warned.
|
|
621
|
-
def cloaker
|
|
622
|
-
|
|
782
|
+
def cloaker(&blk)
|
|
783
|
+
cloaking_class.class_eval do
|
|
623
784
|
define_method :cloaker_, &blk
|
|
624
785
|
meth = instance_method( :cloaker_ )
|
|
625
786
|
remove_method :cloaker_
|
|
626
787
|
meth
|
|
627
788
|
end
|
|
628
789
|
end
|
|
629
|
-
|
|
790
|
+
|
|
630
791
|
# This will resolve the given options against the defaults.
|
|
631
792
|
# Normally just used internally.
|
|
632
793
|
def resolve_defaults(options)
|
|
633
794
|
options.merge(@defaults)
|
|
634
795
|
end
|
|
635
|
-
|
|
796
|
+
|
|
636
797
|
# Starts a listener block. This is the only one that actually takes
|
|
637
798
|
# a block and then you make Configurator.uri calls in order to setup
|
|
638
799
|
# your URIs and handlers. If you write your Handlers as GemPlugins
|
|
@@ -643,9 +804,10 @@ module Mongrel
|
|
|
643
804
|
# * :host => Host name to bind.
|
|
644
805
|
# * :port => Port to bind.
|
|
645
806
|
# * :num_processors => The maximum number of concurrent threads allowed. (950 default)
|
|
646
|
-
# * :timeout => 1/100th of a second timeout between requests. (10 is 1/10th, 0 is
|
|
807
|
+
# * :timeout => 1/100th of a second timeout between requests. (10 is 1/10th, 0 is timeout)
|
|
647
808
|
#
|
|
648
809
|
def listener(options={},&blk)
|
|
810
|
+
raise "Cannot call listener inside another listener block." if (@listener or @listener_name)
|
|
649
811
|
ops = resolve_defaults(options)
|
|
650
812
|
ops[:num_processors] ||= 950
|
|
651
813
|
ops[:timeout] ||= 0
|
|
@@ -653,29 +815,31 @@ module Mongrel
|
|
|
653
815
|
@listener = Mongrel::HttpServer.new(ops[:host], ops[:port].to_i, ops[:num_processors].to_i, ops[:timeout].to_i)
|
|
654
816
|
@listener_name = "#{ops[:host]}:#{ops[:port]}"
|
|
655
817
|
@listeners[@listener_name] = @listener
|
|
656
|
-
|
|
818
|
+
|
|
819
|
+
# Does the actual cloaking operation to give the new implicit self.
|
|
657
820
|
if blk
|
|
658
821
|
cloaker(&blk).bind(self).call
|
|
659
822
|
end
|
|
660
|
-
|
|
661
|
-
# all done processing this listener setup
|
|
823
|
+
|
|
824
|
+
# all done processing this listener setup, reset implicit variables
|
|
662
825
|
@listener = nil
|
|
663
826
|
@listener_name = nil
|
|
664
827
|
end
|
|
665
|
-
|
|
666
|
-
|
|
828
|
+
|
|
829
|
+
|
|
667
830
|
# Called inside a Configurator.listener block in order to
|
|
668
831
|
# add URI->handler mappings for that listener. Use this as
|
|
669
832
|
# many times as you like. It expects the following options
|
|
670
833
|
# or defaults:
|
|
671
834
|
#
|
|
672
|
-
# * :handler => Handler to use for this location.
|
|
835
|
+
# * :handler => HttpHandler -- Handler to use for this location.
|
|
836
|
+
# * :in_front => true/false -- Rather than appending, it prepends this handler.
|
|
673
837
|
def uri(location, options={})
|
|
674
838
|
ops = resolve_defaults(options)
|
|
675
839
|
@listener.register(location, ops[:handler], in_front=ops[:in_front])
|
|
676
840
|
end
|
|
677
|
-
|
|
678
|
-
|
|
841
|
+
|
|
842
|
+
|
|
679
843
|
# Daemonizes the current Ruby script turning all the
|
|
680
844
|
# listeners into an actual "server" or detached process.
|
|
681
845
|
# You must call this *before* frameworks that open files
|
|
@@ -687,35 +851,33 @@ module Mongrel
|
|
|
687
851
|
#
|
|
688
852
|
# * :cwd => Directory to change to.
|
|
689
853
|
# * :log_file => Where to write STDOUT and STDERR.
|
|
690
|
-
# * :pid_file => Where to write the process ID.
|
|
691
854
|
#
|
|
692
|
-
# It is safe to call this on win32 as it will only require daemons
|
|
693
|
-
# if NOT win32.
|
|
855
|
+
# It is safe to call this on win32 as it will only require the daemons
|
|
856
|
+
# gem/library if NOT win32.
|
|
694
857
|
def daemonize(options={})
|
|
695
858
|
ops = resolve_defaults(options)
|
|
696
859
|
# save this for later since daemonize will hose it
|
|
697
860
|
if RUBY_PLATFORM !~ /mswin/
|
|
698
861
|
require 'daemons/daemonize'
|
|
699
|
-
|
|
862
|
+
|
|
700
863
|
Daemonize.daemonize(log_file=File.join(ops[:cwd], ops[:log_file]))
|
|
701
|
-
|
|
864
|
+
|
|
702
865
|
# change back to the original starting directory
|
|
703
866
|
Dir.chdir(ops[:cwd])
|
|
704
|
-
|
|
705
|
-
open(ops[:pid_file],"w") {|f| f.write(Process.pid) }
|
|
867
|
+
|
|
706
868
|
else
|
|
707
869
|
log "WARNING: Win32 does not support daemon mode."
|
|
708
870
|
end
|
|
709
871
|
end
|
|
710
|
-
|
|
711
|
-
|
|
872
|
+
|
|
873
|
+
|
|
712
874
|
# Uses the GemPlugin system to easily load plugins based on their
|
|
713
875
|
# gem dependencies. You pass in either an :includes => [] or
|
|
714
876
|
# :excludes => [] setting listing the names of plugins to include
|
|
715
|
-
# or exclude from the
|
|
877
|
+
# or exclude from the when determining the dependencies.
|
|
716
878
|
def load_plugins(options={})
|
|
717
879
|
ops = resolve_defaults(options)
|
|
718
|
-
|
|
880
|
+
|
|
719
881
|
load_settings = {}
|
|
720
882
|
if ops[:includes]
|
|
721
883
|
ops[:includes].each do |plugin|
|
|
@@ -731,14 +893,14 @@ module Mongrel
|
|
|
731
893
|
|
|
732
894
|
GemPlugin::Manager.instance.load(load_settings)
|
|
733
895
|
end
|
|
734
|
-
|
|
735
|
-
|
|
896
|
+
|
|
897
|
+
|
|
736
898
|
# Easy way to load a YAML file and apply default settings.
|
|
737
899
|
def load_yaml(file, default={})
|
|
738
900
|
default.merge(YAML.load_file(file))
|
|
739
901
|
end
|
|
740
|
-
|
|
741
|
-
|
|
902
|
+
|
|
903
|
+
|
|
742
904
|
# Loads the MIME map file and checks that it is correct
|
|
743
905
|
# on loading. This is commonly passed to Mongrel::DirHandler
|
|
744
906
|
# or any framework handler that uses DirHandler to serve files.
|
|
@@ -748,14 +910,14 @@ module Mongrel
|
|
|
748
910
|
def load_mime_map(file, mime={})
|
|
749
911
|
# configure any requested mime map
|
|
750
912
|
mime = load_yaml(file, mime)
|
|
751
|
-
|
|
913
|
+
|
|
752
914
|
# check all the mime types to make sure they are the right format
|
|
753
915
|
mime.each {|k,v| log "WARNING: MIME type #{k} must start with '.'" if k.index(".") != 0 }
|
|
754
|
-
|
|
916
|
+
|
|
755
917
|
return mime
|
|
756
918
|
end
|
|
757
|
-
|
|
758
|
-
|
|
919
|
+
|
|
920
|
+
|
|
759
921
|
# Loads and creates a plugin for you based on the given
|
|
760
922
|
# name and configured with the selected options. The options
|
|
761
923
|
# are merged with the defaults prior to passing them in.
|
|
@@ -763,26 +925,32 @@ module Mongrel
|
|
|
763
925
|
ops = resolve_defaults(options)
|
|
764
926
|
GemPlugin::Manager.instance.create(name, ops)
|
|
765
927
|
end
|
|
766
|
-
|
|
767
|
-
|
|
928
|
+
|
|
929
|
+
|
|
768
930
|
# Works like a meta run method which goes through all the
|
|
769
931
|
# configured listeners. Use the Configurator.join method
|
|
770
932
|
# to prevent Ruby from exiting until each one is done.
|
|
771
933
|
def run
|
|
772
934
|
@listeners.each {|name,s|
|
|
773
|
-
log "Running #{name} listener."
|
|
774
935
|
s.run
|
|
775
936
|
}
|
|
776
|
-
|
|
937
|
+
|
|
938
|
+
$mongrel_sleeper_thread = Thread.new { loop { sleep 1 } }
|
|
777
939
|
end
|
|
778
|
-
|
|
940
|
+
|
|
779
941
|
# Calls .stop on all the configured listeners so they
|
|
780
|
-
# stop processing requests (gracefully).
|
|
781
|
-
|
|
942
|
+
# stop processing requests (gracefully). By default it
|
|
943
|
+
# assumes that you don't want to restart and that the pid file
|
|
944
|
+
# should be unlinked on exit.
|
|
945
|
+
def stop(needs_restart=false, unlink_pid_file=true)
|
|
782
946
|
@listeners.each {|name,s|
|
|
783
|
-
log "Stopping #{name} listener."
|
|
784
947
|
s.stop
|
|
785
948
|
}
|
|
949
|
+
|
|
950
|
+
@needs_restart = needs_restart
|
|
951
|
+
if unlink_pid_file
|
|
952
|
+
File.unlink @pid_file if (@pid_file and File.exist?(@pid_file))
|
|
953
|
+
end
|
|
786
954
|
end
|
|
787
955
|
|
|
788
956
|
|
|
@@ -799,25 +967,32 @@ module Mongrel
|
|
|
799
967
|
# parameters for each request. This helps you track common problems
|
|
800
968
|
# found in Rails applications that are either slow or become unresponsive
|
|
801
969
|
# after a little while.
|
|
802
|
-
|
|
970
|
+
#
|
|
971
|
+
# TODO: Document the optional selections from the what parameter
|
|
972
|
+
def debug(location, what = [:object, :rails, :files, :threads, :params])
|
|
803
973
|
require 'mongrel/debug'
|
|
804
|
-
|
|
974
|
+
handlers = {
|
|
975
|
+
:object => "/handlers/requestlog::access",
|
|
976
|
+
:rails => "/handlers/requestlog::files",
|
|
977
|
+
:files => "/handlers/requestlog::objects",
|
|
978
|
+
:threads => "/handlers/requestlog::threads",
|
|
979
|
+
:params => "/handlers/requestlog::params"
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
# turn on the debugging infrastructure, and ObjectTracker is a pig
|
|
983
|
+
ObjectTracker.configure if what.include? :object
|
|
805
984
|
MongrelDbg.configure
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
uri location, :handler => plugin("/handlers/requestlog::files")
|
|
813
|
-
uri location, :handler => plugin("/handlers/requestlog::objects")
|
|
814
|
-
uri location, :handler => plugin("/handlers/requestlog::params")
|
|
815
|
-
uri location, :handler => plugin("/handlers/requestlog::threads")
|
|
985
|
+
|
|
986
|
+
# now we roll through each requested debug type, turn it on and load that plugin
|
|
987
|
+
what.each do |type|
|
|
988
|
+
MongrelDbg.begin_trace type
|
|
989
|
+
uri location, :handler => plugin(handlers[type])
|
|
990
|
+
end
|
|
816
991
|
end
|
|
817
992
|
|
|
818
993
|
# Used to allow you to let users specify their own configurations
|
|
819
994
|
# inside your Configurator setup. You pass it a script name and
|
|
820
|
-
# reads it in and does an eval on the contents passing in the right
|
|
995
|
+
# it reads it in and does an eval on the contents passing in the right
|
|
821
996
|
# binding so they can put their own Configurator statements.
|
|
822
997
|
def run_config(script)
|
|
823
998
|
open(script) {|f| eval(f.read, proc {self}) }
|
|
@@ -827,7 +1002,7 @@ module Mongrel
|
|
|
827
1002
|
# It only configures if the platform is not win32 and doesn't do
|
|
828
1003
|
# a HUP signal since this is typically framework specific.
|
|
829
1004
|
#
|
|
830
|
-
# Requires a :pid_file option to indicate a file to delete.
|
|
1005
|
+
# Requires a :pid_file option given to Configurator.new to indicate a file to delete.
|
|
831
1006
|
# It sets the MongrelConfig.needs_restart attribute if
|
|
832
1007
|
# the start command should reload. It's up to you to detect this
|
|
833
1008
|
# and do whatever is needed for a "restart".
|
|
@@ -835,33 +1010,20 @@ module Mongrel
|
|
|
835
1010
|
# This command is safely ignored if the platform is win32 (with a warning)
|
|
836
1011
|
def setup_signals(options={})
|
|
837
1012
|
ops = resolve_defaults(options)
|
|
838
|
-
|
|
1013
|
+
|
|
1014
|
+
# forced shutdown, even if previously restarted (actually just like TERM but for CTRL-C)
|
|
1015
|
+
trap("INT") { log "INT signal received."; stop(need_restart=false) }
|
|
1016
|
+
|
|
839
1017
|
if RUBY_PLATFORM !~ /mswin/
|
|
840
1018
|
# graceful shutdown
|
|
841
|
-
trap("TERM") {
|
|
842
|
-
|
|
843
|
-
stop
|
|
844
|
-
File.unlink ops[:pid_file] if File.exist?(ops[:pid_file])
|
|
845
|
-
}
|
|
846
|
-
|
|
1019
|
+
trap("TERM") { log "TERM signal received."; stop }
|
|
1020
|
+
|
|
847
1021
|
# restart
|
|
848
|
-
trap("USR2") {
|
|
849
|
-
|
|
850
|
-
stop
|
|
851
|
-
File.unlink ops[:pid_file] if File.exist?(ops[:pid_file])
|
|
852
|
-
@needs_restart = true
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
trap("INT") {
|
|
856
|
-
log "INT signal received."
|
|
857
|
-
stop
|
|
858
|
-
File.unlink ops[:pid_file] if File.exist?(ops[:pid_file])
|
|
859
|
-
@needs_restart = false
|
|
860
|
-
}
|
|
861
|
-
|
|
1022
|
+
trap("USR2") { log "USR2 signal received."; stop(need_restart=true) }
|
|
1023
|
+
|
|
862
1024
|
log "Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart)."
|
|
863
1025
|
else
|
|
864
|
-
log "
|
|
1026
|
+
log "Signals ready. INT => stop (no restart)."
|
|
865
1027
|
end
|
|
866
1028
|
end
|
|
867
1029
|
|
|
@@ -869,7 +1031,6 @@ module Mongrel
|
|
|
869
1031
|
def log(msg)
|
|
870
1032
|
STDERR.print "** ", msg, "\n"
|
|
871
1033
|
end
|
|
872
|
-
|
|
873
|
-
end
|
|
874
1034
|
|
|
1035
|
+
end
|
|
875
1036
|
end
|