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