mongrel 0.3.13.3 → 0.3.13.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (258) hide show
  1. data/Rakefile +5 -4
  2. data/bin/mongrel_rails +162 -169
  3. data/doc/rdoc/classes/IO.src/M000001.html +5 -5
  4. data/doc/rdoc/classes/IO.src/M000002.html +5 -5
  5. data/doc/rdoc/classes/Kernel.html +10 -10
  6. data/doc/rdoc/classes/Kernel.src/M000010.html +19 -0
  7. data/doc/rdoc/classes/Kernel.src/M000011.html +23 -0
  8. data/doc/rdoc/classes/Mongrel.html +27 -10
  9. data/doc/rdoc/classes/Mongrel/CGIWrapper.html +67 -54
  10. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000101.html → M000112.html} +11 -10
  11. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000102.html → M000113.html} +31 -31
  12. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000103.html → M000114.html} +20 -20
  13. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000115.html +32 -0
  14. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000105.html → M000116.html} +11 -11
  15. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000106.html → M000117.html} +4 -4
  16. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000107.html → M000118.html} +4 -4
  17. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000108.html → M000119.html} +4 -4
  18. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/{M000109.html → M000120.html} +5 -5
  19. data/doc/rdoc/classes/Mongrel/Camping.html +5 -5
  20. data/doc/rdoc/classes/Mongrel/Camping.src/{M000048.html → M000039.html} +0 -0
  21. data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.html +10 -10
  22. data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.src/{M000049.html → M000040.html} +0 -0
  23. data/doc/rdoc/classes/Mongrel/Camping/CampingHandler.src/{M000050.html → M000041.html} +0 -0
  24. data/doc/rdoc/classes/Mongrel/Command/Base.html +65 -65
  25. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000016.html +24 -0
  26. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000017.html +42 -0
  27. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000018.html +18 -0
  28. data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000029.html → M000019.html} +0 -0
  29. data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000030.html → M000020.html} +0 -0
  30. data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000031.html → M000021.html} +0 -0
  31. data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000032.html → M000022.html} +0 -0
  32. data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000033.html → M000023.html} +0 -0
  33. data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000034.html → M000024.html} +0 -0
  34. data/doc/rdoc/classes/Mongrel/Command/Base.src/{M000035.html → M000025.html} +0 -0
  35. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000026.html +11 -11
  36. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000027.html +11 -29
  37. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000028.html +5 -5
  38. data/doc/rdoc/classes/Mongrel/Command/Registry.html +15 -15
  39. data/doc/rdoc/classes/Mongrel/Command/Registry.src/{M000039.html → M000029.html} +0 -0
  40. data/doc/rdoc/classes/Mongrel/Command/Registry.src/{M000040.html → M000030.html} +10 -6
  41. data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000031.html +58 -0
  42. data/doc/rdoc/classes/Mongrel/Configurator.html +115 -115
  43. data/doc/rdoc/classes/Mongrel/Configurator.src/M000091.html +27 -0
  44. data/doc/rdoc/classes/Mongrel/Configurator.src/M000092.html +31 -0
  45. data/doc/rdoc/classes/Mongrel/Configurator.src/M000093.html +21 -0
  46. data/doc/rdoc/classes/Mongrel/Configurator.src/M000094.html +20 -0
  47. data/doc/rdoc/classes/Mongrel/Configurator.src/M000095.html +23 -0
  48. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000115.html → M000096.html} +4 -4
  49. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000116.html → M000097.html} +24 -24
  50. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000117.html → M000098.html} +5 -5
  51. data/doc/rdoc/classes/Mongrel/Configurator.src/M000099.html +39 -0
  52. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000119.html → M000100.html} +19 -19
  53. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000120.html → M000101.html} +4 -4
  54. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000121.html → M000102.html} +10 -10
  55. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000122.html → M000103.html} +5 -5
  56. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000123.html → M000104.html} +4 -4
  57. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000124.html → M000105.html} +8 -8
  58. data/doc/rdoc/classes/Mongrel/Configurator.src/M000106.html +22 -0
  59. data/doc/rdoc/classes/Mongrel/Configurator.src/{M000126.html → M000107.html} +4 -4
  60. data/doc/rdoc/classes/Mongrel/Configurator.src/M000108.html +34 -0
  61. data/doc/rdoc/classes/Mongrel/Configurator.src/M000109.html +18 -0
  62. data/doc/rdoc/classes/Mongrel/Configurator.src/M000110.html +23 -14
  63. data/doc/rdoc/classes/Mongrel/Configurator.src/M000111.html +5 -18
  64. data/doc/rdoc/classes/Mongrel/Const.html +11 -6
  65. data/doc/rdoc/classes/Mongrel/DeflateFilter.html +10 -10
  66. data/doc/rdoc/classes/Mongrel/DeflateFilter.src/{M000099.html → M000121.html} +5 -5
  67. data/doc/rdoc/classes/Mongrel/DeflateFilter.src/{M000100.html → M000122.html} +14 -14
  68. data/doc/rdoc/classes/Mongrel/DirHandler.html +31 -31
  69. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000058.html → M000049.html} +0 -0
  70. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000059.html → M000050.html} +0 -0
  71. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000060.html → M000051.html} +12 -16
  72. data/doc/rdoc/classes/Mongrel/DirHandler.src/M000052.html +63 -0
  73. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000062.html → M000053.html} +25 -25
  74. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000063.html → M000054.html} +4 -4
  75. data/doc/rdoc/classes/Mongrel/Error404Handler.html +10 -10
  76. data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000131.html → M000123.html} +0 -0
  77. data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000132.html → M000124.html} +0 -0
  78. data/doc/rdoc/classes/Mongrel/HeaderOut.html +10 -10
  79. data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000072.html → M000064.html} +4 -4
  80. data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000073.html → M000065.html} +4 -4
  81. data/doc/rdoc/classes/Mongrel/HttpHandler.html +15 -15
  82. data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000078.html → M000070.html} +0 -0
  83. data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000079.html → M000071.html} +0 -0
  84. data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000080.html → M000072.html} +0 -0
  85. data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.html +20 -20
  86. data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000022.html → M000012.html} +0 -0
  87. data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000023.html → M000013.html} +0 -0
  88. data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000024.html → M000014.html} +0 -0
  89. data/doc/rdoc/classes/Mongrel/HttpHandlerPlugin.src/{M000025.html → M000015.html} +0 -0
  90. data/doc/rdoc/classes/Mongrel/HttpParams.html +131 -0
  91. data/doc/rdoc/classes/Mongrel/HttpParser.html +35 -35
  92. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000051.html → M000042.html} +1 -1
  93. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000052.html → M000043.html} +1 -1
  94. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000053.html → M000044.html} +1 -1
  95. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000054.html → M000045.html} +3 -3
  96. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000055.html → M000046.html} +1 -1
  97. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000056.html → M000047.html} +1 -1
  98. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000057.html → M000048.html} +1 -1
  99. data/doc/rdoc/classes/Mongrel/HttpRequest.html +63 -24
  100. data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000130.html +47 -0
  101. data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000131.html +37 -0
  102. data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000132.html +29 -0
  103. data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000139.html → M000133.html} +6 -6
  104. data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000140.html → M000134.html} +6 -6
  105. data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000141.html → M000135.html} +18 -18
  106. data/doc/rdoc/classes/Mongrel/HttpResponse.html +66 -72
  107. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000073.html +25 -0
  108. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000074.html +20 -0
  109. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000075.html +26 -0
  110. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000076.html +22 -0
  111. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000085.html → M000077.html} +8 -8
  112. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000086.html → M000078.html} +8 -8
  113. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000079.html +31 -0
  114. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000088.html → M000080.html} +7 -7
  115. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000081.html +7 -12
  116. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000082.html +7 -7
  117. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000083.html +7 -12
  118. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000084.html +5 -9
  119. data/doc/rdoc/classes/Mongrel/HttpServer.html +58 -43
  120. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000064.html → M000055.html} +11 -11
  121. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000065.html → M000056.html} +76 -72
  122. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000066.html → M000057.html} +18 -17
  123. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000067.html → M000058.html} +7 -7
  124. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000059.html +22 -0
  125. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000060.html +62 -0
  126. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000069.html → M000061.html} +20 -20
  127. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000070.html → M000062.html} +4 -4
  128. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000071.html → M000063.html} +8 -8
  129. data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.html +15 -15
  130. data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/{M000042.html → M000032.html} +23 -25
  131. data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/{M000043.html → M000033.html} +11 -11
  132. data/doc/rdoc/classes/Mongrel/Rails/RailsConfigurator.src/{M000044.html → M000034.html} +12 -12
  133. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.html +30 -15
  134. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/{M000045.html → M000035.html} +9 -8
  135. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000036.html +54 -0
  136. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000037.html +21 -0
  137. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000038.html +25 -0
  138. data/doc/rdoc/classes/Mongrel/RedirectHandler.html +10 -10
  139. data/doc/rdoc/classes/Mongrel/RedirectHandler.src/{M000136.html → M000128.html} +8 -8
  140. data/doc/rdoc/classes/Mongrel/RedirectHandler.src/{M000137.html → M000129.html} +13 -13
  141. data/doc/rdoc/classes/Mongrel/StatisticsFilter.html +16 -16
  142. data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/M000125.html +24 -0
  143. data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/{M000134.html → M000126.html} +10 -10
  144. data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/{M000135.html → M000127.html} +4 -4
  145. data/doc/rdoc/classes/{Stats.html → Mongrel/Stats.html} +44 -60
  146. data/doc/rdoc/classes/Mongrel/Stats.src/M000136.html +19 -0
  147. data/doc/rdoc/classes/Mongrel/Stats.src/M000137.html +23 -0
  148. data/doc/rdoc/classes/Mongrel/Stats.src/M000138.html +26 -0
  149. data/doc/rdoc/classes/Mongrel/Stats.src/M000139.html +18 -0
  150. data/doc/rdoc/classes/{Stats.src/M000009.html → Mongrel/Stats.src/M000140.html} +6 -6
  151. data/doc/rdoc/classes/Mongrel/Stats.src/M000141.html +18 -0
  152. data/doc/rdoc/classes/Mongrel/Stats.src/M000142.html +23 -0
  153. data/doc/rdoc/classes/Mongrel/Stats.src/M000143.html +20 -0
  154. data/doc/rdoc/classes/Mongrel/StatusHandler.html +20 -20
  155. data/doc/rdoc/classes/Mongrel/StatusHandler.src/{M000074.html → M000066.html} +4 -4
  156. data/doc/rdoc/classes/Mongrel/StatusHandler.src/{M000075.html → M000067.html} +10 -10
  157. data/doc/rdoc/classes/Mongrel/StatusHandler.src/{M000076.html → M000068.html} +28 -28
  158. data/doc/rdoc/classes/Mongrel/StatusHandler.src/{M000077.html → M000069.html} +6 -6
  159. data/doc/rdoc/classes/Mongrel/URIClassifier.html +30 -30
  160. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000093.html → M000085.html} +4 -4
  161. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000094.html → M000086.html} +4 -4
  162. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000095.html → M000087.html} +0 -0
  163. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000096.html → M000088.html} +1 -1
  164. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000097.html → M000089.html} +0 -0
  165. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000098.html → M000090.html} +1 -1
  166. data/doc/rdoc/classes/MongrelDbg.html +26 -26
  167. data/doc/rdoc/classes/MongrelDbg.src/M000005.html +24 -0
  168. data/doc/rdoc/classes/MongrelDbg.src/{M000016.html → M000006.html} +6 -6
  169. data/doc/rdoc/classes/MongrelDbg.src/{M000017.html → M000007.html} +8 -8
  170. data/doc/rdoc/classes/MongrelDbg.src/{M000018.html → M000008.html} +7 -7
  171. data/doc/rdoc/classes/MongrelDbg.src/{M000019.html → M000009.html} +4 -4
  172. data/doc/rdoc/classes/RequestLog/Access.html +5 -5
  173. data/doc/rdoc/classes/RequestLog/Access.src/{M000142.html → M000144.html} +5 -5
  174. data/doc/rdoc/classes/RequestLog/Files.html +5 -5
  175. data/doc/rdoc/classes/RequestLog/Files.src/{M000143.html → M000145.html} +5 -5
  176. data/doc/rdoc/classes/RequestLog/Objects.html +12 -6
  177. data/doc/rdoc/classes/RequestLog/Objects.src/M000147.html +51 -0
  178. data/doc/rdoc/classes/RequestLog/Params.html +5 -5
  179. data/doc/rdoc/classes/RequestLog/Params.src/{M000146.html → M000148.html} +5 -5
  180. data/doc/rdoc/classes/RequestLog/Threads.html +5 -5
  181. data/doc/rdoc/classes/RequestLog/Threads.src/{M000144.html → M000146.html} +20 -20
  182. data/doc/rdoc/classes/{ObjectTracker.html → Sync.html} +26 -45
  183. data/doc/rdoc/created.rid +1 -1
  184. data/doc/rdoc/files/COPYING.html +1 -1
  185. data/doc/rdoc/files/LICENSE.html +1 -1
  186. data/doc/rdoc/files/README.html +1 -1
  187. data/doc/rdoc/files/ext/http11/http11_c.html +1 -1
  188. data/doc/rdoc/files/lib/mongrel/camping_rb.html +1 -1
  189. data/doc/rdoc/files/lib/mongrel/cgi_rb.html +1 -1
  190. data/doc/rdoc/files/lib/mongrel/command_rb.html +1 -1
  191. data/doc/rdoc/files/lib/mongrel/configurator_rb.html +111 -0
  192. data/doc/rdoc/files/lib/mongrel/debug_rb.html +1 -1
  193. data/doc/rdoc/files/lib/mongrel/handlers_rb.html +1 -1
  194. data/doc/rdoc/files/lib/mongrel/init_rb.html +1 -1
  195. data/doc/rdoc/files/lib/mongrel/rails_rb.html +2 -1
  196. data/doc/rdoc/files/lib/mongrel/stats_rb.html +1 -1
  197. data/doc/rdoc/files/lib/mongrel/tcphack_rb.html +1 -1
  198. data/doc/rdoc/files/lib/mongrel_rb.html +2 -4
  199. data/doc/rdoc/fr_class_index.html +3 -2
  200. data/doc/rdoc/fr_file_index.html +1 -0
  201. data/doc/rdoc/fr_method_index.html +144 -142
  202. data/ext/http11/http11.c +69 -52
  203. data/ext/http11/http11_parser.c +366 -282
  204. data/ext/http11/http11_parser.h +2 -0
  205. data/ext/http11/http11_parser.rl +192 -0
  206. data/lib/mongrel.rb +127 -433
  207. data/lib/mongrel/cgi.rb +19 -6
  208. data/lib/mongrel/command.rb +15 -3
  209. data/lib/mongrel/configurator.rb +374 -0
  210. data/lib/mongrel/debug.rb +47 -56
  211. data/lib/mongrel/handlers.rb +16 -20
  212. data/lib/mongrel/rails.rb +36 -20
  213. data/lib/mongrel/stats.rb +60 -58
  214. data/test/test_conditional.rb +37 -30
  215. data/test/test_http11.rb +14 -14
  216. data/test/test_stats.rb +2 -2
  217. data/test/test_ws.rb +4 -2
  218. data/tools/rakehelp.rb +4 -4
  219. metadata +262 -260
  220. data/doc/rdoc/classes/Kernel.src/M000020.html +0 -19
  221. data/doc/rdoc/classes/Kernel.src/M000021.html +0 -23
  222. data/doc/rdoc/classes/Mongrel/CGIWrapper.src/M000104.html +0 -27
  223. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000036.html +0 -24
  224. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000037.html +0 -24
  225. data/doc/rdoc/classes/Mongrel/Command/Base.src/M000038.html +0 -18
  226. data/doc/rdoc/classes/Mongrel/Command/Registry.src/M000041.html +0 -50
  227. data/doc/rdoc/classes/Mongrel/Configurator.src/M000112.html +0 -20
  228. data/doc/rdoc/classes/Mongrel/Configurator.src/M000113.html +0 -20
  229. data/doc/rdoc/classes/Mongrel/Configurator.src/M000114.html +0 -23
  230. data/doc/rdoc/classes/Mongrel/Configurator.src/M000118.html +0 -30
  231. data/doc/rdoc/classes/Mongrel/Configurator.src/M000125.html +0 -25
  232. data/doc/rdoc/classes/Mongrel/Configurator.src/M000127.html +0 -35
  233. data/doc/rdoc/classes/Mongrel/Configurator.src/M000128.html +0 -18
  234. data/doc/rdoc/classes/Mongrel/Configurator.src/M000129.html +0 -33
  235. data/doc/rdoc/classes/Mongrel/Configurator.src/M000130.html +0 -18
  236. data/doc/rdoc/classes/Mongrel/DirHandler.src/M000061.html +0 -63
  237. data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000138.html +0 -56
  238. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000087.html +0 -31
  239. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000089.html +0 -20
  240. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000090.html +0 -20
  241. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000091.html +0 -20
  242. data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000092.html +0 -18
  243. data/doc/rdoc/classes/Mongrel/HttpServer.src/M000068.html +0 -50
  244. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000046.html +0 -51
  245. data/doc/rdoc/classes/Mongrel/Rails/RailsHandler.src/M000047.html +0 -23
  246. data/doc/rdoc/classes/Mongrel/StatisticsFilter.src/M000133.html +0 -24
  247. data/doc/rdoc/classes/MongrelDbg.src/M000015.html +0 -19
  248. data/doc/rdoc/classes/ObjectTracker.src/M000013.html +0 -27
  249. data/doc/rdoc/classes/ObjectTracker.src/M000014.html +0 -44
  250. data/doc/rdoc/classes/RequestLog/Objects.src/M000145.html +0 -19
  251. data/doc/rdoc/classes/Stats.src/M000005.html +0 -19
  252. data/doc/rdoc/classes/Stats.src/M000006.html +0 -23
  253. data/doc/rdoc/classes/Stats.src/M000007.html +0 -26
  254. data/doc/rdoc/classes/Stats.src/M000008.html +0 -18
  255. data/doc/rdoc/classes/Stats.src/M000010.html +0 -18
  256. data/doc/rdoc/classes/Stats.src/M000011.html +0 -23
  257. data/doc/rdoc/classes/Stats.src/M000012.html +0 -20
  258. data/lib/http11.so +0 -0
@@ -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
+ }
@@ -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.3".freeze
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=(4 * 1024)
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\nContent-Length: %d\r\nConnection: close\r\n".freeze
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
- HTTP_IF_UNMODIFIED_SINCE="HTTP_IF_UNMODIFIED_SINCE".freeze
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, initial_body, socket, notifier)
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
- clen = params[Const::CONTENT_LENGTH].to_i - initial_body.length
194
- total = clen
197
+ dispatcher.request_begins(params) if dispatcher
195
198
 
196
- if clen > Const::MAX_BODY
197
- @body = Tempfile.new(Const::MONGREL_TMP_BASE)
198
- @body.binmode
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
- begin
204
- @body.write(initial_body)
205
- notifier.request_begins(params) if notifier
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
- clen -= @body.write(@socket.read(clen % Const::CHUNK_SIZE))
209
- notifier.request_progress(params, clen, total) if notifier
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
- while clen > 0 and !@socket.closed?
213
- data = @socket.read(Const::CHUNK_SIZE)
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
- notifier.request_progress(params, clen, total) if notifier
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 unless @socket.closed?
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.rewind
367
- @body.rewind
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=nil)
407
+ def send_status(content_length=@body.length)
372
408
  if not @status_sent
373
- content_length ||= @body.length
374
- write(Const::STATUS_FORMAT % [status, HTTP_STATUS_CODES[@status], content_length])
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. If the
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
- # The presence of ruby-sendfile is determined by @socket.response_to? :sendfile, which means
401
- # that if you have your own sendfile implementation you can use it without changing this function,
402
- # just make sure it follows the ruby-sendfile signature.
403
- def send_file(path)
404
- File.open(path, "rb") do |f|
405
- if @socket.respond_to? :sendfile
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
- write(chunk)
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 unless @socket.closed?
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::REQUEST_URI])
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
- # TODO: Find a faster/better way to carve out the range, preferably without copying.
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
- data << client.readpartial(Const::CHUNK_SIZE)
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
- # ignored
606
+ client.close rescue Object
575
607
  rescue HttpParserError
576
- STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
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 unless client.closed?
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("Timed out thread."))
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 if not @socket.closed?
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