mongrel 0.3.13.3 → 0.3.13.4
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 +5 -4
- data/bin/mongrel_rails +162 -169
- data/doc/rdoc/classes/IO.src/M000001.html +5 -5
- data/doc/rdoc/classes/IO.src/M000002.html +5 -5
- data/doc/rdoc/classes/Kernel.html +10 -10
- data/doc/rdoc/classes/Kernel.src/M000010.html +19 -0
- data/doc/rdoc/classes/Kernel.src/M000011.html +23 -0
- data/doc/rdoc/classes/Mongrel.html +27 -10
- data/doc/rdoc/classes/Mongrel/CGIWrapper.html +67 -54
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000101.html → M000112.html} +11 -10
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000102.html → M000113.html} +31 -31
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000103.html → M000114.html} +20 -20
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000115.html +32 -0
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000105.html → M000116.html} +11 -11
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000106.html → M000117.html} +4 -4
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000107.html → M000118.html} +4 -4
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000108.html → M000119.html} +4 -4
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000109.html → M000120.html} +5 -5
- data/doc/rdoc/classes/Mongrel/Camping.html +5 -5
- data/doc/rdoc/classes/Mongrel/Camping.src/{M000048.html → M000039.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.html +10 -10
- data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.src/{M000049.html → M000040.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.src/{M000050.html → M000041.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.html +65 -65
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000016.html +24 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000017.html +42 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000018.html +18 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000029.html → M000019.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000030.html → M000020.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000031.html → M000021.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000032.html → M000022.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000033.html → M000023.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000034.html → M000024.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000035.html → M000025.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000026.html +11 -11
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000027.html +11 -29
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000028.html +5 -5
- data/doc/rdoc/classes/Mongrel/Command/Registry.html +15 -15
- data/doc/rdoc/classes/Mongrel/Command/Registry.src/{M000039.html → M000029.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Command/Registry.src/{M000040.html → M000030.html} +10 -6
- data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000031.html +58 -0
- data/doc/rdoc/classes/Mongrel/Configurator.html +115 -115
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000091.html +27 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000092.html +31 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000093.html +21 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000094.html +20 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000095.html +23 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000115.html → M000096.html} +4 -4
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000116.html → M000097.html} +24 -24
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000117.html → M000098.html} +5 -5
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000099.html +39 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000119.html → M000100.html} +19 -19
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000120.html → M000101.html} +4 -4
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000121.html → M000102.html} +10 -10
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000122.html → M000103.html} +5 -5
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000123.html → M000104.html} +4 -4
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000124.html → M000105.html} +8 -8
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000106.html +22 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/{M000126.html → M000107.html} +4 -4
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000108.html +34 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000109.html +18 -0
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000110.html +23 -14
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000111.html +5 -18
- data/doc/rdoc/classes/Mongrel/Const.html +11 -6
- data/doc/rdoc/classes/Mongrel/DeflateFilter.html +10 -10
- data/doc/rdoc/classes/Mongrel/DeflateFilter.src/{M000099.html → M000121.html} +5 -5
- data/doc/rdoc/classes/Mongrel/DeflateFilter.src/{M000100.html → M000122.html} +14 -14
- data/doc/rdoc/classes/Mongrel/DirHandler.html +31 -31
- data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000058.html → M000049.html} +0 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000059.html → M000050.html} +0 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000060.html → M000051.html} +12 -16
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000052.html +63 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000062.html → M000053.html} +25 -25
- data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000063.html → M000054.html} +4 -4
- data/doc/rdoc/classes/Mongrel/Error404Handler.html +10 -10
- data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000131.html → M000123.html} +0 -0
- data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000132.html → M000124.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HeaderOut.html +10 -10
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000072.html → M000064.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000073.html → M000065.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HttpHandler.html +15 -15
- data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000078.html → M000070.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000079.html → M000071.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000080.html → M000072.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.html +20 -20
- data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000022.html → M000012.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000023.html → M000013.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000024.html → M000014.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000025.html → M000015.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParams.html +131 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.html +35 -35
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000051.html → M000042.html} +1 -1
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000052.html → M000043.html} +1 -1
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000053.html → M000044.html} +1 -1
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000054.html → M000045.html} +3 -3
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000055.html → M000046.html} +1 -1
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000056.html → M000047.html} +1 -1
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000057.html → M000048.html} +1 -1
- data/doc/rdoc/classes/Mongrel/HttpRequest.html +63 -24
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000130.html +47 -0
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000131.html +37 -0
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000132.html +29 -0
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000139.html → M000133.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000140.html → M000134.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000141.html → M000135.html} +18 -18
- data/doc/rdoc/classes/Mongrel/HttpResponse.html +66 -72
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000073.html +25 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000074.html +20 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000075.html +26 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000076.html +22 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000085.html → M000077.html} +8 -8
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000086.html → M000078.html} +8 -8
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000079.html +31 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000088.html → M000080.html} +7 -7
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000081.html +7 -12
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000082.html +7 -7
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000083.html +7 -12
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000084.html +5 -9
- data/doc/rdoc/classes/Mongrel/HttpServer.html +58 -43
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000064.html → M000055.html} +11 -11
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000065.html → M000056.html} +76 -72
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000066.html → M000057.html} +18 -17
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000067.html → M000058.html} +7 -7
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000059.html +22 -0
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000060.html +62 -0
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000069.html → M000061.html} +20 -20
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000070.html → M000062.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000071.html → M000063.html} +8 -8
- data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.html +15 -15
- data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/{M000042.html → M000032.html} +23 -25
- data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/{M000043.html → M000033.html} +11 -11
- data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/{M000044.html → M000034.html} +12 -12
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.html +30 -15
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/{M000045.html → M000035.html} +9 -8
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000036.html +54 -0
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000037.html +21 -0
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000038.html +25 -0
- data/doc/rdoc/classes/Mongrel/RedirectHandler.html +10 -10
- data/doc/rdoc/classes/Mongrel/RedirectHandler.src/{M000136.html → M000128.html} +8 -8
- data/doc/rdoc/classes/Mongrel/RedirectHandler.src/{M000137.html → M000129.html} +13 -13
- data/doc/rdoc/classes/Mongrel/StatisticsFilter.html +16 -16
- data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/M000125.html +24 -0
- data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/{M000134.html → M000126.html} +10 -10
- data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/{M000135.html → M000127.html} +4 -4
- data/doc/rdoc/classes/{Stats.html → Mongrel/Stats.html} +44 -60
- data/doc/rdoc/classes/Mongrel/Stats.src/M000136.html +19 -0
- data/doc/rdoc/classes/Mongrel/Stats.src/M000137.html +23 -0
- data/doc/rdoc/classes/Mongrel/Stats.src/M000138.html +26 -0
- data/doc/rdoc/classes/Mongrel/Stats.src/M000139.html +18 -0
- data/doc/rdoc/classes/{Stats.src/M000009.html → Mongrel/Stats.src/M000140.html} +6 -6
- data/doc/rdoc/classes/Mongrel/Stats.src/M000141.html +18 -0
- data/doc/rdoc/classes/Mongrel/Stats.src/M000142.html +23 -0
- data/doc/rdoc/classes/Mongrel/Stats.src/M000143.html +20 -0
- data/doc/rdoc/classes/Mongrel/StatusHandler.html +20 -20
- data/doc/rdoc/classes/Mongrel/StatusHandler.src/{M000074.html → M000066.html} +4 -4
- data/doc/rdoc/classes/Mongrel/StatusHandler.src/{M000075.html → M000067.html} +10 -10
- data/doc/rdoc/classes/Mongrel/StatusHandler.src/{M000076.html → M000068.html} +28 -28
- data/doc/rdoc/classes/Mongrel/StatusHandler.src/{M000077.html → M000069.html} +6 -6
- data/doc/rdoc/classes/Mongrel/URIClassifier.html +30 -30
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000093.html → M000085.html} +4 -4
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000094.html → M000086.html} +4 -4
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000095.html → M000087.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000096.html → M000088.html} +1 -1
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000097.html → M000089.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000098.html → M000090.html} +1 -1
- data/doc/rdoc/classes/MongrelDbg.html +26 -26
- data/doc/rdoc/classes/MongrelDbg.src/M000005.html +24 -0
- data/doc/rdoc/classes/MongrelDbg.src/{M000016.html → M000006.html} +6 -6
- data/doc/rdoc/classes/MongrelDbg.src/{M000017.html → M000007.html} +8 -8
- data/doc/rdoc/classes/MongrelDbg.src/{M000018.html → M000008.html} +7 -7
- data/doc/rdoc/classes/MongrelDbg.src/{M000019.html → M000009.html} +4 -4
- data/doc/rdoc/classes/RequestLog/Access.html +5 -5
- data/doc/rdoc/classes/RequestLog/Access.src/{M000142.html → M000144.html} +5 -5
- data/doc/rdoc/classes/RequestLog/Files.html +5 -5
- data/doc/rdoc/classes/RequestLog/Files.src/{M000143.html → M000145.html} +5 -5
- data/doc/rdoc/classes/RequestLog/Objects.html +12 -6
- data/doc/rdoc/classes/RequestLog/Objects.src/M000147.html +51 -0
- data/doc/rdoc/classes/RequestLog/Params.html +5 -5
- data/doc/rdoc/classes/RequestLog/Params.src/{M000146.html → M000148.html} +5 -5
- data/doc/rdoc/classes/RequestLog/Threads.html +5 -5
- data/doc/rdoc/classes/RequestLog/Threads.src/{M000144.html → M000146.html} +20 -20
- data/doc/rdoc/classes/{ObjectTracker.html → Sync.html} +26 -45
- 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 +1 -1
- data/doc/rdoc/files/lib/mongrel/cgi_rb.html +1 -1
- data/doc/rdoc/files/lib/mongrel/command_rb.html +1 -1
- data/doc/rdoc/files/lib/mongrel/configurator_rb.html +111 -0
- data/doc/rdoc/files/lib/mongrel/debug_rb.html +1 -1
- data/doc/rdoc/files/lib/mongrel/handlers_rb.html +1 -1
- data/doc/rdoc/files/lib/mongrel/init_rb.html +1 -1
- data/doc/rdoc/files/lib/mongrel/rails_rb.html +2 -1
- data/doc/rdoc/files/lib/mongrel/stats_rb.html +1 -1
- data/doc/rdoc/files/lib/mongrel/tcphack_rb.html +1 -1
- data/doc/rdoc/files/lib/mongrel_rb.html +2 -4
- data/doc/rdoc/fr_class_index.html +3 -2
- data/doc/rdoc/fr_file_index.html +1 -0
- data/doc/rdoc/fr_method_index.html +144 -142
- data/ext/http11/http11.c +69 -52
- data/ext/http11/http11_parser.c +366 -282
- data/ext/http11/http11_parser.h +2 -0
- data/ext/http11/http11_parser.rl +192 -0
- data/lib/mongrel.rb +127 -433
- data/lib/mongrel/cgi.rb +19 -6
- data/lib/mongrel/command.rb +15 -3
- data/lib/mongrel/configurator.rb +374 -0
- data/lib/mongrel/debug.rb +47 -56
- data/lib/mongrel/handlers.rb +16 -20
- data/lib/mongrel/rails.rb +36 -20
- data/lib/mongrel/stats.rb +60 -58
- data/test/test_conditional.rb +37 -30
- data/test/test_http11.rb +14 -14
- data/test/test_stats.rb +2 -2
- data/test/test_ws.rb +4 -2
- data/tools/rakehelp.rb +4 -4
- metadata +262 -260
- data/doc/rdoc/classes/Kernel.src/M000020.html +0 -19
- data/doc/rdoc/classes/Kernel.src/M000021.html +0 -23
- data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000104.html +0 -27
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000036.html +0 -24
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000037.html +0 -24
- data/doc/rdoc/classes/Mongrel/Command/Base.src/M000038.html +0 -18
- data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000041.html +0 -50
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000112.html +0 -20
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000113.html +0 -20
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000114.html +0 -23
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000118.html +0 -30
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000125.html +0 -25
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000127.html +0 -35
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000128.html +0 -18
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000129.html +0 -33
- data/doc/rdoc/classes/Mongrel/Configurator.src/M000130.html +0 -18
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000061.html +0 -63
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000138.html +0 -56
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000087.html +0 -31
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000089.html +0 -20
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000090.html +0 -20
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000091.html +0 -20
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000092.html +0 -18
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000068.html +0 -50
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000046.html +0 -51
- data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000047.html +0 -23
- data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/M000133.html +0 -24
- data/doc/rdoc/classes/MongrelDbg.src/M000015.html +0 -19
- data/doc/rdoc/classes/ObjectTracker.src/M000013.html +0 -27
- data/doc/rdoc/classes/ObjectTracker.src/M000014.html +0 -44
- data/doc/rdoc/classes/RequestLog/Objects.src/M000145.html +0 -19
- data/doc/rdoc/classes/Stats.src/M000005.html +0 -19
- data/doc/rdoc/classes/Stats.src/M000006.html +0 -23
- data/doc/rdoc/classes/Stats.src/M000007.html +0 -26
- data/doc/rdoc/classes/Stats.src/M000008.html +0 -18
- data/doc/rdoc/classes/Stats.src/M000010.html +0 -18
- data/doc/rdoc/classes/Stats.src/M000011.html +0 -23
- data/doc/rdoc/classes/Stats.src/M000012.html +0 -20
- data/lib/http11.so +0 -0
data/ext/http11/http11_parser.h
CHANGED
|
@@ -23,12 +23,14 @@ typedef struct http_parser {
|
|
|
23
23
|
size_t mark;
|
|
24
24
|
size_t field_start;
|
|
25
25
|
size_t field_len;
|
|
26
|
+
size_t query_start;
|
|
26
27
|
|
|
27
28
|
void *data;
|
|
28
29
|
|
|
29
30
|
field_cb http_field;
|
|
30
31
|
element_cb request_method;
|
|
31
32
|
element_cb request_uri;
|
|
33
|
+
element_cb request_path;
|
|
32
34
|
element_cb query_string;
|
|
33
35
|
element_cb http_version;
|
|
34
36
|
element_cb header_done;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2005 Zed A. Shaw
|
|
3
|
+
* You can redistribute it and/or modify it under the same terms as Ruby.
|
|
4
|
+
*/
|
|
5
|
+
#include "http11_parser.h"
|
|
6
|
+
#include <stdio.h>
|
|
7
|
+
#include <assert.h>
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <ctype.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
|
|
12
|
+
#define LEN(AT, FPC) (FPC - buffer - parser->AT)
|
|
13
|
+
#define MARK(M,FPC) (parser->M = (FPC) - buffer)
|
|
14
|
+
#define PTR_TO(F) (buffer + parser->F)
|
|
15
|
+
|
|
16
|
+
/** machine **/
|
|
17
|
+
%%{
|
|
18
|
+
machine http_parser;
|
|
19
|
+
|
|
20
|
+
action mark {MARK(mark, fpc); }
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
action start_field { MARK(field_start, fpc); }
|
|
24
|
+
action write_field {
|
|
25
|
+
parser->field_len = LEN(field_start, fpc);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
action start_value { MARK(mark, fpc); }
|
|
29
|
+
action write_value {
|
|
30
|
+
if(parser->http_field != NULL) {
|
|
31
|
+
parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
action request_method {
|
|
35
|
+
if(parser->request_method != NULL)
|
|
36
|
+
parser->request_method(parser->data, PTR_TO(mark), LEN(mark, fpc));
|
|
37
|
+
}
|
|
38
|
+
action request_uri {
|
|
39
|
+
if(parser->request_uri != NULL)
|
|
40
|
+
parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, fpc));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
action start_query {MARK(query_start, fpc); }
|
|
44
|
+
action query_string {
|
|
45
|
+
if(parser->query_string != NULL)
|
|
46
|
+
parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, fpc));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
action http_version {
|
|
50
|
+
if(parser->http_version != NULL)
|
|
51
|
+
parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
action request_path {
|
|
55
|
+
if(parser->request_path != NULL)
|
|
56
|
+
parser->request_path(parser->data, PTR_TO(mark), LEN(mark,fpc));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
action done {
|
|
60
|
+
parser->body_start = fpc - buffer + 1;
|
|
61
|
+
if(parser->header_done != NULL)
|
|
62
|
+
parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
|
|
63
|
+
fbreak;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
#### HTTP PROTOCOL GRAMMAR
|
|
68
|
+
# line endings
|
|
69
|
+
CRLF = "\r\n";
|
|
70
|
+
|
|
71
|
+
# character types
|
|
72
|
+
CTL = (cntrl | 127);
|
|
73
|
+
safe = ("$" | "-" | "_" | ".");
|
|
74
|
+
extra = ("!" | "*" | "'" | "(" | ")" | ",");
|
|
75
|
+
reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+");
|
|
76
|
+
unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">");
|
|
77
|
+
national = any -- (alpha | digit | reserved | extra | safe | unsafe);
|
|
78
|
+
unreserved = (alpha | digit | safe | extra | national);
|
|
79
|
+
escape = ("%" xdigit xdigit);
|
|
80
|
+
uchar = (unreserved | escape);
|
|
81
|
+
pchar = (uchar | ":" | "@" | "&" | "=" | "+");
|
|
82
|
+
tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
|
|
83
|
+
|
|
84
|
+
# elements
|
|
85
|
+
token = (ascii -- (CTL | tspecials));
|
|
86
|
+
|
|
87
|
+
# URI schemes and absolute paths
|
|
88
|
+
scheme = ( alpha | digit | "+" | "-" | "." )* ;
|
|
89
|
+
absolute_uri = (scheme ":" (uchar | reserved )*);
|
|
90
|
+
|
|
91
|
+
path = (pchar+ ( "/" pchar* )*) ;
|
|
92
|
+
query = ( uchar | reserved )* %query_string ;
|
|
93
|
+
param = ( pchar | "/" )* ;
|
|
94
|
+
params = (param ( ";" param )*) ;
|
|
95
|
+
rel_path = (path? %request_path (";" params)?) ("?" %start_query query)?;
|
|
96
|
+
absolute_path = ("/"+ rel_path);
|
|
97
|
+
|
|
98
|
+
Request_URI = ("*" | absolute_uri | absolute_path) >mark %request_uri;
|
|
99
|
+
Method = (upper | digit | safe){1,20} >mark %request_method;
|
|
100
|
+
|
|
101
|
+
http_number = (digit+ "." digit+) ;
|
|
102
|
+
HTTP_Version = ("HTTP/" http_number) >mark %http_version ;
|
|
103
|
+
Request_Line = (Method " " Request_URI " " HTTP_Version CRLF) ;
|
|
104
|
+
|
|
105
|
+
field_name = (token -- ":")+ >start_field %write_field;
|
|
106
|
+
|
|
107
|
+
field_value = any* >start_value %write_value;
|
|
108
|
+
|
|
109
|
+
message_header = field_name ":" " "* field_value :> CRLF;
|
|
110
|
+
|
|
111
|
+
Request = Request_Line (message_header)* ( CRLF @done);
|
|
112
|
+
|
|
113
|
+
main := Request;
|
|
114
|
+
}%%
|
|
115
|
+
|
|
116
|
+
/** Data **/
|
|
117
|
+
%% write data;
|
|
118
|
+
|
|
119
|
+
int http_parser_init(http_parser *parser) {
|
|
120
|
+
int cs = 0;
|
|
121
|
+
%% write init;
|
|
122
|
+
parser->cs = cs;
|
|
123
|
+
parser->body_start = 0;
|
|
124
|
+
parser->content_len = 0;
|
|
125
|
+
parser->mark = 0;
|
|
126
|
+
parser->nread = 0;
|
|
127
|
+
parser->field_len = 0;
|
|
128
|
+
parser->field_start = 0;
|
|
129
|
+
|
|
130
|
+
return(1);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
/** exec **/
|
|
135
|
+
size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
|
|
136
|
+
const char *p, *pe;
|
|
137
|
+
int cs = parser->cs;
|
|
138
|
+
|
|
139
|
+
assert(off <= len && "offset past end of buffer");
|
|
140
|
+
|
|
141
|
+
p = buffer+off;
|
|
142
|
+
pe = buffer+len;
|
|
143
|
+
|
|
144
|
+
assert(*pe == '\0' && "pointer does not end on NUL");
|
|
145
|
+
assert(pe - p == len - off && "pointers aren't same distance");
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
%% write exec;
|
|
149
|
+
|
|
150
|
+
parser->cs = cs;
|
|
151
|
+
parser->nread += p - (buffer + off);
|
|
152
|
+
|
|
153
|
+
assert(p <= pe && "buffer overflow after parsing execute");
|
|
154
|
+
assert(parser->nread <= len && "nread longer than length");
|
|
155
|
+
assert(parser->body_start <= len && "body starts after buffer end");
|
|
156
|
+
assert(parser->mark < len && "mark is after buffer end");
|
|
157
|
+
assert(parser->field_len <= len && "field has length longer than whole buffer");
|
|
158
|
+
assert(parser->field_start < len && "field starts after buffer end");
|
|
159
|
+
|
|
160
|
+
if(parser->body_start) {
|
|
161
|
+
/* final \r\n combo encountered so stop right here */
|
|
162
|
+
%%write eof;
|
|
163
|
+
parser->nread++;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return(parser->nread);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
int http_parser_finish(http_parser *parser)
|
|
170
|
+
{
|
|
171
|
+
int cs = parser->cs;
|
|
172
|
+
|
|
173
|
+
%%write eof;
|
|
174
|
+
|
|
175
|
+
parser->cs = cs;
|
|
176
|
+
|
|
177
|
+
if (http_parser_has_error(parser) ) {
|
|
178
|
+
return -1;
|
|
179
|
+
} else if (http_parser_is_finished(parser) ) {
|
|
180
|
+
return 1;
|
|
181
|
+
} else {
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
int http_parser_has_error(http_parser *parser) {
|
|
187
|
+
return parser->cs == http_parser_error;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
int http_parser_is_finished(http_parser *parser) {
|
|
191
|
+
return parser->cs == http_parser_first_final;
|
|
192
|
+
}
|
data/lib/mongrel.rb
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
|
|
5
5
|
# for more information.
|
|
6
6
|
|
|
7
|
+
$mongrel_debug_client = false
|
|
8
|
+
|
|
7
9
|
require 'socket'
|
|
8
10
|
require 'http11'
|
|
9
11
|
require 'tempfile'
|
|
@@ -14,17 +16,11 @@ require 'mongrel/handlers'
|
|
|
14
16
|
require 'mongrel/command'
|
|
15
17
|
require 'mongrel/tcphack'
|
|
16
18
|
require 'yaml'
|
|
19
|
+
require 'mongrel/configurator'
|
|
17
20
|
require 'time'
|
|
18
21
|
require 'rubygems'
|
|
19
22
|
require 'etc'
|
|
20
23
|
|
|
21
|
-
begin
|
|
22
|
-
require 'sendfile'
|
|
23
|
-
STDERR.puts "** You have sendfile installed, will use that to serve files."
|
|
24
|
-
rescue Object
|
|
25
|
-
# do nothing
|
|
26
|
-
end
|
|
27
|
-
|
|
28
24
|
|
|
29
25
|
# Mongrel module containing all of the classes (include C extensions) for running
|
|
30
26
|
# a Mongrel web server. It contains a minimalist HTTP server with just enough
|
|
@@ -33,7 +29,7 @@ module Mongrel
|
|
|
33
29
|
|
|
34
30
|
class URIClassifier
|
|
35
31
|
attr_reader :handler_map
|
|
36
|
-
|
|
32
|
+
|
|
37
33
|
# Returns the URIs that have been registered with this classifier so far.
|
|
38
34
|
# The URIs returned should not be modified as this will cause a memory leak.
|
|
39
35
|
# You can use this to inspect the contents of the URIClassifier.
|
|
@@ -119,14 +115,15 @@ module Mongrel
|
|
|
119
115
|
|
|
120
116
|
# The original URI requested by the client. Passed to URIClassifier to build PATH_INFO and SCRIPT_NAME.
|
|
121
117
|
REQUEST_URI='REQUEST_URI'.freeze
|
|
118
|
+
REQUEST_PATH='REQUEST_PATH'.freeze
|
|
122
119
|
|
|
123
|
-
MONGREL_VERSION="0.3.13.
|
|
120
|
+
MONGREL_VERSION="0.3.13.4".freeze
|
|
124
121
|
|
|
125
122
|
# TODO: this use of a base for tempfiles needs to be looked at for security problems
|
|
126
123
|
MONGREL_TMP_BASE="mongrel".freeze
|
|
127
124
|
|
|
128
125
|
# The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
|
|
129
|
-
ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: #{MONGREL_VERSION}\r\n\r\nNOT FOUND".freeze
|
|
126
|
+
ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Mongrel #{MONGREL_VERSION}\r\n\r\nNOT FOUND".freeze
|
|
130
127
|
|
|
131
128
|
CONTENT_LENGTH="CONTENT_LENGTH".freeze
|
|
132
129
|
|
|
@@ -134,7 +131,7 @@ module Mongrel
|
|
|
134
131
|
ERROR_503_RESPONSE="HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze
|
|
135
132
|
|
|
136
133
|
# The basic max request size we'll try to read.
|
|
137
|
-
CHUNK_SIZE=(
|
|
134
|
+
CHUNK_SIZE=(16 * 1024)
|
|
138
135
|
|
|
139
136
|
# This is the maximum header that is allowed before a client is booted. The parser detects
|
|
140
137
|
# this, but we'd also like to do this as well.
|
|
@@ -144,7 +141,7 @@ module Mongrel
|
|
|
144
141
|
MAX_BODY=MAX_HEADER
|
|
145
142
|
|
|
146
143
|
# A frozen format for this is about 15% faster
|
|
147
|
-
STATUS_FORMAT = "HTTP/1.1 %d %s\r\
|
|
144
|
+
STATUS_FORMAT = "HTTP/1.1 %d %s\r\nConnection: close\r\n".freeze
|
|
148
145
|
CONTENT_TYPE = "Content-Type".freeze
|
|
149
146
|
LAST_MODIFIED = "Last-Modified".freeze
|
|
150
147
|
ETAG = "ETag".freeze
|
|
@@ -158,11 +155,15 @@ module Mongrel
|
|
|
158
155
|
LINE_END="\r\n".freeze
|
|
159
156
|
REMOTE_ADDR="REMOTE_ADDR".freeze
|
|
160
157
|
HTTP_X_FORWARDED_FOR="HTTP_X_FORWARDED_FOR".freeze
|
|
161
|
-
|
|
158
|
+
HTTP_IF_MODIFIED_SINCE="HTTP_IF_MODIFIED_SINCE".freeze
|
|
162
159
|
HTTP_IF_NONE_MATCH="HTTP_IF_NONE_MATCH".freeze
|
|
163
160
|
REDIRECT = "HTTP/1.1 302 Found\r\nLocation: %s\r\nConnection: close\r\n\r\n".freeze
|
|
164
161
|
end
|
|
165
162
|
|
|
163
|
+
# Basically a Hash with one extra parameter for the HTTP body, mostly used internally.
|
|
164
|
+
class HttpParams < Hash
|
|
165
|
+
attr_accessor :http_body
|
|
166
|
+
end
|
|
166
167
|
|
|
167
168
|
# When a handler is found for a registered URI then this class is constructed
|
|
168
169
|
# and passed to your HttpHandler::process method. You should assume that
|
|
@@ -186,48 +187,82 @@ module Mongrel
|
|
|
186
187
|
# body data into the HttpRequest.body attribute.
|
|
187
188
|
#
|
|
188
189
|
# TODO: Implement tempfile removal when the request is done.
|
|
189
|
-
def initialize(params,
|
|
190
|
+
def initialize(params, socket, dispatcher)
|
|
190
191
|
@params = params
|
|
191
192
|
@socket = socket
|
|
193
|
+
content_length = params[Const::CONTENT_LENGTH].to_i
|
|
194
|
+
remain = content_length - params.http_body.length
|
|
195
|
+
|
|
192
196
|
|
|
193
|
-
|
|
194
|
-
total = clen
|
|
197
|
+
dispatcher.request_begins(params) if dispatcher
|
|
195
198
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
else
|
|
199
|
+
# Some clients (like FF1.0) report 0 for body and then send a body. This will probably truncate them but at least the request goes through usually.
|
|
200
|
+
if remain <= 0
|
|
201
|
+
# we've got everything, pack it up
|
|
200
202
|
@body = StringIO.new
|
|
203
|
+
@body.write params.http_body
|
|
204
|
+
dispatcher.request_progress(params, 0, content_length) if dispatcher
|
|
205
|
+
elsif remain > 0
|
|
206
|
+
# must read more data to complete body
|
|
207
|
+
if remain > Const::MAX_BODY
|
|
208
|
+
# huge body, put it in a tempfile
|
|
209
|
+
@body = Tempfile.new(Const::MONGREL_TMP_BASE)
|
|
210
|
+
@body.binmode
|
|
211
|
+
else
|
|
212
|
+
# small body, just use that
|
|
213
|
+
@body = StringIO.new
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
@body.write params.http_body
|
|
217
|
+
read_body(remain, content_length, dispatcher)
|
|
201
218
|
end
|
|
202
219
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
220
|
+
@body.rewind if body
|
|
221
|
+
end
|
|
222
|
+
|
|
206
223
|
|
|
224
|
+
# Does the heavy lifting of properly reading the larger body requests in
|
|
225
|
+
# small chunks. It expects @body to be an IO object, @socket to be valid,
|
|
226
|
+
# and will set @body = nil if the request fails. It also expects any initial
|
|
227
|
+
# part of the body that has been read to be in the @body already.
|
|
228
|
+
def read_body(remain, total, dispatcher)
|
|
229
|
+
begin
|
|
207
230
|
# write the odd sized chunk first
|
|
208
|
-
|
|
209
|
-
|
|
231
|
+
|
|
232
|
+
remain -= @body.write(read_socket(remain % Const::CHUNK_SIZE))
|
|
233
|
+
dispatcher.request_progress(params, remain, total) if dispatcher
|
|
210
234
|
|
|
211
235
|
# then stream out nothing but perfectly sized chunks
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
# have to do it this way since @socket.eof? causes it to block
|
|
215
|
-
raise "Socket closed or read failure" if not data or data.length != Const::CHUNK_SIZE
|
|
216
|
-
clen -= @body.write(data)
|
|
236
|
+
until remain <= 0 or @socket.closed?
|
|
237
|
+
remain -= @body.write(read_socket(Const::CHUNK_SIZE))
|
|
217
238
|
# ASSUME: we are writing to a disk and these writes always write the requested amount
|
|
218
|
-
|
|
239
|
+
dispatcher.request_progress(params, remain, total) if dispatcher
|
|
219
240
|
end
|
|
220
|
-
|
|
221
|
-
# rewind to keep the world happy
|
|
222
|
-
@body.rewind
|
|
223
241
|
rescue Object
|
|
242
|
+
STDERR.puts "ERROR reading http body: #$!"
|
|
243
|
+
$!.backtrace.join("\n")
|
|
224
244
|
# any errors means we should delete the file, including if the file is dumped
|
|
225
|
-
@socket.close
|
|
245
|
+
@socket.close rescue Object
|
|
226
246
|
@body.delete if @body.class == Tempfile
|
|
227
247
|
@body = nil # signals that there was a problem
|
|
228
248
|
end
|
|
229
249
|
end
|
|
230
250
|
|
|
251
|
+
def read_socket(len)
|
|
252
|
+
if !@socket.closed?
|
|
253
|
+
data = @socket.read(len)
|
|
254
|
+
if !data
|
|
255
|
+
raise "Socket read return nil"
|
|
256
|
+
elsif data.length != len
|
|
257
|
+
raise "Socket read returned insufficient data: #{data.length}"
|
|
258
|
+
else
|
|
259
|
+
data
|
|
260
|
+
end
|
|
261
|
+
else
|
|
262
|
+
raise "Socket already closed when reading."
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
231
266
|
# Performs URI escaping so that you can construct proper
|
|
232
267
|
# query strings faster. Use this rather than the cgi.rb
|
|
233
268
|
# version since it's faster. (Stolen from Camping).
|
|
@@ -363,15 +398,16 @@ module Mongrel
|
|
|
363
398
|
elsif @header_sent
|
|
364
399
|
raise "You have already sent the request headers."
|
|
365
400
|
else
|
|
366
|
-
@header.out.
|
|
367
|
-
@body.
|
|
401
|
+
@header.out.truncate(0)
|
|
402
|
+
@body.close
|
|
403
|
+
@body = StringIO.new
|
|
368
404
|
end
|
|
369
405
|
end
|
|
370
406
|
|
|
371
|
-
def send_status(content_length
|
|
407
|
+
def send_status(content_length=@body.length)
|
|
372
408
|
if not @status_sent
|
|
373
|
-
content_length
|
|
374
|
-
write(Const::STATUS_FORMAT % [status, HTTP_STATUS_CODES[@status]
|
|
409
|
+
@header['Content-Length'] = content_length unless @status == 304
|
|
410
|
+
write(Const::STATUS_FORMAT % [@status, HTTP_STATUS_CODES[@status]])
|
|
375
411
|
@status_sent = true
|
|
376
412
|
end
|
|
377
413
|
end
|
|
@@ -393,33 +429,29 @@ module Mongrel
|
|
|
393
429
|
end
|
|
394
430
|
|
|
395
431
|
# Appends the contents of +path+ to the response stream. The file is opened for binary
|
|
396
|
-
# reading and written in chunks to the socket.
|
|
397
|
-
# <a href="http://rubyforge.org/projects/ruby-sendfile">sendfile</a> library is found,
|
|
398
|
-
# it is used to send the file, often with greater speed and less memory/cpu usage.
|
|
432
|
+
# reading and written in chunks to the socket.
|
|
399
433
|
#
|
|
400
|
-
#
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
begin
|
|
407
|
-
@socket.sendfile(f)
|
|
408
|
-
rescue => details
|
|
409
|
-
socket_error(details)
|
|
410
|
-
end
|
|
411
|
-
else
|
|
434
|
+
# Sendfile API support has been removed in 0.3.13.4 due to stability problems.
|
|
435
|
+
def send_file(path, small_file = false)
|
|
436
|
+
if small_file
|
|
437
|
+
File.open(path, "rb") {|f| @socket << f.read }
|
|
438
|
+
else
|
|
439
|
+
File.open(path, "rb") do |f|
|
|
412
440
|
while chunk = f.read(Const::CHUNK_SIZE) and chunk.length > 0
|
|
413
|
-
|
|
441
|
+
begin
|
|
442
|
+
write(chunk)
|
|
443
|
+
rescue Object => exc
|
|
444
|
+
break
|
|
445
|
+
end
|
|
414
446
|
end
|
|
415
447
|
end
|
|
416
|
-
@body_sent = true
|
|
417
448
|
end
|
|
449
|
+
@body_sent = true
|
|
418
450
|
end
|
|
419
451
|
|
|
420
452
|
def socket_error(details)
|
|
421
453
|
# ignore these since it means the client closed off early
|
|
422
|
-
@socket.close
|
|
454
|
+
@socket.close rescue Object
|
|
423
455
|
done = true
|
|
424
456
|
raise details
|
|
425
457
|
end
|
|
@@ -514,7 +546,7 @@ module Mongrel
|
|
|
514
546
|
def process_client(client)
|
|
515
547
|
begin
|
|
516
548
|
parser = HttpParser.new
|
|
517
|
-
params =
|
|
549
|
+
params = HttpParams.new
|
|
518
550
|
request = nil
|
|
519
551
|
data = client.readpartial(Const::CHUNK_SIZE)
|
|
520
552
|
nparsed = 0
|
|
@@ -527,7 +559,7 @@ module Mongrel
|
|
|
527
559
|
nparsed = parser.execute(params, data, nparsed)
|
|
528
560
|
|
|
529
561
|
if parser.finished?
|
|
530
|
-
script_name, path_info, handlers = @classifier.resolve(params[Const::
|
|
562
|
+
script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH])
|
|
531
563
|
|
|
532
564
|
if handlers
|
|
533
565
|
params[Const::PATH_INFO] = path_info
|
|
@@ -535,10 +567,7 @@ module Mongrel
|
|
|
535
567
|
params[Const::REMOTE_ADDR] = params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last
|
|
536
568
|
notifier = handlers[0].request_notify ? handlers[0] : nil
|
|
537
569
|
|
|
538
|
-
|
|
539
|
-
data = data[nparsed ... data.length] || ""
|
|
540
|
-
|
|
541
|
-
request = HttpRequest.new(params, data, client, notifier)
|
|
570
|
+
request = HttpRequest.new(params, client, notifier)
|
|
542
571
|
|
|
543
572
|
# in the case of large file uploads the user could close the socket, so skip those requests
|
|
544
573
|
break if request.body == nil # nil signals from HttpRequest::initialize that the request was aborted
|
|
@@ -564,22 +593,29 @@ module Mongrel
|
|
|
564
593
|
break #done
|
|
565
594
|
else
|
|
566
595
|
# Parser is not done, queue up more data to read and continue parsing
|
|
567
|
-
|
|
596
|
+
chunk = client.readpartial(Const::CHUNK_SIZE)
|
|
597
|
+
break if !chunk or chunk.length == 0 # read failed, stop processing
|
|
598
|
+
|
|
599
|
+
data << chunk
|
|
568
600
|
if data.length >= Const::MAX_HEADER
|
|
569
601
|
raise HttpParserError.new("HEADER is longer than allowed, aborting client early.")
|
|
570
602
|
end
|
|
571
603
|
end
|
|
572
604
|
end
|
|
573
605
|
rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
|
|
574
|
-
|
|
606
|
+
client.close rescue Object
|
|
575
607
|
rescue HttpParserError
|
|
576
|
-
|
|
608
|
+
if $mongrel_debug_client
|
|
609
|
+
STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
|
|
610
|
+
STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
|
|
611
|
+
end
|
|
577
612
|
rescue Errno::EMFILE
|
|
578
613
|
reap_dead_workers('too many files')
|
|
579
614
|
rescue Object
|
|
580
615
|
STDERR.puts "#{Time.now}: ERROR: #$!"
|
|
616
|
+
STDERR.puts $!.backtrace.join("\n") if $mongrel_debug_client
|
|
581
617
|
ensure
|
|
582
|
-
client.close
|
|
618
|
+
client.close rescue Object
|
|
583
619
|
request.body.delete if request and request.body.class == Tempfile
|
|
584
620
|
end
|
|
585
621
|
end
|
|
@@ -591,13 +627,14 @@ module Mongrel
|
|
|
591
627
|
def reap_dead_workers(reason='unknown')
|
|
592
628
|
if @workers.list.length > 0
|
|
593
629
|
STDERR.puts "#{Time.now}: Reaping #{@workers.list.length} threads for slow workers because of '#{reason}'"
|
|
630
|
+
error_msg = "Mongrel timed out this thread: #{reason}"
|
|
594
631
|
mark = Time.now
|
|
595
632
|
@workers.list.each do |w|
|
|
596
633
|
w[:started_on] = Time.now if not w[:started_on]
|
|
597
634
|
|
|
598
635
|
if mark - w[:started_on] > @death_time + @timeout
|
|
599
636
|
STDERR.puts "Thread #{w.inspect} is too old, killing."
|
|
600
|
-
w.raise(TimeoutError.new(
|
|
637
|
+
w.raise(TimeoutError.new(error_msg))
|
|
601
638
|
end
|
|
602
639
|
end
|
|
603
640
|
end
|
|
@@ -616,21 +653,34 @@ module Mongrel
|
|
|
616
653
|
end
|
|
617
654
|
end
|
|
618
655
|
|
|
656
|
+
def configure_socket_options
|
|
657
|
+
if /linux/ === RUBY_PLATFORM
|
|
658
|
+
# 9 is currently TCP_DEFER_ACCEPT
|
|
659
|
+
$tcp_defer_accept_opts = [9,1]
|
|
660
|
+
$tcp_cork_opts = [3,1]
|
|
661
|
+
end
|
|
662
|
+
end
|
|
619
663
|
|
|
620
664
|
# Runs the thing. It returns the thread used so you can "join" it. You can also
|
|
621
665
|
# access the HttpServer::acceptor attribute to get the thread later.
|
|
622
666
|
def run
|
|
623
667
|
BasicSocket.do_not_reverse_lookup=true
|
|
624
668
|
|
|
669
|
+
configure_socket_options
|
|
670
|
+
|
|
671
|
+
@socket.setsockopt(Socket::SOL_TCP, $tcp_defer_accept_opts[0], $tcp_defer_accept_opts[1]) if $tcp_defer_accept_opts
|
|
672
|
+
|
|
625
673
|
@acceptor = Thread.new do
|
|
626
674
|
while true
|
|
627
675
|
begin
|
|
628
676
|
client = @socket.accept
|
|
677
|
+
client.setsockopt(Socket::SOL_TCP, $tcp_cork_opts[0], $tcp_cork_opts[1]) if $tcp_cork_opts
|
|
678
|
+
|
|
629
679
|
worker_list = @workers.list
|
|
630
680
|
|
|
631
681
|
if worker_list.length >= @num_processors
|
|
632
682
|
STDERR.puts "Server overloaded with #{worker_list.length} processors (#@num_processors max). Dropping connection."
|
|
633
|
-
client.close
|
|
683
|
+
client.close rescue Object
|
|
634
684
|
reap_dead_workers("max processors")
|
|
635
685
|
else
|
|
636
686
|
thread = Thread.new { process_client(client) }
|
|
@@ -641,11 +691,17 @@ module Mongrel
|
|
|
641
691
|
sleep @timeout/100 if @timeout > 0
|
|
642
692
|
end
|
|
643
693
|
rescue StopServer
|
|
644
|
-
@socket.close
|
|
694
|
+
@socket.close rescue Object
|
|
645
695
|
break
|
|
646
696
|
rescue Errno::EMFILE
|
|
647
697
|
reap_dead_workers("too many open files")
|
|
648
698
|
sleep 0.5
|
|
699
|
+
rescue Errno::ECONNABORTED
|
|
700
|
+
# client closed the socket even before accept
|
|
701
|
+
client.close rescue Object
|
|
702
|
+
rescue Object => exc
|
|
703
|
+
STDERR.puts "!!!!!! UNHANDLED EXCEPTION! #{exc}. TELL ZED HE'S A MORON."
|
|
704
|
+
STDERR.puts $!.backtrace.join("\n") if $mongrel_debug_client
|
|
649
705
|
end
|
|
650
706
|
end
|
|
651
707
|
|
|
@@ -700,366 +756,4 @@ module Mongrel
|
|
|
700
756
|
end
|
|
701
757
|
|
|
702
758
|
end
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
# Implements a simple DSL for configuring a Mongrel server for your
|
|
706
|
-
# purposes. More used by framework implementers to setup Mongrel
|
|
707
|
-
# how they like, but could be used by regular folks to add more things
|
|
708
|
-
# to an existing mongrel configuration.
|
|
709
|
-
#
|
|
710
|
-
# It is used like this:
|
|
711
|
-
#
|
|
712
|
-
# require 'mongrel'
|
|
713
|
-
# config = Mongrel::Configurator.new :host => "127.0.0.1" do
|
|
714
|
-
# listener :port => 3000 do
|
|
715
|
-
# uri "/app", :handler => Mongrel::DirHandler.new(".", load_mime_map("mime.yaml"))
|
|
716
|
-
# end
|
|
717
|
-
# run
|
|
718
|
-
# end
|
|
719
|
-
#
|
|
720
|
-
# This will setup a simple DirHandler at the current directory and load additional
|
|
721
|
-
# mime types from mimy.yaml. The :host => "127.0.0.1" is actually not
|
|
722
|
-
# specific to the servers but just a hash of default parameters that all
|
|
723
|
-
# server or uri calls receive.
|
|
724
|
-
#
|
|
725
|
-
# When you are inside the block after Mongrel::Configurator.new you can simply
|
|
726
|
-
# call functions that are part of Configurator (like server, uri, daemonize, etc)
|
|
727
|
-
# without having to refer to anything else. You can also call these functions on
|
|
728
|
-
# the resulting object directly for additional configuration.
|
|
729
|
-
#
|
|
730
|
-
# A major thing about Configurator is that it actually lets you configure
|
|
731
|
-
# multiple listeners for any hosts and ports you want. These are kept in a
|
|
732
|
-
# map config.listeners so you can get to them.
|
|
733
|
-
#
|
|
734
|
-
# * :pid_file => Where to write the process ID.
|
|
735
|
-
class Configurator
|
|
736
|
-
attr_reader :listeners
|
|
737
|
-
attr_reader :defaults
|
|
738
|
-
attr_reader :needs_restart
|
|
739
|
-
|
|
740
|
-
# You pass in initial defaults and then a block to continue configuring.
|
|
741
|
-
def initialize(defaults={}, &blk)
|
|
742
|
-
@listener = nil
|
|
743
|
-
@listener_name = nil
|
|
744
|
-
@listeners = {}
|
|
745
|
-
@defaults = defaults
|
|
746
|
-
@needs_restart = false
|
|
747
|
-
@pid_file = defaults[:pid_file]
|
|
748
|
-
|
|
749
|
-
if blk
|
|
750
|
-
cloaker(&blk).bind(self).call
|
|
751
|
-
end
|
|
752
|
-
end
|
|
753
|
-
|
|
754
|
-
# Change privilege of the process to specified user and group.
|
|
755
|
-
def change_privilege(user, group)
|
|
756
|
-
begin
|
|
757
|
-
if group
|
|
758
|
-
log "Changing group to #{group}."
|
|
759
|
-
Process::GID.change_privilege(Etc.getgrnam(group).gid)
|
|
760
|
-
end
|
|
761
|
-
|
|
762
|
-
if user
|
|
763
|
-
log "Changing user to #{user}."
|
|
764
|
-
Process::UID.change_privilege(Etc.getpwnam(user).uid)
|
|
765
|
-
end
|
|
766
|
-
rescue Errno::EPERM
|
|
767
|
-
log "FAILED to change user:group #{user}:#{group}: #$!"
|
|
768
|
-
exit 1
|
|
769
|
-
end
|
|
770
|
-
end
|
|
771
|
-
|
|
772
|
-
# Writes the PID file but only if we're on windows.
|
|
773
|
-
def write_pid_file
|
|
774
|
-
if RUBY_PLATFORM !~ /mswin/
|
|
775
|
-
open(@pid_file,"w") {|f| f.write(Process.pid) }
|
|
776
|
-
end
|
|
777
|
-
end
|
|
778
|
-
|
|
779
|
-
# generates a class for cloaking the current self and making the DSL nicer
|
|
780
|
-
def cloaking_class
|
|
781
|
-
class << self
|
|
782
|
-
self
|
|
783
|
-
end
|
|
784
|
-
end
|
|
785
|
-
|
|
786
|
-
# Do not call this. You were warned.
|
|
787
|
-
def cloaker(&blk)
|
|
788
|
-
cloaking_class.class_eval do
|
|
789
|
-
define_method :cloaker_, &blk
|
|
790
|
-
meth = instance_method( :cloaker_ )
|
|
791
|
-
remove_method :cloaker_
|
|
792
|
-
meth
|
|
793
|
-
end
|
|
794
|
-
end
|
|
795
|
-
|
|
796
|
-
# This will resolve the given options against the defaults.
|
|
797
|
-
# Normally just used internally.
|
|
798
|
-
def resolve_defaults(options)
|
|
799
|
-
options.merge(@defaults)
|
|
800
|
-
end
|
|
801
|
-
|
|
802
|
-
# Starts a listener block. This is the only one that actually takes
|
|
803
|
-
# a block and then you make Configurator.uri calls in order to setup
|
|
804
|
-
# your URIs and handlers. If you write your Handlers as GemPlugins
|
|
805
|
-
# then you can use load_plugins and plugin to load them.
|
|
806
|
-
#
|
|
807
|
-
# It expects the following options (or defaults):
|
|
808
|
-
#
|
|
809
|
-
# * :host => Host name to bind.
|
|
810
|
-
# * :port => Port to bind.
|
|
811
|
-
# * :num_processors => The maximum number of concurrent threads allowed. (950 default)
|
|
812
|
-
# * :timeout => 1/100th of a second timeout between requests. (10 is 1/10th, 0 is timeout)
|
|
813
|
-
# * :user => User to change to, must have :group as well.
|
|
814
|
-
# * :group => Group to change to, must have :user as well.
|
|
815
|
-
#
|
|
816
|
-
def listener(options={},&blk)
|
|
817
|
-
raise "Cannot call listener inside another listener block." if (@listener or @listener_name)
|
|
818
|
-
ops = resolve_defaults(options)
|
|
819
|
-
ops[:num_processors] ||= 950
|
|
820
|
-
ops[:timeout] ||= 0
|
|
821
|
-
|
|
822
|
-
@listener = Mongrel::HttpServer.new(ops[:host], ops[:port].to_i, ops[:num_processors].to_i, ops[:timeout].to_i)
|
|
823
|
-
@listener_name = "#{ops[:host]}:#{ops[:port]}"
|
|
824
|
-
@listeners[@listener_name] = @listener
|
|
825
|
-
|
|
826
|
-
if ops[:user] and ops[:group]
|
|
827
|
-
change_privilege(ops[:user], ops[:group])
|
|
828
|
-
end
|
|
829
|
-
|
|
830
|
-
# Does the actual cloaking operation to give the new implicit self.
|
|
831
|
-
if blk
|
|
832
|
-
cloaker(&blk).bind(self).call
|
|
833
|
-
end
|
|
834
|
-
|
|
835
|
-
# all done processing this listener setup, reset implicit variables
|
|
836
|
-
@listener = nil
|
|
837
|
-
@listener_name = nil
|
|
838
|
-
end
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
# Called inside a Configurator.listener block in order to
|
|
842
|
-
# add URI->handler mappings for that listener. Use this as
|
|
843
|
-
# many times as you like. It expects the following options
|
|
844
|
-
# or defaults:
|
|
845
|
-
#
|
|
846
|
-
# * :handler => HttpHandler -- Handler to use for this location.
|
|
847
|
-
# * :in_front => true/false -- Rather than appending, it prepends this handler.
|
|
848
|
-
def uri(location, options={})
|
|
849
|
-
ops = resolve_defaults(options)
|
|
850
|
-
@listener.register(location, ops[:handler], in_front=ops[:in_front])
|
|
851
|
-
end
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
# Daemonizes the current Ruby script turning all the
|
|
855
|
-
# listeners into an actual "server" or detached process.
|
|
856
|
-
# You must call this *before* frameworks that open files
|
|
857
|
-
# as otherwise the files will be closed by this function.
|
|
858
|
-
#
|
|
859
|
-
# Does not work for Win32 systems (the call is silently ignored).
|
|
860
|
-
#
|
|
861
|
-
# Requires the following options or defaults:
|
|
862
|
-
#
|
|
863
|
-
# * :cwd => Directory to change to.
|
|
864
|
-
# * :log_file => Where to write STDOUT and STDERR.
|
|
865
|
-
#
|
|
866
|
-
# It is safe to call this on win32 as it will only require the daemons
|
|
867
|
-
# gem/library if NOT win32.
|
|
868
|
-
def daemonize(options={})
|
|
869
|
-
ops = resolve_defaults(options)
|
|
870
|
-
# save this for later since daemonize will hose it
|
|
871
|
-
if RUBY_PLATFORM !~ /mswin/
|
|
872
|
-
require 'daemons/daemonize'
|
|
873
|
-
|
|
874
|
-
Daemonize.daemonize(log_file=File.join(ops[:cwd], ops[:log_file]))
|
|
875
|
-
|
|
876
|
-
# change back to the original starting directory
|
|
877
|
-
Dir.chdir(ops[:cwd])
|
|
878
|
-
|
|
879
|
-
else
|
|
880
|
-
log "WARNING: Win32 does not support daemon mode."
|
|
881
|
-
end
|
|
882
|
-
end
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
# Uses the GemPlugin system to easily load plugins based on their
|
|
886
|
-
# gem dependencies. You pass in either an :includes => [] or
|
|
887
|
-
# :excludes => [] setting listing the names of plugins to include
|
|
888
|
-
# or exclude from the when determining the dependencies.
|
|
889
|
-
def load_plugins(options={})
|
|
890
|
-
ops = resolve_defaults(options)
|
|
891
|
-
|
|
892
|
-
load_settings = {}
|
|
893
|
-
if ops[:includes]
|
|
894
|
-
ops[:includes].each do |plugin|
|
|
895
|
-
load_settings[plugin] = GemPlugin::INCLUDE
|
|
896
|
-
end
|
|
897
|
-
end
|
|
898
|
-
|
|
899
|
-
if ops[:excludes]
|
|
900
|
-
ops[:excludes].each do |plugin|
|
|
901
|
-
load_settings[plugin] = GemPlugin::EXCLUDE
|
|
902
|
-
end
|
|
903
|
-
end
|
|
904
|
-
|
|
905
|
-
GemPlugin::Manager.instance.load(load_settings)
|
|
906
|
-
end
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
# Easy way to load a YAML file and apply default settings.
|
|
910
|
-
def load_yaml(file, default={})
|
|
911
|
-
default.merge(YAML.load_file(file))
|
|
912
|
-
end
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
# Loads the MIME map file and checks that it is correct
|
|
916
|
-
# on loading. This is commonly passed to Mongrel::DirHandler
|
|
917
|
-
# or any framework handler that uses DirHandler to serve files.
|
|
918
|
-
# You can also include a set of default MIME types as additional
|
|
919
|
-
# settings. See Mongrel::DirHandler for how the MIME types map
|
|
920
|
-
# is organized.
|
|
921
|
-
def load_mime_map(file, mime={})
|
|
922
|
-
# configure any requested mime map
|
|
923
|
-
mime = load_yaml(file, mime)
|
|
924
|
-
|
|
925
|
-
# check all the mime types to make sure they are the right format
|
|
926
|
-
mime.each {|k,v| log "WARNING: MIME type #{k} must start with '.'" if k.index(".") != 0 }
|
|
927
|
-
|
|
928
|
-
return mime
|
|
929
|
-
end
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
# Loads and creates a plugin for you based on the given
|
|
933
|
-
# name and configured with the selected options. The options
|
|
934
|
-
# are merged with the defaults prior to passing them in.
|
|
935
|
-
def plugin(name, options={})
|
|
936
|
-
ops = resolve_defaults(options)
|
|
937
|
-
GemPlugin::Manager.instance.create(name, ops)
|
|
938
|
-
end
|
|
939
|
-
|
|
940
|
-
# Let's you do redirects easily as described in Mongrel::RedirectHandler.
|
|
941
|
-
# You use it inside the configurator like this:
|
|
942
|
-
#
|
|
943
|
-
# redirect("/test", "/to/there") # simple
|
|
944
|
-
# redirect("/to", /t/, 'w') # regexp
|
|
945
|
-
# redirect("/hey", /(w+)/) {|match| ...} # block
|
|
946
|
-
#
|
|
947
|
-
def redirect(from, pattern, replacement = nil, &block)
|
|
948
|
-
uri from, :handler => Mongrel::RedirectHandler.new(pattern, replacement, &block)
|
|
949
|
-
end
|
|
950
|
-
|
|
951
|
-
# Works like a meta run method which goes through all the
|
|
952
|
-
# configured listeners. Use the Configurator.join method
|
|
953
|
-
# to prevent Ruby from exiting until each one is done.
|
|
954
|
-
def run
|
|
955
|
-
@listeners.each {|name,s|
|
|
956
|
-
s.run
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
$mongrel_sleeper_thread = Thread.new { loop { sleep 1 } }
|
|
960
|
-
end
|
|
961
|
-
|
|
962
|
-
# Calls .stop on all the configured listeners so they
|
|
963
|
-
# stop processing requests (gracefully). By default it
|
|
964
|
-
# assumes that you don't want to restart and that the pid file
|
|
965
|
-
# should be unlinked on exit.
|
|
966
|
-
def stop(needs_restart=false, unlink_pid_file=true)
|
|
967
|
-
@listeners.each {|name,s|
|
|
968
|
-
s.stop
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
@needs_restart = needs_restart
|
|
972
|
-
if unlink_pid_file
|
|
973
|
-
File.unlink @pid_file if (@pid_file and File.exist?(@pid_file))
|
|
974
|
-
end
|
|
975
|
-
end
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
# This method should actually be called *outside* of the
|
|
979
|
-
# Configurator block so that you can control it. In other words
|
|
980
|
-
# do it like: config.join.
|
|
981
|
-
def join
|
|
982
|
-
@listeners.values.each {|s| s.acceptor.join }
|
|
983
|
-
end
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
# Calling this before you register your URIs to the given location
|
|
987
|
-
# will setup a set of handlers that log open files, objects, and the
|
|
988
|
-
# parameters for each request. This helps you track common problems
|
|
989
|
-
# found in Rails applications that are either slow or become unresponsive
|
|
990
|
-
# after a little while.
|
|
991
|
-
#
|
|
992
|
-
# You can pass an extra parameter *what* to indicate what you want to
|
|
993
|
-
# debug. For example, if you just want to dump rails stuff then do:
|
|
994
|
-
#
|
|
995
|
-
# debug "/", what = [:rails]
|
|
996
|
-
#
|
|
997
|
-
# And it will only produce the log/mongrel_debug/rails.log file.
|
|
998
|
-
# Available options are: :objects, :rails, :files, :threads, :params
|
|
999
|
-
#
|
|
1000
|
-
# NOTE: Use [:files] to get accesses dumped to stderr like with WEBrick.
|
|
1001
|
-
def debug(location, what = [:objects, :rails, :files, :threads, :params])
|
|
1002
|
-
require 'mongrel/debug'
|
|
1003
|
-
handlers = {
|
|
1004
|
-
:files => "/handlers/requestlog::access",
|
|
1005
|
-
:rails => "/handlers/requestlog::files",
|
|
1006
|
-
:objects => "/handlers/requestlog::objects",
|
|
1007
|
-
:threads => "/handlers/requestlog::threads",
|
|
1008
|
-
:params => "/handlers/requestlog::params"
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
# turn on the debugging infrastructure, and ObjectTracker is a pig
|
|
1012
|
-
ObjectTracker.configure if what.include? :objects
|
|
1013
|
-
MongrelDbg.configure
|
|
1014
|
-
|
|
1015
|
-
# now we roll through each requested debug type, turn it on and load that plugin
|
|
1016
|
-
what.each do |type|
|
|
1017
|
-
MongrelDbg.begin_trace type
|
|
1018
|
-
uri location, :handler => plugin(handlers[type])
|
|
1019
|
-
end
|
|
1020
|
-
end
|
|
1021
|
-
|
|
1022
|
-
# Used to allow you to let users specify their own configurations
|
|
1023
|
-
# inside your Configurator setup. You pass it a script name and
|
|
1024
|
-
# it reads it in and does an eval on the contents passing in the right
|
|
1025
|
-
# binding so they can put their own Configurator statements.
|
|
1026
|
-
def run_config(script)
|
|
1027
|
-
open(script) {|f| eval(f.read, proc {self}) }
|
|
1028
|
-
end
|
|
1029
|
-
|
|
1030
|
-
# Sets up the standard signal handlers that are used on most Ruby
|
|
1031
|
-
# It only configures if the platform is not win32 and doesn't do
|
|
1032
|
-
# a HUP signal since this is typically framework specific.
|
|
1033
|
-
#
|
|
1034
|
-
# Requires a :pid_file option given to Configurator.new to indicate a file to delete.
|
|
1035
|
-
# It sets the MongrelConfig.needs_restart attribute if
|
|
1036
|
-
# the start command should reload. It's up to you to detect this
|
|
1037
|
-
# and do whatever is needed for a "restart".
|
|
1038
|
-
#
|
|
1039
|
-
# This command is safely ignored if the platform is win32 (with a warning)
|
|
1040
|
-
def setup_signals(options={})
|
|
1041
|
-
ops = resolve_defaults(options)
|
|
1042
|
-
|
|
1043
|
-
# forced shutdown, even if previously restarted (actually just like TERM but for CTRL-C)
|
|
1044
|
-
trap("INT") { log "INT signal received."; stop(need_restart=false) }
|
|
1045
|
-
|
|
1046
|
-
if RUBY_PLATFORM !~ /mswin/
|
|
1047
|
-
# graceful shutdown
|
|
1048
|
-
trap("TERM") { log "TERM signal received."; stop }
|
|
1049
|
-
|
|
1050
|
-
# restart
|
|
1051
|
-
trap("USR2") { log "USR2 signal received."; stop(need_restart=true) }
|
|
1052
|
-
|
|
1053
|
-
log "Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart)."
|
|
1054
|
-
else
|
|
1055
|
-
log "Signals ready. INT => stop (no restart)."
|
|
1056
|
-
end
|
|
1057
|
-
end
|
|
1058
|
-
|
|
1059
|
-
# Logs a simple message to STDERR (or the mongrel log if in daemon mode).
|
|
1060
|
-
def log(msg)
|
|
1061
|
-
STDERR.print "** ", msg, "\n"
|
|
1062
|
-
end
|
|
1063
|
-
|
|
1064
|
-
end
|
|
1065
759
|
end
|