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/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
|