passenger 2.0.6 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (497) hide show
  1. data/DEVELOPERS.TXT +10 -4
  2. data/LICENSE +1 -1
  3. data/NEWS +0 -0
  4. data/Rakefile +183 -117
  5. data/benchmark/dispatcher.rb +5 -9
  6. data/bin/passenger-install-apache2-module +52 -18
  7. data/bin/passenger-memory-stats +67 -13
  8. data/bin/passenger-spawn-server +8 -4
  9. data/bin/passenger-status +21 -46
  10. data/bin/passenger-stress-test +5 -5
  11. data/debian/postinst +1 -1
  12. data/doc/ApplicationPool algorithm.txt +180 -128
  13. data/doc/Architectural overview.html +1 -778
  14. data/doc/Security of user switching support.html +1 -643
  15. data/doc/Users guide Apache.html +3127 -0
  16. data/doc/Users guide Nginx.html +1458 -0
  17. data/doc/Users guide.html +1404 -467
  18. data/doc/Users guide.txt +843 -105
  19. data/doc/cxxapi/ApplicationPoolServer_8h-source.html +751 -641
  20. data/doc/cxxapi/ApplicationPool_8h-source.html +168 -171
  21. data/doc/cxxapi/Application_8h-source.html +494 -394
  22. data/doc/cxxapi/Bucket_8h-source.html +21 -15
  23. data/doc/cxxapi/CachedFileStat_8h-source.html +191 -0
  24. data/doc/cxxapi/Configuration_8h-source.html +311 -149
  25. data/doc/cxxapi/DirectoryMapper_8h-source.html +309 -0
  26. data/doc/cxxapi/DummySpawnManager_8h-source.html +3 -4
  27. data/doc/cxxapi/Exceptions_8h-source.html +182 -165
  28. data/doc/cxxapi/FileChecker_8h-source.html +130 -0
  29. data/doc/cxxapi/Hooks_8h-source.html +2 -3
  30. data/doc/cxxapi/Logging_8h-source.html +92 -89
  31. data/doc/cxxapi/MessageChannel_8h-source.html +585 -477
  32. data/doc/cxxapi/PoolOptions_8h-source.html +305 -0
  33. data/doc/cxxapi/SpawnManager_8h-source.html +515 -540
  34. data/doc/cxxapi/StandardApplicationPool_8h-source.html +779 -679
  35. data/doc/cxxapi/SystemTime_8h-source.html +104 -0
  36. data/doc/cxxapi/Utils_8h-source.html +331 -227
  37. data/doc/cxxapi/annotated.html +6 -7
  38. data/doc/cxxapi/classClient-members.html +1 -2
  39. data/doc/cxxapi/classClient.html +1 -2
  40. data/doc/cxxapi/classHooks-members.html +5 -2
  41. data/doc/cxxapi/classHooks.html +112 -2
  42. data/doc/cxxapi/classPassenger_1_1Application-members.html +2 -3
  43. data/doc/cxxapi/classPassenger_1_1Application.html +8 -9
  44. data/doc/cxxapi/classPassenger_1_1ApplicationPool-members.html +4 -4
  45. data/doc/cxxapi/classPassenger_1_1ApplicationPool.html +42 -81
  46. data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer-members.html +1 -2
  47. data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer.html +3 -4
  48. data/doc/cxxapi/classPassenger_1_1ApplicationPool__inherit__graph.png +0 -0
  49. data/doc/cxxapi/classPassenger_1_1Application_1_1Session-members.html +3 -2
  50. data/doc/cxxapi/classPassenger_1_1Application_1_1Session.html +74 -3
  51. data/doc/cxxapi/classPassenger_1_1BusyException-members.html +1 -2
  52. data/doc/cxxapi/classPassenger_1_1BusyException.html +2 -3
  53. data/doc/cxxapi/classPassenger_1_1ConfigurationException-members.html +1 -2
  54. data/doc/cxxapi/classPassenger_1_1ConfigurationException.html +2 -3
  55. data/doc/cxxapi/classPassenger_1_1DirectoryMapper-members.html +38 -0
  56. data/doc/cxxapi/classPassenger_1_1DirectoryMapper.html +256 -0
  57. data/doc/cxxapi/classPassenger_1_1DummySpawnManager-members.html +1 -2
  58. data/doc/cxxapi/classPassenger_1_1DummySpawnManager.html +2 -3
  59. data/doc/cxxapi/{classPassenger_1_1Thread-members.html → classPassenger_1_1FileChecker-members.html} +4 -5
  60. data/doc/cxxapi/classPassenger_1_1FileChecker.html +121 -0
  61. data/doc/cxxapi/classPassenger_1_1FileNotFoundException-members.html +1 -2
  62. data/doc/cxxapi/classPassenger_1_1FileNotFoundException.html +2 -3
  63. data/doc/cxxapi/classPassenger_1_1FileNotFoundException__inherit__graph.png +0 -0
  64. data/doc/cxxapi/classPassenger_1_1FileSystemException-members.html +2 -3
  65. data/doc/cxxapi/classPassenger_1_1FileSystemException.html +2 -3
  66. data/doc/cxxapi/classPassenger_1_1FileSystemException__inherit__graph.png +0 -0
  67. data/doc/cxxapi/classPassenger_1_1IOException-members.html +1 -2
  68. data/doc/cxxapi/classPassenger_1_1IOException.html +2 -3
  69. data/doc/cxxapi/classPassenger_1_1IOException__inherit__graph.png +0 -0
  70. data/doc/cxxapi/classPassenger_1_1MessageChannel-members.html +5 -2
  71. data/doc/cxxapi/classPassenger_1_1MessageChannel.html +155 -5
  72. data/doc/cxxapi/{classboost_1_1this__thread_1_1enable__syscall__interruption-members.html → classPassenger_1_1RuntimeException-members.html} +2 -3
  73. data/doc/cxxapi/{classboost_1_1this__thread_1_1enable__syscall__interruption.html → classPassenger_1_1RuntimeException.html} +10 -8
  74. data/doc/cxxapi/classPassenger_1_1SpawnException-members.html +1 -2
  75. data/doc/cxxapi/classPassenger_1_1SpawnException.html +2 -3
  76. data/doc/cxxapi/classPassenger_1_1SpawnManager-members.html +2 -3
  77. data/doc/cxxapi/classPassenger_1_1SpawnManager.html +15 -56
  78. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool-members.html +5 -4
  79. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool.html +20 -81
  80. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool__inherit__graph.png +0 -0
  81. data/doc/cxxapi/classPassenger_1_1SystemException-members.html +2 -3
  82. data/doc/cxxapi/classPassenger_1_1SystemException.html +9 -10
  83. data/doc/cxxapi/classPassenger_1_1SystemException__inherit__graph.png +0 -0
  84. data/doc/cxxapi/{classboost_1_1this__thread_1_1disable__syscall__interruption-members.html → classPassenger_1_1SystemTime-members.html} +5 -3
  85. data/doc/cxxapi/classPassenger_1_1SystemTime.html +86 -0
  86. data/doc/cxxapi/classPassenger_1_1TempFile-members.html +2 -3
  87. data/doc/cxxapi/classPassenger_1_1TempFile.html +17 -9
  88. data/doc/cxxapi/definitions_8h-source.html +1 -2
  89. data/doc/cxxapi/files.html +6 -3
  90. data/doc/cxxapi/functions.html +98 -35
  91. data/doc/cxxapi/functions_func.html +60 -32
  92. data/doc/cxxapi/functions_type.html +1 -2
  93. data/doc/cxxapi/functions_vars.html +27 -2
  94. data/doc/cxxapi/graph_legend.html +1 -2
  95. data/doc/cxxapi/graph_legend.png +0 -0
  96. data/doc/cxxapi/group__Configuration.html +3 -4
  97. data/doc/cxxapi/group__Configuration.png +0 -0
  98. data/doc/cxxapi/group__Core.html +3 -4
  99. data/doc/cxxapi/group__Core.png +0 -0
  100. data/doc/cxxapi/group__Exceptions.html +4 -2
  101. data/doc/cxxapi/group__Hooks.html +1 -6
  102. data/doc/cxxapi/group__Hooks.png +0 -0
  103. data/doc/cxxapi/group__Support.html +259 -36
  104. data/doc/cxxapi/hierarchy.html +6 -7
  105. data/doc/cxxapi/inherit__graph__0.map +1 -1
  106. data/doc/cxxapi/inherit__graph__0.md5 +1 -1
  107. data/doc/cxxapi/inherit__graph__0.png +0 -0
  108. data/doc/cxxapi/inherit__graph__1.map +1 -1
  109. data/doc/cxxapi/inherit__graph__1.md5 +1 -1
  110. data/doc/cxxapi/inherit__graph__1.png +0 -0
  111. data/doc/cxxapi/inherit__graph__10.map +1 -1
  112. data/doc/cxxapi/inherit__graph__10.md5 +1 -1
  113. data/doc/cxxapi/inherit__graph__10.png +0 -0
  114. data/doc/cxxapi/inherit__graph__11.map +1 -1
  115. data/doc/cxxapi/inherit__graph__11.md5 +1 -1
  116. data/doc/cxxapi/inherit__graph__11.png +0 -0
  117. data/doc/cxxapi/inherit__graph__12.map +2 -1
  118. data/doc/cxxapi/inherit__graph__12.md5 +1 -1
  119. data/doc/cxxapi/inherit__graph__12.png +0 -0
  120. data/doc/cxxapi/inherit__graph__13.map +1 -1
  121. data/doc/cxxapi/inherit__graph__13.md5 +1 -1
  122. data/doc/cxxapi/inherit__graph__13.png +0 -0
  123. data/doc/cxxapi/inherit__graph__14.map +1 -2
  124. data/doc/cxxapi/inherit__graph__14.md5 +1 -1
  125. data/doc/cxxapi/inherit__graph__14.png +0 -0
  126. data/doc/cxxapi/inherit__graph__15.map +1 -1
  127. data/doc/cxxapi/inherit__graph__15.md5 +1 -1
  128. data/doc/cxxapi/inherit__graph__15.png +0 -0
  129. data/doc/cxxapi/inherit__graph__16.map +1 -1
  130. data/doc/cxxapi/inherit__graph__16.md5 +1 -1
  131. data/doc/cxxapi/inherit__graph__16.png +0 -0
  132. data/doc/cxxapi/inherit__graph__17.png +0 -0
  133. data/doc/cxxapi/inherit__graph__18.png +0 -0
  134. data/doc/cxxapi/inherit__graph__19.png +0 -0
  135. data/doc/cxxapi/inherit__graph__2.map +1 -1
  136. data/doc/cxxapi/inherit__graph__2.md5 +1 -1
  137. data/doc/cxxapi/inherit__graph__2.png +0 -0
  138. data/doc/cxxapi/inherit__graph__20.map +1 -1
  139. data/doc/cxxapi/inherit__graph__20.md5 +1 -1
  140. data/doc/cxxapi/inherit__graph__20.png +0 -0
  141. data/doc/cxxapi/inherit__graph__21.map +1 -1
  142. data/doc/cxxapi/inherit__graph__21.md5 +1 -1
  143. data/doc/cxxapi/inherit__graph__21.png +0 -0
  144. data/doc/cxxapi/inherit__graph__3.map +1 -1
  145. data/doc/cxxapi/inherit__graph__3.md5 +1 -1
  146. data/doc/cxxapi/inherit__graph__3.png +0 -0
  147. data/doc/cxxapi/inherit__graph__4.map +1 -1
  148. data/doc/cxxapi/inherit__graph__4.md5 +1 -1
  149. data/doc/cxxapi/inherit__graph__4.png +0 -0
  150. data/doc/cxxapi/inherit__graph__5.map +2 -1
  151. data/doc/cxxapi/inherit__graph__5.md5 +1 -1
  152. data/doc/cxxapi/inherit__graph__5.png +0 -0
  153. data/doc/cxxapi/inherit__graph__6.map +1 -1
  154. data/doc/cxxapi/inherit__graph__6.md5 +1 -1
  155. data/doc/cxxapi/inherit__graph__6.png +0 -0
  156. data/doc/cxxapi/inherit__graph__7.map +1 -1
  157. data/doc/cxxapi/inherit__graph__7.md5 +1 -1
  158. data/doc/cxxapi/inherit__graph__7.png +0 -0
  159. data/doc/cxxapi/inherit__graph__8.map +1 -1
  160. data/doc/cxxapi/inherit__graph__8.md5 +1 -1
  161. data/doc/cxxapi/inherit__graph__8.png +0 -0
  162. data/doc/cxxapi/inherit__graph__9.map +1 -2
  163. data/doc/cxxapi/inherit__graph__9.md5 +1 -1
  164. data/doc/cxxapi/inherit__graph__9.png +0 -0
  165. data/doc/cxxapi/inherits.html +30 -31
  166. data/doc/cxxapi/main.html +1 -2
  167. data/doc/cxxapi/modules.html +1 -2
  168. data/doc/cxxapi/structPassenger_1_1AnythingToString-members.html +1 -2
  169. data/doc/cxxapi/structPassenger_1_1AnythingToString.html +2 -3
  170. data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4-members.html +1 -2
  171. data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4.html +2 -3
  172. data/doc/cxxapi/structPassenger_1_1PoolOptions-members.html +49 -0
  173. data/doc/cxxapi/structPassenger_1_1PoolOptions.html +404 -0
  174. data/doc/cxxapi/tree.html +18 -20
  175. data/doc/images/conservative_spawning.png +0 -0
  176. data/doc/images/conservative_spawning.svg +248 -0
  177. data/doc/images/smart-lv2.png +0 -0
  178. data/doc/images/smart-lv2.svg +320 -0
  179. data/doc/rdoc/classes/ConditionVariable.html +68 -34
  180. data/doc/rdoc/classes/Exception.html +16 -16
  181. data/doc/rdoc/classes/GC.html +9 -9
  182. data/doc/rdoc/classes/IO.html +36 -17
  183. data/doc/rdoc/classes/PhusionPassenger.html +183 -0
  184. data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +511 -0
  185. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer.html +285 -242
  186. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerAlreadyStarted.html +3 -3
  187. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerError.html +3 -3
  188. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerNotStarted.html +3 -3
  189. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/UnknownMessage.html +3 -3
  190. data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +598 -0
  191. data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +140 -0
  192. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess.html +247 -0
  193. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess/Instance.html +138 -0
  194. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AppInitError.html +36 -19
  195. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/Application.html +81 -96
  196. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/ConsoleTextTemplate.html +18 -18
  197. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/FrameworkInitError.html +20 -18
  198. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/HTMLTemplate.html +18 -18
  199. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/InitializationError.html +9 -9
  200. data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +92 -0
  201. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/MessageChannel.html +93 -92
  202. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/NativeSupport.html +55 -25
  203. data/doc/rdoc/classes/PhusionPassenger/Rack.html +91 -0
  204. data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +185 -0
  205. data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +182 -0
  206. data/doc/rdoc/classes/PhusionPassenger/Railz.html +95 -0
  207. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner.html +424 -0
  208. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner/Error.html +98 -0
  209. data/doc/rdoc/classes/PhusionPassenger/Railz/CGIFixed.html +200 -0
  210. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner.html +444 -0
  211. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner/Error.html +98 -0
  212. data/doc/rdoc/classes/PhusionPassenger/Railz/RequestHandler.html +154 -0
  213. data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +408 -0
  214. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/UnknownError.html +13 -13
  215. data/doc/rdoc/classes/PhusionPassenger/Utils.html +687 -0
  216. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/VersionNotFound.html +8 -8
  217. data/doc/rdoc/classes/PhusionPassenger/WSGI.html +89 -0
  218. data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +188 -0
  219. data/doc/rdoc/classes/PlatformInfo.html +663 -159
  220. data/doc/rdoc/classes/RakeExtensions.html +4 -4
  221. data/doc/rdoc/classes/Signal.html +134 -0
  222. data/doc/rdoc/created.rid +1 -1
  223. data/doc/rdoc/files/DEVELOPERS_TXT.html +15 -10
  224. data/doc/rdoc/files/README.html +5 -7
  225. data/doc/rdoc/files/ext/{passenger → phusion_passenger}/native_support_c.html +2 -2
  226. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/abstract_request_handler_rb.html +7 -9
  227. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +120 -0
  228. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/abstract_server_rb.html +7 -10
  229. data/doc/rdoc/files/lib/phusion_passenger/admin_tools/control_process_rb.html +99 -0
  230. data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +92 -0
  231. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/application_rb.html +6 -8
  232. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/console_text_template_rb.html +5 -7
  233. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/constants_rb.html +4 -5
  234. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/dependencies_rb.html +6 -8
  235. data/doc/rdoc/files/lib/phusion_passenger/events_rb.html +116 -0
  236. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/exceptions_rb.html +5 -7
  237. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/html_template_rb.html +5 -7
  238. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/message_channel_rb.html +5 -7
  239. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/platform_info_rb.html +6 -7
  240. data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +123 -0
  241. data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +117 -0
  242. data/doc/rdoc/files/lib/{passenger/utils_rb.html → phusion_passenger/railz/application_spawner_rb.html} +24 -17
  243. data/doc/rdoc/files/lib/phusion_passenger/railz/cgi_fixed_rb.html +126 -0
  244. data/doc/rdoc/files/lib/phusion_passenger/railz/framework_spawner_rb.html +139 -0
  245. data/doc/rdoc/files/lib/phusion_passenger/railz/request_handler_rb.html +118 -0
  246. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/simple_benchmarking_rb.html +5 -7
  247. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/spawn_manager_rb.html +40 -24
  248. data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +169 -0
  249. data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +120 -0
  250. data/doc/rdoc/files/lib/rake/extensions_rb.html +3 -4
  251. data/doc/rdoc/fr_class_index.html +37 -19
  252. data/doc/rdoc/fr_file_index.html +25 -14
  253. data/doc/rdoc/fr_method_index.html +145 -74
  254. data/ext/apache2/Application.h +145 -44
  255. data/ext/apache2/ApplicationPool.h +27 -29
  256. data/ext/apache2/ApplicationPoolServer.h +183 -72
  257. data/ext/apache2/ApplicationPoolServerExecutable.cpp +249 -42
  258. data/ext/apache2/Bucket.cpp +61 -9
  259. data/ext/apache2/Bucket.h +15 -8
  260. data/ext/apache2/CachedFileStat.cpp +114 -0
  261. data/ext/apache2/CachedFileStat.h +169 -0
  262. data/ext/apache2/Configuration.cpp +213 -22
  263. data/ext/apache2/Configuration.h +176 -13
  264. data/ext/apache2/DirectoryMapper.h +287 -0
  265. data/ext/apache2/Exceptions.h +30 -12
  266. data/ext/apache2/FileChecker.h +108 -0
  267. data/ext/apache2/Hooks.cpp +709 -493
  268. data/ext/apache2/LICENSE-CNRI.TXT +15 -0
  269. data/ext/apache2/Logging.h +26 -22
  270. data/ext/apache2/MessageChannel.h +124 -15
  271. data/ext/apache2/PoolOptions.h +283 -0
  272. data/ext/apache2/SpawnManager.h +75 -99
  273. data/ext/apache2/StandardApplicationPool.h +296 -195
  274. data/ext/apache2/SystemTime.cpp +28 -0
  275. data/ext/apache2/SystemTime.h +82 -0
  276. data/ext/apache2/Utils.cpp +172 -18
  277. data/ext/apache2/Utils.h +124 -19
  278. data/ext/boost/cstdint.hpp +4 -2
  279. data/ext/boost/current_function.hpp +67 -0
  280. data/ext/boost/detail/sp_counted_base.hpp +4 -4
  281. data/ext/boost/thread/exceptions.hpp +2 -1
  282. data/ext/boost/thread/pthread/thread.hpp +11 -3
  283. data/ext/boost/thread/pthread/thread_data.hpp +2 -1
  284. data/ext/oxt/backtrace.cpp +172 -0
  285. data/ext/oxt/backtrace.hpp +135 -0
  286. data/ext/oxt/detail/backtrace_disabled.hpp +39 -0
  287. data/ext/oxt/detail/backtrace_enabled.hpp +155 -0
  288. data/ext/oxt/detail/spin_lock_gcc_x86.hpp +82 -0
  289. data/ext/oxt/detail/spin_lock_portable.hpp +38 -0
  290. data/ext/oxt/detail/spin_lock_pthreads.hpp +97 -0
  291. data/ext/oxt/detail/tracable_exception_disabled.hpp +46 -0
  292. data/ext/oxt/detail/tracable_exception_enabled.hpp +48 -0
  293. data/ext/oxt/macros.hpp +58 -0
  294. data/ext/oxt/spin_lock.hpp +55 -0
  295. data/ext/{apache2/System.cpp → oxt/system_calls.cpp} +87 -52
  296. data/ext/oxt/system_calls.hpp +234 -0
  297. data/ext/oxt/thread.cpp +32 -0
  298. data/ext/oxt/thread.hpp +223 -0
  299. data/ext/oxt/tracable_exception.cpp +87 -0
  300. data/ext/oxt/tracable_exception.hpp +35 -0
  301. data/{lib/passenger/constants.rb → ext/phusion_passenger/extconf.rb} +14 -9
  302. data/ext/{passenger → phusion_passenger}/native_support.c +33 -6
  303. data/lib/{passenger → phusion_passenger}/abstract_request_handler.rb +209 -93
  304. data/lib/{passenger → phusion_passenger}/abstract_server.rb +23 -8
  305. data/lib/phusion_passenger/abstract_server_collection.rb +301 -0
  306. data/lib/phusion_passenger/admin_tools.rb +25 -0
  307. data/lib/phusion_passenger/admin_tools/control_process.rb +107 -0
  308. data/lib/{passenger → phusion_passenger}/application.rb +13 -16
  309. data/lib/{passenger → phusion_passenger}/console_text_template.rb +2 -2
  310. data/{ext/passenger/extconf.rb → lib/phusion_passenger/constants.rb} +5 -5
  311. data/lib/{passenger → phusion_passenger}/dependencies.rb +38 -32
  312. data/lib/phusion_passenger/events.rb +45 -0
  313. data/lib/{passenger → phusion_passenger}/exceptions.rb +12 -5
  314. data/lib/{passenger → phusion_passenger}/html_template.rb +2 -2
  315. data/lib/{passenger → phusion_passenger}/message_channel.rb +3 -2
  316. data/lib/phusion_passenger/platform_info.rb +500 -0
  317. data/lib/{passenger → phusion_passenger}/rack/application_spawner.rb +29 -22
  318. data/lib/{passenger → phusion_passenger}/rack/request_handler.rb +14 -9
  319. data/lib/{passenger → phusion_passenger}/railz/application_spawner.rb +94 -74
  320. data/lib/{passenger → phusion_passenger}/railz/cgi_fixed.rb +2 -2
  321. data/lib/{passenger → phusion_passenger}/railz/framework_spawner.rb +86 -98
  322. data/lib/{passenger → phusion_passenger}/railz/request_handler.rb +6 -6
  323. data/lib/{passenger → phusion_passenger}/simple_benchmarking.rb +0 -0
  324. data/lib/{passenger → phusion_passenger}/spawn_manager.rb +136 -128
  325. data/lib/{passenger → phusion_passenger}/templates/apache2_config_snippets.txt.erb +0 -0
  326. data/lib/{passenger → phusion_passenger}/templates/apache_must_be_compiled_with_compatible_mpm.txt.erb +0 -0
  327. data/lib/phusion_passenger/templates/app_exited_during_initialization.html.erb +38 -0
  328. data/lib/{passenger → phusion_passenger}/templates/app_init_error.html.erb +0 -0
  329. data/lib/{passenger → phusion_passenger}/templates/database_error.html.erb +0 -0
  330. data/lib/{passenger → phusion_passenger}/templates/deployment_example.txt.erb +1 -1
  331. data/lib/{passenger → phusion_passenger}/templates/error_layout.css +0 -0
  332. data/lib/{passenger → phusion_passenger}/templates/error_layout.html.erb +0 -0
  333. data/lib/{passenger → phusion_passenger}/templates/framework_init_error.html.erb +0 -0
  334. data/lib/{passenger → phusion_passenger}/templates/general_error.html.erb +0 -0
  335. data/lib/{passenger → phusion_passenger}/templates/invalid_app_root.html.erb +1 -1
  336. data/lib/{passenger → phusion_passenger}/templates/load_error.html.erb +0 -0
  337. data/lib/{passenger → phusion_passenger}/templates/no_write_permission_to_passenger_root.txt.erb +0 -0
  338. data/lib/{passenger → phusion_passenger}/templates/possible_solutions_for_compilation_and_installation_problems.txt.erb +0 -0
  339. data/lib/{passenger → phusion_passenger}/templates/run_installer_as_root.txt.erb +0 -0
  340. data/lib/{passenger → phusion_passenger}/templates/version_not_found.html.erb +0 -0
  341. data/lib/{passenger → phusion_passenger}/templates/welcome.txt.erb +0 -0
  342. data/lib/{passenger → phusion_passenger}/utils.rb +210 -44
  343. data/lib/{passenger → phusion_passenger}/wsgi/application_spawner.rb +18 -15
  344. data/lib/{passenger → phusion_passenger}/wsgi/request_handler.py +7 -1
  345. data/man/passenger-memory-stats.8 +1 -1
  346. data/misc/render_error_pages.rb +1 -1
  347. data/test/ApplicationPoolServerTest.cpp +0 -28
  348. data/test/ApplicationPoolServer_ApplicationPoolTest.cpp +4 -0
  349. data/test/ApplicationPoolTest.cpp +307 -69
  350. data/test/CachedFileStatTest.cpp +262 -0
  351. data/test/FileCheckerTest.cpp +79 -0
  352. data/test/MessageChannelTest.cpp +3 -3
  353. data/test/PoolOptionsTest.cpp +37 -0
  354. data/test/SpawnManagerTest.cpp +4 -4
  355. data/test/StandardApplicationPoolTest.cpp +4 -0
  356. data/test/SystemTimeTest.cpp +37 -0
  357. data/test/UtilsTest.cpp +137 -0
  358. data/test/integration_tests.rb +270 -23
  359. data/test/oxt/backtrace_test.cpp +128 -0
  360. data/test/oxt/oxt_test_main.cpp +25 -0
  361. data/test/oxt/syscall_interruption_test.cpp +50 -0
  362. data/test/ruby/abstract_request_handler_spec.rb +83 -0
  363. data/test/ruby/abstract_server_collection_spec.rb +246 -0
  364. data/test/ruby/application_spec.rb +3 -3
  365. data/test/ruby/message_channel_spec.rb +2 -2
  366. data/test/ruby/rack/application_spawner_spec.rb +3 -5
  367. data/test/ruby/rails/application_spawner_spec.rb +54 -15
  368. data/test/ruby/rails/framework_spawner_spec.rb +6 -8
  369. data/test/ruby/rails/minimal_spawner_spec.rb +29 -0
  370. data/test/ruby/rails/spawner_error_handling_spec.rb +1 -1
  371. data/test/ruby/rails/spawner_privilege_lowering_spec.rb +3 -3
  372. data/test/ruby/spawn_manager_spec.rb +23 -12
  373. data/test/ruby/utils_spec.rb +36 -2
  374. data/test/ruby/wsgi/application_spawner_spec.rb +47 -0
  375. data/test/stub/apache2/httpd.conf.erb +3 -5
  376. data/test/stub/message_channel.rb +2 -2
  377. data/test/stub/message_channel_2.rb +2 -2
  378. data/test/stub/message_channel_3.rb +3 -3
  379. data/test/stub/minimal-railsapp/README +0 -0
  380. data/test/stub/minimal-railsapp/config/application.rb +0 -0
  381. data/test/stub/minimal-railsapp/config/environment.rb +0 -0
  382. data/test/stub/minimal-railsapp/vendor/rails/actionmailer/lib/action_mailer.rb +0 -0
  383. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_controller.rb +0 -0
  384. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_pack.rb +0 -0
  385. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_view.rb +0 -0
  386. data/test/stub/minimal-railsapp/vendor/rails/activerecord/lib/active_record.rb +0 -0
  387. data/test/stub/minimal-railsapp/vendor/rails/activeresource/lib/active_resource.rb +0 -0
  388. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support.rb +0 -0
  389. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support/whiny_nil.rb +0 -0
  390. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/dispatcher.rb +0 -0
  391. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/initializer.rb +0 -0
  392. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/ruby_version_check.rb +0 -0
  393. data/test/stub/rails_apps/foobar/app/controllers/foo_controller.rb +8 -0
  394. data/test/stub/rails_apps/foobar/config/environments/development.rb +1 -2
  395. data/test/stub/rails_apps/mycook/app/controllers/welcome_controller.rb +21 -1
  396. data/test/stub/rails_apps/mycook/sites/some.site/public/uploads.html +26 -0
  397. data/test/stub/rails_apps/mycook/sites/some.site/public/welcome/cached.html +26 -0
  398. data/test/stub/railsapp/app/controllers/application.rb +0 -0
  399. data/test/stub/railsapp/app/controllers/bar_controller_1.rb +0 -0
  400. data/test/stub/railsapp/app/controllers/bar_controller_2.rb +1 -1
  401. data/test/stub/railsapp/app/controllers/foo_controller.rb +4 -0
  402. data/test/stub/railsapp/app/helpers/application_helper.rb +0 -0
  403. data/test/stub/railsapp/config/boot.rb +0 -0
  404. data/test/stub/railsapp/config/database.yml +0 -0
  405. data/test/stub/railsapp/config/environment.rb +0 -0
  406. data/test/stub/railsapp/config/environments/development.rb +0 -0
  407. data/test/stub/railsapp/config/environments/production.rb +0 -0
  408. data/test/stub/railsapp/config/initializers/inflections.rb +0 -0
  409. data/test/stub/railsapp/config/initializers/mime_types.rb +0 -0
  410. data/test/stub/railsapp/config/routes.rb +0 -0
  411. data/test/stub/railsapp/public/useless.txt +0 -0
  412. data/test/stub/spawn_server.rb +3 -4
  413. data/test/stub/wsgi/passenger_wsgi.pyc +0 -0
  414. data/test/support/apache2_controller.rb +57 -7
  415. data/test/support/tut.h +15 -0
  416. data/vendor/README +12 -0
  417. data/vendor/README_FOR_PACKAGERS +1 -0
  418. data/vendor/rack-0.9.1/AUTHORS +8 -0
  419. data/vendor/rack-0.9.1/COPYING +18 -0
  420. data/vendor/rack-0.9.1/ChangeLog +1423 -0
  421. data/vendor/rack-0.9.1/KNOWN-ISSUES +18 -0
  422. data/vendor/rack-0.9.1/README +306 -0
  423. data/vendor/rack-0.9.1/Rakefile +188 -0
  424. data/vendor/rack-0.9.1/SPEC +129 -0
  425. data/vendor/rack-0.9.1/lib/rack.rb +86 -0
  426. data/vendor/rack-0.9.1/lib/rack/adapter/camping.rb +22 -0
  427. data/vendor/rack-0.9.1/lib/rack/auth/abstract/handler.rb +28 -0
  428. data/vendor/rack-0.9.1/lib/rack/auth/abstract/request.rb +37 -0
  429. data/vendor/rack-0.9.1/lib/rack/auth/basic.rb +58 -0
  430. data/vendor/rack-0.9.1/lib/rack/auth/digest/md5.rb +124 -0
  431. data/vendor/rack-0.9.1/lib/rack/auth/digest/nonce.rb +51 -0
  432. data/vendor/rack-0.9.1/lib/rack/auth/digest/params.rb +55 -0
  433. data/vendor/rack-0.9.1/lib/rack/auth/digest/request.rb +40 -0
  434. data/vendor/rack-0.9.1/lib/rack/auth/openid.rb +438 -0
  435. data/vendor/rack-0.9.1/lib/rack/builder.rb +67 -0
  436. data/vendor/rack-0.9.1/lib/rack/cascade.rb +36 -0
  437. data/vendor/rack-0.9.1/lib/rack/commonlogger.rb +61 -0
  438. data/vendor/rack-0.9.1/lib/rack/conditionalget.rb +43 -0
  439. data/vendor/rack-0.9.1/lib/rack/content_length.rb +25 -0
  440. data/vendor/rack-0.9.1/lib/rack/deflater.rb +87 -0
  441. data/vendor/rack-0.9.1/lib/rack/directory.rb +150 -0
  442. data/vendor/rack-0.9.1/lib/rack/file.rb +85 -0
  443. data/vendor/rack-0.9.1/lib/rack/handler.rb +48 -0
  444. data/vendor/rack-0.9.1/lib/rack/handler/cgi.rb +57 -0
  445. data/vendor/rack-0.9.1/lib/rack/handler/evented_mongrel.rb +8 -0
  446. data/vendor/rack-0.9.1/lib/rack/handler/fastcgi.rb +86 -0
  447. data/vendor/rack-0.9.1/lib/rack/handler/lsws.rb +52 -0
  448. data/vendor/rack-0.9.1/lib/rack/handler/mongrel.rb +82 -0
  449. data/vendor/rack-0.9.1/lib/rack/handler/scgi.rb +57 -0
  450. data/vendor/rack-0.9.1/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  451. data/vendor/rack-0.9.1/lib/rack/handler/thin.rb +15 -0
  452. data/vendor/rack-0.9.1/lib/rack/handler/webrick.rb +61 -0
  453. data/vendor/rack-0.9.1/lib/rack/head.rb +19 -0
  454. data/vendor/rack-0.9.1/lib/rack/lint.rb +465 -0
  455. data/vendor/rack-0.9.1/lib/rack/lobster.rb +65 -0
  456. data/vendor/rack-0.9.1/lib/rack/methodoverride.rb +27 -0
  457. data/vendor/rack-0.9.1/lib/rack/mime.rb +204 -0
  458. data/vendor/rack-0.9.1/lib/rack/mock.rb +160 -0
  459. data/vendor/rack-0.9.1/lib/rack/recursive.rb +57 -0
  460. data/vendor/rack-0.9.1/lib/rack/reloader.rb +64 -0
  461. data/vendor/rack-0.9.1/lib/rack/request.rb +218 -0
  462. data/vendor/rack-0.9.1/lib/rack/response.rb +171 -0
  463. data/vendor/rack-0.9.1/lib/rack/session/abstract/id.rb +153 -0
  464. data/vendor/rack-0.9.1/lib/rack/session/cookie.rb +89 -0
  465. data/vendor/rack-0.9.1/lib/rack/session/memcache.rb +97 -0
  466. data/vendor/rack-0.9.1/lib/rack/session/pool.rb +73 -0
  467. data/vendor/rack-0.9.1/lib/rack/showexceptions.rb +348 -0
  468. data/vendor/rack-0.9.1/lib/rack/showstatus.rb +106 -0
  469. data/vendor/rack-0.9.1/lib/rack/static.rb +38 -0
  470. data/vendor/rack-0.9.1/lib/rack/urlmap.rb +48 -0
  471. data/vendor/rack-0.9.1/lib/rack/utils.rb +347 -0
  472. metadata +1197 -1055
  473. data/doc/cxxapi/System_8h-source.html +0 -251
  474. data/doc/cxxapi/classDirectoryMapper-members.html +0 -38
  475. data/doc/cxxapi/classDirectoryMapper.html +0 -203
  476. data/doc/cxxapi/classPassenger_1_1Thread.html +0 -100
  477. data/doc/cxxapi/classboost_1_1this__thread_1_1disable__syscall__interruption.html +0 -46
  478. data/doc/cxxapi/classboost_1_1this__thread_1_1restore__syscall__interruption-members.html +0 -33
  479. data/doc/cxxapi/classboost_1_1this__thread_1_1restore__syscall__interruption.html +0 -44
  480. data/doc/cxxapi/namespacePassenger.html +0 -208
  481. data/doc/cxxapi/namespacePassenger_1_1InterruptableCalls.html +0 -43
  482. data/doc/cxxapi/namespacemembers.html +0 -70
  483. data/doc/cxxapi/namespacemembers_func.html +0 -66
  484. data/doc/cxxapi/namespacemembers_type.html +0 -46
  485. data/doc/cxxapi/namespaces.html +0 -35
  486. data/doc/rdoc/classes/Passenger.html +0 -136
  487. data/doc/rdoc/classes/Passenger/AbstractRequestHandler.html +0 -402
  488. data/doc/rdoc/classes/Passenger/SpawnManager.html +0 -379
  489. data/doc/rdoc/classes/Passenger/Utils.html +0 -578
  490. data/ext/apache2/System.h +0 -228
  491. data/lib/passenger/platform_info.rb +0 -302
  492. data/lib/passenger/templates/app_exited_during_initialization.html.erb +0 -19
  493. data/test/stub/apache2/httpd.conf +0 -75
  494. data/test/stub/rails_apps/foobar/config/environments/test.rb +0 -22
  495. data/test/stub/rails_apps/mycook/config/environments/test.rb +0 -22
  496. data/test/stub/railsapp/config/environments/test.rb +0 -22
  497. data/test/stub/railsapp2/config/environments/test.rb +0 -22
@@ -17,18 +17,6 @@
17
17
  * with this program; if not, write to the Free Software Foundation, Inc.,
18
18
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
19
  */
20
- #include <ap_config.h>
21
- #include <httpd.h>
22
- #include <http_config.h>
23
- #include <http_core.h>
24
- #include <http_request.h>
25
- #include <http_protocol.h>
26
- #include <http_log.h>
27
- #include <util_script.h>
28
- #include <apr_pools.h>
29
- #include <apr_strings.h>
30
- #include <apr_lib.h>
31
-
32
20
  #include <boost/thread.hpp>
33
21
 
34
22
  #include <sys/time.h>
@@ -37,6 +25,7 @@
37
25
  #include <cstdio>
38
26
  #include <unistd.h>
39
27
 
28
+ #include <oxt/macros.hpp>
40
29
  #include "Hooks.h"
41
30
  #include "Bucket.h"
42
31
  #include "Configuration.h"
@@ -44,17 +33,34 @@
44
33
  #include "Logging.h"
45
34
  #include "ApplicationPoolServer.h"
46
35
  #include "MessageChannel.h"
47
- #include "System.h"
36
+ #include "DirectoryMapper.h"
37
+
38
+ /* The Apache/APR headers *must* come after the Boost headers, otherwise
39
+ * compilation will fail on OpenBSD.
40
+ *
41
+ * apr_want.h *must* come after MessageChannel.h, otherwise compilation will
42
+ * fail on platforms on which apr_want.h tries to redefine 'struct iovec'.
43
+ * http://tinyurl.com/b6aatw
44
+ */
45
+ #include <ap_config.h>
46
+ #include <httpd.h>
47
+ #include <http_config.h>
48
+ #include <http_core.h>
49
+ #include <http_request.h>
50
+ #include <http_protocol.h>
51
+ #include <http_log.h>
52
+ #include <util_script.h>
53
+ #include <apr_pools.h>
54
+ #include <apr_strings.h>
55
+ #include <apr_lib.h>
48
56
 
49
57
  using namespace std;
50
58
  using namespace Passenger;
51
59
 
52
60
  extern "C" module AP_MODULE_DECLARE_DATA passenger_module;
53
61
 
62
+
54
63
  #define DEFAULT_RUBY_COMMAND "ruby"
55
- #define DEFAULT_RAILS_ENV "production"
56
- #define DEFAULT_RACK_ENV "production"
57
- #define DEFAULT_WSGI_ENV "production"
58
64
 
59
65
  /**
60
66
  * If the HTTP client sends POST data larger than this value (in bytes),
@@ -65,261 +71,150 @@ extern "C" module AP_MODULE_DECLARE_DATA passenger_module;
65
71
 
66
72
 
67
73
  /**
68
- * Utility class for determining URI-to-Rails/Rack directory mappings.
69
- * Given a URI, it will determine whether that URI belongs to a Rails/Rack
70
- * application, what the base URI of that application is, and what the
71
- * associated 'public' directory is.
74
+ * Apache hook functions, wrapped in a class.
72
75
  *
73
- * @note This class is not thread-safe, but is reentrant.
74
76
  * @ingroup Core
75
77
  */
76
- class DirectoryMapper {
77
- public:
78
- enum ApplicationType {
79
- NONE,
80
- RAILS,
81
- RACK,
82
- WSGI
83
- };
84
-
78
+ class Hooks {
85
79
  private:
86
- DirConfig *config;
87
- request_rec *r;
88
- bool baseURIKnown;
89
- const char *baseURI;
90
- ApplicationType appType;
91
-
92
- inline bool shouldAutoDetectRails() {
93
- return config->autoDetectRails == DirConfig::ENABLED ||
94
- config->autoDetectRails == DirConfig::UNSET;
95
- }
96
-
97
- inline bool shouldAutoDetectRack() {
98
- return config->autoDetectRack == DirConfig::ENABLED ||
99
- config->autoDetectRack == DirConfig::UNSET;
100
- }
101
-
102
- inline bool shouldAutoDetectWSGI() {
103
- return config->autoDetectWSGI == DirConfig::ENABLED ||
104
- config->autoDetectWSGI == DirConfig::UNSET;
105
- }
106
-
107
- public:
108
- /**
109
- * @warning Do not use this object after the destruction of <tt>r</tt> or <tt>config</tt>.
110
- */
111
- DirectoryMapper(request_rec *r, DirConfig *config) {
112
- this->r = r;
113
- this->config = config;
114
- appType = NONE;
115
- baseURIKnown = false;
116
- baseURI = NULL;
117
- }
118
-
119
- /**
120
- * Determine whether the given HTTP request falls under one of the specified
121
- * RailsBaseURIs or RackBaseURIs. If yes, then the first matching base URI will
122
- * be returned.
123
- *
124
- * If Rails/Rack autodetection was enabled in the configuration, and the document
125
- * root seems to be a valid Rails/Rack 'public' folder, then this method will
126
- * return "/".
127
- *
128
- * Otherwise, NULL will be returned.
129
- *
130
- * @throws SystemException An error occured while examening the filesystem.
131
- * @warning The return value may only be used as long as <tt>config</tt>
132
- * hasn't been destroyed.
133
- */
134
- const char *getBaseURI() {
135
- if (baseURIKnown) {
136
- return baseURI;
137
- }
138
-
139
- set<string>::const_iterator it;
140
- const char *uri = r->uri;
141
- size_t uri_len = strlen(uri);
142
-
143
- if (uri_len == 0 || uri[0] != '/') {
144
- baseURIKnown = true;
145
- return NULL;
146
- }
147
-
148
- for (it = config->railsBaseURIs.begin(); it != config->railsBaseURIs.end(); it++) {
149
- const string &base(*it);
150
- if ( base == "/"
151
- || ( uri_len == base.size() && memcmp(uri, base.c_str(), uri_len) == 0 )
152
- || ( uri_len > base.size() && memcmp(uri, base.c_str(), base.size()) == 0
153
- && uri[base.size()] == '/' )
154
- ) {
155
- baseURIKnown = true;
156
- baseURI = base.c_str();
157
- appType = RAILS;
158
- return baseURI;
159
- }
160
- }
161
-
162
- for (it = config->rackBaseURIs.begin(); it != config->rackBaseURIs.end(); it++) {
163
- const string &base(*it);
164
- if ( base == "/"
165
- || ( uri_len == base.size() && memcmp(uri, base.c_str(), uri_len) == 0 )
166
- || ( uri_len > base.size() && memcmp(uri, base.c_str(), base.size()) == 0
167
- && uri[base.size()] == '/' )
168
- ) {
169
- baseURIKnown = true;
170
- baseURI = base.c_str();
171
- appType = RACK;
172
- return baseURI;
173
- }
174
- }
80
+ struct AprDestructable {
81
+ virtual ~AprDestructable() { }
175
82
 
176
- if (shouldAutoDetectRails() && verifyRailsDir(ap_document_root(r))) {
177
- baseURIKnown = true;
178
- baseURI = "/";
179
- appType = RAILS;
180
- return baseURI;
181
- }
182
- if (shouldAutoDetectRack() && verifyRackDir(ap_document_root(r))) {
183
- baseURIKnown = true;
184
- baseURI = "/";
185
- appType = RACK;
186
- return baseURI;
187
- }
188
- if (shouldAutoDetectWSGI() && verifyWSGIDir(ap_document_root(r))) {
189
- baseURIKnown = true;
190
- baseURI = "/";
191
- appType = WSGI;
192
- return baseURI;
83
+ static apr_status_t cleanup(void *p) {
84
+ delete (AprDestructable *) p;
85
+ return APR_SUCCESS;
193
86
  }
194
-
195
- baseURIKnown = true;
196
- return NULL;
197
- }
87
+ };
198
88
 
199
- /**
200
- * Returns the filename of the 'public' directory of the Rails/Rack application
201
- * that's associated with the HTTP request.
202
- *
203
- * Returns an empty string if the document root of the HTTP request
204
- * cannot be determined, or if it isn't a valid folder.
205
- *
206
- * @throws SystemException An error occured while examening the filesystem.
207
- */
208
- string getPublicDirectory() {
209
- if (!baseURIKnown) {
210
- getBaseURI();
211
- }
212
- if (baseURI == NULL) {
213
- return "";
214
- }
89
+ struct RequestNote: public AprDestructable {
90
+ DirectoryMapper mapper;
91
+ DirConfig *config;
92
+ bool forwardToBackend;
93
+ const char *handlerBeforeModRewrite;
94
+ char *filenameBeforeModRewrite;
95
+ apr_filetype_e oldFileType;
96
+ const char *handlerBeforeModAutoIndex;
215
97
 
216
- const char *docRoot = ap_document_root(r);
217
- size_t len = strlen(docRoot);
218
- if (len > 0) {
219
- string path;
220
- if (docRoot[len - 1] == '/') {
221
- path.assign(docRoot, len - 1);
222
- } else {
223
- path.assign(docRoot, len);
224
- }
225
- if (strcmp(baseURI, "/") != 0) {
226
- path.append(baseURI);
227
- }
228
- return path;
229
- } else {
230
- return "";
98
+ RequestNote(const DirectoryMapper &m)
99
+ : mapper(m) {
100
+ forwardToBackend = false;
101
+ filenameBeforeModRewrite = NULL;
231
102
  }
232
- }
103
+ };
233
104
 
234
- /**
235
- * Returns the application type that's associated with the HTTP request.
236
- *
237
- * @throws SystemException An error occured while examening the filesystem.
238
- */
239
- ApplicationType getApplicationType() {
240
- if (!baseURIKnown) {
241
- getBaseURI();
242
- }
243
- return appType;
244
- }
105
+ struct ErrorReport: public AprDestructable {
106
+ virtual int report(request_rec *r) = 0;
107
+ };
245
108
 
246
- /**
247
- * Returns the application type (as a string) that's associated
248
- * with the HTTP request.
249
- *
250
- * @throws SystemException An error occured while examening the filesystem.
251
- */
252
- const char *getApplicationTypeString() {
253
- if (!baseURIKnown) {
254
- getBaseURI();
255
- }
256
- switch (appType) {
257
- case RAILS:
258
- return "rails";
259
- case RACK:
260
- return "rack";
261
- case WSGI:
262
- return "wsgi";
263
- default:
264
- return NULL;
265
- };
266
- }
267
- };
268
-
269
-
270
- /**
271
- * Apache hook functions, wrapped in a class.
272
- *
273
- * @ingroup Core
274
- */
275
- class Hooks {
276
- private:
277
- struct Container {
278
- Application::SessionPtr session;
109
+ struct ReportFileSystemError: public ErrorReport {
110
+ FileSystemException e;
279
111
 
280
- static apr_status_t cleanup(void *p) {
281
- try {
282
- this_thread::disable_interruption di;
283
- this_thread::disable_syscall_interruption dsi;
284
- delete (Container *) p;
285
- } catch (const thread_interrupted &) {
286
- P_TRACE(3, "A system call was interrupted during closing "
287
- "of a session. Apache is probably restarting or "
288
- "shutting down.");
289
- } catch (const exception &e) {
290
- P_TRACE(3, "Exception during closing of a session: " <<
291
- e.what());
112
+ ReportFileSystemError(const FileSystemException &ex): e(ex) { }
113
+
114
+ int report(request_rec *r) {
115
+ ap_set_content_type(r, "text/html; charset=UTF-8");
116
+ ap_rputs("<h1>Passenger error #2</h1>\n", r);
117
+ ap_rputs("An error occurred while trying to access '", r);
118
+ ap_rputs(ap_escape_html(r->pool, e.filename().c_str()), r);
119
+ ap_rputs("': ", r);
120
+ ap_rputs(ap_escape_html(r->pool, e.what()), r);
121
+ if (e.code() == EPERM) {
122
+ ap_rputs("<p>", r);
123
+ ap_rputs("Apache doesn't have read permissions to that file. ", r);
124
+ ap_rputs("Please fix the relevant file permissions.", r);
125
+ ap_rputs("</p>", r);
292
126
  }
293
- return APR_SUCCESS;
127
+ P_ERROR("A filesystem exception occured.\n" <<
128
+ " Message: " << e.what() << "\n" <<
129
+ " Backtrace:\n" << e.backtrace());
130
+ return OK;
294
131
  }
295
132
  };
133
+
134
+ enum Threeway { YES, NO, UNKNOWN };
296
135
 
297
136
  ApplicationPoolServerPtr applicationPoolServer;
298
137
  thread_specific_ptr<ApplicationPoolPtr> threadSpecificApplicationPool;
138
+ Threeway m_hasModRewrite, m_hasModDir, m_hasModAutoIndex;
139
+ CachedMultiFileStat *mstat;
299
140
 
300
- DirConfig *getDirConfig(request_rec *r) {
141
+ inline DirConfig *getDirConfig(request_rec *r) {
301
142
  return (DirConfig *) ap_get_module_config(r->per_dir_config, &passenger_module);
302
143
  }
303
144
 
304
- ServerConfig *getServerConfig(server_rec *s) {
145
+ inline ServerConfig *getServerConfig(server_rec *s) {
305
146
  return (ServerConfig *) ap_get_module_config(s->module_config, &passenger_module);
306
147
  }
307
148
 
149
+ inline RequestNote *getRequestNote(request_rec *r) {
150
+ // The union is needed in order to be compliant with
151
+ // C99/C++'s strict aliasing rules. http://tinyurl.com/g5hgh
152
+ union {
153
+ RequestNote *note;
154
+ void *pointer;
155
+ } u;
156
+ u.note = 0;
157
+ apr_pool_userdata_get(&u.pointer, "Phusion Passenger", r->pool);
158
+ return u.note;
159
+ }
160
+
308
161
  /**
162
+ * Returns a usable ApplicationPool object.
163
+ *
309
164
  * When using the worker MPM and global queuing, deadlocks can occur, for
310
165
  * the same reason described in ApplicationPoolServer::connect(). This
311
166
  * method allows us to avoid this deadlock by making sure that each
312
167
  * thread gets its own connection to the application pool server.
168
+ *
169
+ * It also checks whether the currently cached ApplicationPool object
170
+ * is disconnected (which can happen if an error previously occured).
171
+ * If so, it will reconnect to the ApplicationPool server.
313
172
  */
314
173
  ApplicationPoolPtr getApplicationPool() {
315
174
  ApplicationPoolPtr *pool_ptr = threadSpecificApplicationPool.get();
316
175
  if (pool_ptr == NULL) {
317
176
  pool_ptr = new ApplicationPoolPtr(applicationPoolServer->connect());
318
177
  threadSpecificApplicationPool.reset(pool_ptr);
178
+ } else if (!(*pool_ptr)->connected()) {
179
+ P_DEBUG("Reconnecting to ApplicationPool server");
180
+ *pool_ptr = applicationPoolServer->connect();
319
181
  }
320
182
  return *pool_ptr;
321
183
  }
322
184
 
185
+ bool hasModRewrite() {
186
+ if (m_hasModRewrite == UNKNOWN) {
187
+ if (ap_find_linked_module("mod_rewrite.c")) {
188
+ m_hasModRewrite = YES;
189
+ } else {
190
+ m_hasModRewrite = NO;
191
+ }
192
+ }
193
+ return m_hasModRewrite == YES;
194
+ }
195
+
196
+ bool hasModDir() {
197
+ if (m_hasModDir == UNKNOWN) {
198
+ if (ap_find_linked_module("mod_dir.c")) {
199
+ m_hasModDir = YES;
200
+ } else {
201
+ m_hasModDir = NO;
202
+ }
203
+ }
204
+ return m_hasModDir == YES;
205
+ }
206
+
207
+ bool hasModAutoIndex() {
208
+ if (m_hasModAutoIndex == UNKNOWN) {
209
+ if (ap_find_linked_module("mod_autoindex.c")) {
210
+ m_hasModAutoIndex = YES;
211
+ } else {
212
+ m_hasModAutoIndex = NO;
213
+ }
214
+ }
215
+ return m_hasModAutoIndex == YES;
216
+ }
217
+
323
218
  int reportDocumentRootDeterminationError(request_rec *r) {
324
219
  ap_set_content_type(r, "text/html; charset=UTF-8");
325
220
  ap_rputs("<h1>Passenger error #1</h1>\n", r);
@@ -327,28 +222,322 @@ private:
327
222
  return OK;
328
223
  }
329
224
 
330
- int reportFileSystemError(request_rec *r, const FileSystemException &e) {
331
- ap_set_content_type(r, "text/html; charset=UTF-8");
332
- ap_rputs("<h1>Passenger error #2</h1>\n", r);
333
- ap_rputs("An error occurred while trying to access '", r);
334
- ap_rputs(ap_escape_html(r->pool, e.filename().c_str()), r);
335
- ap_rputs("': ", r);
336
- ap_rputs(ap_escape_html(r->pool, e.what()), r);
337
- if (e.code() == EPERM) {
338
- ap_rputs("<p>", r);
339
- ap_rputs("Apache doesn't have read permissions to that file. ", r);
340
- ap_rputs("Please fix the relevant file permissions.", r);
341
- ap_rputs("</p>", r);
342
- }
343
- return OK;
344
- }
345
-
346
225
  int reportBusyException(request_rec *r) {
347
226
  ap_custom_response(r, HTTP_SERVICE_UNAVAILABLE,
348
227
  "This website is too busy right now. Please try again later.");
349
228
  return HTTP_SERVICE_UNAVAILABLE;
350
229
  }
351
230
 
231
+ /**
232
+ * Gather some information about the request and do some preparations. In this method,
233
+ * it will be determined whether the request URI should be served statically by Apache
234
+ * (in case of static assets or in case there's a page cache file available) or
235
+ * whether it should be forwarded to the backend application.
236
+ *
237
+ * The strategy is as follows:
238
+ *
239
+ * We check whether Phusion Passenger is enabled for this URI (A).
240
+ * If so, then we check whether the following situations are true:
241
+ * (B) There is a backend application defined for this URI.
242
+ * (C) r->filename already exists.
243
+ * (D) There is a page cache file for the URI.
244
+ *
245
+ * - If A is not true, or if B is not true, or if C is true, then won't do anything.
246
+ * Passenger will be disabled during the rest of this request.
247
+ * - If D is true, then we first transform r->filename to the page cache file's
248
+ * filename, and then we let Apache serve it statically.
249
+ * - If D is not true, then we forward the request to the backend application.
250
+ *
251
+ * @pre The (A) condition must be true.
252
+ * @param coreModuleWillBeRun Whether the core.c map_to_storage hook might be called after this.
253
+ * @return Whether the Passenger handler hook method should be run.
254
+ */
255
+ bool prepareRequest(request_rec *r, DirConfig *config, const char *filename, bool coreModuleWillBeRun = false) {
256
+ TRACE_POINT();
257
+ DirectoryMapper mapper(r, config, mstat, config->getStatThrottleRate());
258
+ try {
259
+ if (mapper.getBaseURI() == NULL) {
260
+ // (B) is not true.
261
+ return false;
262
+ }
263
+ } catch (const FileSystemException &e) {
264
+ /* DirectoryMapper tried to examine the filesystem in order
265
+ * to autodetect the application type (e.g. by checking whether
266
+ * environment.rb exists. But something went wrong, probably
267
+ * because of a permission problem. This usually
268
+ * means that the user is trying to deploy an application, but
269
+ * set the wrong permissions on the relevant folders.
270
+ * Later, in the handler hook, we inform the user about this
271
+ * problem so that he can either disable Phusion Passenger's
272
+ * autodetection routines, or fix the permissions.
273
+ */
274
+ apr_pool_userdata_set(new ReportFileSystemError(e),
275
+ "Phusion Passenger: error report",
276
+ ReportFileSystemError::cleanup,
277
+ r->pool);
278
+ return true;
279
+ }
280
+
281
+ /* Save some information for the hook methods that are called later.
282
+ * The existance of this note indicates that the URI belongs to a Phusion
283
+ * Passenger-served application.
284
+ */
285
+ RequestNote *note = new RequestNote(mapper);
286
+ note->config = config;
287
+ apr_pool_userdata_set(note, "Phusion Passenger", RequestNote::cleanup, r->pool);
288
+
289
+ try {
290
+ // (B) is true.
291
+ FileType fileType = getFileType(filename);
292
+ if (fileType == FT_REGULAR) {
293
+ // (C) is true.
294
+ return false;
295
+ }
296
+
297
+ // (C) is not true. Check whether (D) is true.
298
+ char *pageCacheFile;
299
+ /* Only GET requests may hit the page cache. This is
300
+ * important because of REST conventions, e.g.
301
+ * 'POST /foo' maps to 'FooController#create',
302
+ * while 'GET /foo' maps to 'FooController#index'.
303
+ * We wouldn't want our page caching support to interfere
304
+ * with that.
305
+ */
306
+ if (r->method_number == M_GET) {
307
+ if (fileType == FT_DIRECTORY) {
308
+ size_t len;
309
+
310
+ len = strlen(filename);
311
+ if (len > 0 && filename[len - 1] == '/') {
312
+ pageCacheFile = apr_pstrcat(r->pool, filename,
313
+ "index.html", NULL);
314
+ } else {
315
+ pageCacheFile = apr_pstrcat(r->pool, filename,
316
+ ".html", NULL);
317
+ }
318
+ } else {
319
+ pageCacheFile = apr_pstrcat(r->pool, filename,
320
+ ".html", NULL);
321
+ }
322
+ if (!fileExists(pageCacheFile)) {
323
+ pageCacheFile = NULL;
324
+ }
325
+ } else {
326
+ pageCacheFile = NULL;
327
+ }
328
+ if (pageCacheFile != NULL) {
329
+ // (D) is true.
330
+ r->filename = pageCacheFile;
331
+ r->canonical_filename = pageCacheFile;
332
+ if (!coreModuleWillBeRun) {
333
+ r->finfo.filetype = APR_NOFILE;
334
+ ap_set_content_type(r, "text/html");
335
+ ap_directory_walk(r);
336
+ ap_file_walk(r);
337
+ }
338
+ return false;
339
+ } else {
340
+ // (D) is not true.
341
+ note->forwardToBackend = true;
342
+ return true;
343
+ }
344
+ } catch (const FileSystemException &e) {
345
+ /* Something went wrong while accessing the directory in which
346
+ * r->filename lives. We already know that this URI belongs to
347
+ * a backend application, so this error probably means that the
348
+ * user set the wrong permissions for his 'public' folder. We
349
+ * don't let the handler hook run so that Apache can decide how
350
+ * to display the error.
351
+ */
352
+ return false;
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Most of the high-level logic for forwarding a request to a backend application
358
+ * is contained in this method.
359
+ */
360
+ int handleRequest(request_rec *r) {
361
+ /* Check whether an error occured in prepareRequest() that should be reported
362
+ * to the browser.
363
+ */
364
+
365
+ // The union is needed in order to be compliant with
366
+ // C99/C++'s strict aliasing rules. http://tinyurl.com/g5hgh
367
+ union {
368
+ ErrorReport *errorReport;
369
+ void *pointer;
370
+ } u;
371
+
372
+ u.errorReport = 0;
373
+ apr_pool_userdata_get(&u.pointer, "Phusion Passenger: error report", r->pool);
374
+ if (u.errorReport != 0) {
375
+ return u.errorReport->report(r);
376
+ }
377
+
378
+ RequestNote *note = getRequestNote(r);
379
+ if (note == 0 || !note->forwardToBackend) {
380
+ return DECLINED;
381
+ } else if (r->handler != NULL && strcmp(r->handler, "redirect-handler") == 0) {
382
+ // mod_rewrite is at work.
383
+ return DECLINED;
384
+ }
385
+
386
+ TRACE_POINT();
387
+ DirConfig *config = note->config;
388
+ DirectoryMapper &mapper(note->mapper);
389
+
390
+ if (mapper.getPublicDirectory().empty()) {
391
+ return reportDocumentRootDeterminationError(r);
392
+ }
393
+
394
+ int httpStatus = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
395
+ if (httpStatus != OK) {
396
+ return httpStatus;
397
+ }
398
+
399
+ try {
400
+ this_thread::disable_interruption di;
401
+ this_thread::disable_syscall_interruption dsi;
402
+ apr_bucket_brigade *bb;
403
+ apr_bucket *b;
404
+ Application::SessionPtr session;
405
+ bool expectingUploadData;
406
+ shared_ptr<TempFile> uploadData;
407
+
408
+ expectingUploadData = ap_should_client_block(r);
409
+ if (expectingUploadData && atol(lookupHeader(r, "Content-Length"))
410
+ > UPLOAD_ACCELERATION_THRESHOLD) {
411
+ uploadData = receiveRequestBody(r);
412
+ }
413
+
414
+ UPDATE_TRACE_POINT();
415
+ try {
416
+ ServerConfig *sconfig = getServerConfig(r->server);
417
+ string appRoot(canonicalizePath(
418
+ config->getAppRoot(mapper.getPublicDirectory().c_str())
419
+ ));
420
+
421
+ session = getApplicationPool()->get(PoolOptions(
422
+ appRoot,
423
+ true,
424
+ sconfig->getDefaultUser(),
425
+ mapper.getEnvironment(),
426
+ config->getSpawnMethodString(),
427
+ mapper.getApplicationTypeString(),
428
+ config->frameworkSpawnerTimeout,
429
+ config->appSpawnerTimeout,
430
+ config->getMaxRequests(),
431
+ config->getMemoryLimit(),
432
+ config->usingGlobalQueue(),
433
+ config->getStatThrottleRate(),
434
+ config->getRestartDir()
435
+ ));
436
+ P_TRACE(3, "Forwarding " << r->uri << " to PID " << session->getPid());
437
+ } catch (const SpawnException &e) {
438
+ r->status = 500;
439
+ if (e.hasErrorPage()) {
440
+ ap_set_content_type(r, "text/html; charset=utf-8");
441
+ ap_rputs(e.getErrorPage().c_str(), r);
442
+ return OK;
443
+ } else {
444
+ throw;
445
+ }
446
+ } catch (const FileSystemException &e) {
447
+ /* The application root cannot be determined. This could
448
+ * happen if, for example, the user specified 'RailsBaseURI /foo'
449
+ * while there is no filesystem entry called "foo" in the virtual
450
+ * host's document root.
451
+ */
452
+ return ReportFileSystemError(e).report(r);
453
+ } catch (const BusyException &e) {
454
+ return reportBusyException(r);
455
+ }
456
+
457
+ UPDATE_TRACE_POINT();
458
+ session->setReaderTimeout(r->server->timeout / 1000);
459
+ session->setWriterTimeout(r->server->timeout / 1000);
460
+ sendHeaders(r, session, mapper.getBaseURI());
461
+ if (expectingUploadData) {
462
+ if (uploadData != NULL) {
463
+ sendRequestBody(r, session, uploadData);
464
+ uploadData.reset();
465
+ } else {
466
+ sendRequestBody(r, session);
467
+ }
468
+ }
469
+ session->shutdownWriter();
470
+
471
+ UPDATE_TRACE_POINT();
472
+ apr_file_t *readerPipe = NULL;
473
+ int reader = session->getStream();
474
+ pid_t backendPid = session->getPid();
475
+ apr_os_pipe_put(&readerPipe, &reader, r->pool);
476
+ apr_file_pipe_timeout_set(readerPipe, r->server->timeout);
477
+
478
+ bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
479
+ b = passenger_bucket_create(session, readerPipe, r->connection->bucket_alloc);
480
+ session.reset();
481
+ APR_BRIGADE_INSERT_TAIL(bb, b);
482
+
483
+ b = apr_bucket_eos_create(r->connection->bucket_alloc);
484
+ APR_BRIGADE_INSERT_TAIL(bb, b);
485
+
486
+ // I know the size because I read util_script.c's source. :-(
487
+ char backendData[MAX_STRING_LEN];
488
+ int result = ap_scan_script_header_err_brigade(r, bb, backendData);
489
+ if (result == OK) {
490
+ // The API documentation for ap_scan_script_err_brigade() says it
491
+ // returns HTTP_OK on success, but it actually returns OK.
492
+
493
+ // Manually set the Status header because
494
+ // ap_scan_script_header_err_brigade() filters it
495
+ // out. Some broken HTTP clients depend on the
496
+ // Status header for retrieving the HTTP status.
497
+ if (!r->status_line && *r->status_line == '\0') {
498
+ r->status_line = apr_psprintf(r->pool,
499
+ "%d Unknown Status",
500
+ r->status);
501
+ }
502
+ apr_table_setn(r->headers_out, "Status", r->status_line);
503
+
504
+ ap_pass_brigade(r->output_filters, bb);
505
+ return OK;
506
+ } else if (backendData[0] == '\0') {
507
+ P_ERROR("Backend process " << backendPid <<
508
+ " did not return a valid HTTP response. It returned no data.");
509
+ apr_table_setn(r->err_headers_out, "Status", "500 Internal Server Error");
510
+ return HTTP_INTERNAL_SERVER_ERROR;
511
+ } else {
512
+ P_ERROR("Backend process " << backendPid <<
513
+ " did not return a valid HTTP response. It returned: [" <<
514
+ backendData << "]");
515
+ apr_table_setn(r->err_headers_out, "Status", "500 Internal Server Error");
516
+ return HTTP_INTERNAL_SERVER_ERROR;
517
+ }
518
+
519
+ } catch (const thread_interrupted &e) {
520
+ P_TRACE(3, "A system call was interrupted during an HTTP request. Apache "
521
+ "is probably restarting or shutting down. Backtrace:\n" <<
522
+ e.backtrace());
523
+ return HTTP_INTERNAL_SERVER_ERROR;
524
+
525
+ } catch (const tracable_exception &e) {
526
+ P_ERROR("Unexpected error in mod_passenger: " <<
527
+ e.what() << "\n" << " Backtrace:\n" << e.backtrace());
528
+ return HTTP_INTERNAL_SERVER_ERROR;
529
+
530
+ } catch (const exception &e) {
531
+ P_ERROR("Unexpected error in mod_passenger: " <<
532
+ e.what() << "\n" << " Backtrace: not available");
533
+ return HTTP_INTERNAL_SERVER_ERROR;
534
+
535
+ } catch (...) {
536
+ P_ERROR("An unexpected, unknown error occured in mod_passenger.");
537
+ throw;
538
+ }
539
+ }
540
+
352
541
  /**
353
542
  * Convert an HTTP header name to a CGI environment name.
354
543
  */
@@ -391,32 +580,6 @@ private:
391
580
  return lookupName(r->subprocess_env, name);
392
581
  }
393
582
 
394
- // This code is a duplicate of what's in util_script.c. We can't use
395
- // r->unparsed_uri because it gets changed if there was a redirect.
396
- char *originalURI(request_rec *r) {
397
- char *first, *last;
398
-
399
- if (r->the_request == NULL) {
400
- return (char *) apr_pcalloc(r->pool, 1);
401
- }
402
-
403
- first = r->the_request; // use the request-line
404
-
405
- while (*first && !apr_isspace(*first)) {
406
- ++first; // skip over the method
407
- }
408
- while (apr_isspace(*first)) {
409
- ++first; // and the space(s)
410
- }
411
-
412
- last = first;
413
- while (*last && !apr_isspace(*last)) {
414
- ++last; // end at next whitespace
415
- }
416
-
417
- return apr_pstrmemdup(r->pool, first, last - first);
418
- }
419
-
420
583
  void inline addHeader(apr_table_t *table, const char *name, const char *value) {
421
584
  if (name != NULL && value != NULL) {
422
585
  apr_table_addn(table, name, value);
@@ -441,7 +604,7 @@ private:
441
604
  addHeader(headers, "REMOTE_PORT", apr_psprintf(r->pool, "%d", r->connection->remote_addr->port));
442
605
  addHeader(headers, "REMOTE_USER", r->user);
443
606
  addHeader(headers, "REQUEST_METHOD", r->method);
444
- addHeader(headers, "REQUEST_URI", originalURI(r));
607
+ addHeader(headers, "REQUEST_URI", r->unparsed_uri);
445
608
  addHeader(headers, "QUERY_STRING", r->args ? r->args : "");
446
609
  if (strcmp(baseURI, "/") != 0) {
447
610
  addHeader(headers, "SCRIPT_NAME", baseURI);
@@ -518,21 +681,38 @@ private:
518
681
  }
519
682
 
520
683
  shared_ptr<TempFile> receiveRequestBody(request_rec *r) {
684
+ TRACE_POINT();
521
685
  shared_ptr<TempFile> tempFile(new TempFile());
522
686
  char buf[1024 * 32];
523
687
  apr_off_t len;
688
+ size_t total_written = 0;
524
689
 
525
690
  while ((len = ap_get_client_block(r, buf, sizeof(buf))) > 0) {
526
691
  size_t written = 0;
527
692
  do {
528
693
  size_t ret = fwrite(buf, 1, len - written, tempFile->handle);
529
- if (ret == 0) {
530
- throw SystemException("An error occured while writing "
531
- "HTTP upload data to a temporary file",
532
- errno);
694
+ if (ret <= 0 || fflush(tempFile->handle) == EOF) {
695
+ int e = errno;
696
+ string message("An error occured while "
697
+ "buffering HTTP upload data to "
698
+ "a temporary file in ");
699
+ message.append(getTempDir());
700
+ if (e == ENOSPC) {
701
+ message.append(". Please make sure "
702
+ "that this directory has "
703
+ "enough disk space for "
704
+ "buffering file uploads, "
705
+ "or set the 'PassengerTempDir' "
706
+ "directive to a directory "
707
+ "that has enough disk space.");
708
+ throw RuntimeException(message);
709
+ } else {
710
+ throw SystemException(message, e);
711
+ }
533
712
  }
534
713
  written += ret;
535
714
  } while (written < (size_t) len);
715
+ total_written += written;
536
716
  }
537
717
  if (len == -1) {
538
718
  throw IOException("An error occurred while receiving HTTP upload data.");
@@ -544,8 +724,9 @@ private:
544
724
  }
545
725
 
546
726
  void sendRequestBody(request_rec *r, Application::SessionPtr &session, shared_ptr<TempFile> &uploadData) {
727
+ TRACE_POINT();
547
728
  rewind(uploadData->handle);
548
- P_DEBUG("Content-Length = " << lookupHeader(r, "Content-Length"));
729
+ P_DEBUG("File upload: Content-Length = " << lookupHeader(r, "Content-Length"));
549
730
  while (!feof(uploadData->handle)) {
550
731
  char buf[1024 * 32];
551
732
  size_t size;
@@ -573,6 +754,10 @@ public:
573
754
  passenger_config_merge_all_servers(pconf, s);
574
755
  ServerConfig *config = getServerConfig(s);
575
756
  Passenger::setLogLevel(config->logLevel);
757
+ m_hasModRewrite = UNKNOWN;
758
+ m_hasModDir = UNKNOWN;
759
+ m_hasModAutoIndex = UNKNOWN;
760
+ mstat = cached_multi_file_stat_new(1024);
576
761
 
577
762
  P_DEBUG("Initializing Phusion Passenger...");
578
763
  ap_add_version_component(pconf, "Phusion_Passenger/" PASSENGER_VERSION);
@@ -580,6 +765,22 @@ public:
580
765
  const char *ruby, *user;
581
766
  string applicationPoolServerExe, spawnServer;
582
767
 
768
+ if (config->tempDir != NULL) {
769
+ setenv("TMPDIR", config->tempDir, 1);
770
+ } else {
771
+ unsetenv("TMPDIR");
772
+ }
773
+ /*
774
+ * As described in the comment in init_module, upon (re)starting
775
+ * Apache, the Hooks constructor is called twice. We unset
776
+ * PHUSION_PASSENGER_TMP before calling createPassengerTmpDir()
777
+ * because we want the temp directory's name to contain the PID
778
+ * of the process in which the Hooks constructor was called for
779
+ * the second time.
780
+ */
781
+ unsetenv("PHUSION_PASSENGER_TMP");
782
+ createPassengerTempDir();
783
+
583
784
  ruby = (config->ruby != NULL) ? config->ruby : DEFAULT_RUBY_COMMAND;
584
785
  if (config->userSwitching) {
585
786
  user = "";
@@ -623,217 +824,204 @@ public:
623
824
  pool->setMax(config->maxPoolSize);
624
825
  pool->setMaxPerApp(config->maxInstancesPerApp);
625
826
  pool->setMaxIdleTime(config->poolIdleTime);
626
- pool->setUseGlobalQueue(config->getUseGlobalQueue());
627
827
  }
628
828
 
629
- int handleRequest(request_rec *r) {
829
+ ~Hooks() {
830
+ cached_multi_file_stat_free(mstat);
831
+ removeDirTree(getPassengerTempDir().c_str());
832
+ }
833
+
834
+ int prepareRequestWhenInHighPerformanceMode(request_rec *r) {
630
835
  DirConfig *config = getDirConfig(r);
631
- DirectoryMapper mapper(r, config);
632
- if (mapper.getBaseURI() == NULL || r->filename == NULL || fileExists(r->filename)) {
836
+ if (config->isEnabled() && config->highPerformanceMode()) {
837
+ if (prepareRequest(r, config, r->filename, true)) {
838
+ return OK;
839
+ } else {
840
+ return DECLINED;
841
+ }
842
+ } else {
633
843
  return DECLINED;
634
844
  }
635
-
636
- try {
637
- if (mapper.getPublicDirectory().empty()) {
638
- return reportDocumentRootDeterminationError(r);
845
+ }
846
+
847
+ /**
848
+ * This is the hook method for the map_to_storage hook. Apache's final map_to_storage hook
849
+ * method (defined in core.c) will do the following:
850
+ *
851
+ * If r->filename doesn't exist, then it will change the filename to the
852
+ * following form:
853
+ *
854
+ * A/B
855
+ *
856
+ * A is top-most directory that exists. B is the first filename piece that
857
+ * normally follows A. For example, suppose that a website's DocumentRoot
858
+ * is /website, on server http://test.com/. Suppose that there's also a
859
+ * directory /website/images.
860
+ *
861
+ * If we access: then r->filename will be:
862
+ * http://test.com/foo/bar /website/foo
863
+ * http://test.com/foo/bar/baz /website/foo
864
+ * http://test.com/images/foo/bar /website/images/foo
865
+ *
866
+ * We obviously don't want this to happen because it'll interfere with our page
867
+ * cache file search code. So here we save the original value of r->filename so
868
+ * that we can use it later.
869
+ */
870
+ int saveOriginalFilename(request_rec *r) {
871
+ apr_table_set(r->notes, "Phusion Passenger: original filename", r->filename);
872
+ return DECLINED;
873
+ }
874
+
875
+ int prepareRequestWhenNotInHighPerformanceMode(request_rec *r) {
876
+ DirConfig *config = getDirConfig(r);
877
+ if (config->isEnabled()) {
878
+ if (config->highPerformanceMode()) {
879
+ /* Preparations have already been done in the map_to_storage hook.
880
+ * Prevent other modules' fixups hooks from being run.
881
+ */
882
+ return OK;
883
+ } else {
884
+ // core.c's map_to_storage hook will transform the filename, as
885
+ // described by saveOriginalFilename(). Here we restore the
886
+ // original filename.
887
+ const char *filename = apr_table_get(r->notes, "Phusion Passenger: original filename");
888
+ if (filename == NULL) {
889
+ return DECLINED;
890
+ } else {
891
+ prepareRequest(r, config, filename);
892
+ return DECLINED;
893
+ }
639
894
  }
640
- } catch (const FileSystemException &e) {
641
- return reportFileSystemError(r, e);
895
+ } else {
896
+ return DECLINED;
642
897
  }
643
-
644
- int httpStatus = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
645
- if (httpStatus != OK) {
646
- return httpStatus;
898
+ }
899
+
900
+ /**
901
+ * The default .htaccess provided by on Rails on Rails (that is, before version 2.1.0)
902
+ * has the following mod_rewrite rules in it:
903
+ *
904
+ * RewriteEngine on
905
+ * RewriteRule ^$ index.html [QSA]
906
+ * RewriteRule ^([^.]+)$ $1.html [QSA]
907
+ * RewriteCond %{REQUEST_FILENAME} !-f
908
+ * RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
909
+ *
910
+ * As a result, all requests that do not map to a filename will be redirected to
911
+ * dispatch.cgi (or dispatch.fcgi, if the user so specified). We don't want that
912
+ * to happen, so before mod_rewrite applies its rules, we save the current state.
913
+ * After mod_rewrite has applied its rules, undoRedirectionToDispatchCgi() will
914
+ * check whether mod_rewrite attempted to perform an internal redirection to
915
+ * dispatch.(f)cgi. If so, then it will revert the state to the way it was before
916
+ * mod_rewrite took place.
917
+ */
918
+ int saveStateBeforeRewriteRules(request_rec *r) {
919
+ RequestNote *note = getRequestNote(r);
920
+ if (note != 0 && hasModRewrite()) {
921
+ note->handlerBeforeModRewrite = r->handler;
922
+ note->filenameBeforeModRewrite = r->filename;
923
+ }
924
+ return DECLINED;
925
+ }
926
+
927
+ int undoRedirectionToDispatchCgi(request_rec *r) {
928
+ RequestNote *note = getRequestNote(r);
929
+ if (note == 0 || !hasModRewrite()) {
930
+ return DECLINED;
647
931
  }
648
932
 
649
- try {
650
- this_thread::disable_interruption di;
651
- this_thread::disable_syscall_interruption dsi;
652
- apr_bucket_brigade *bb;
653
- apr_bucket *b;
654
- Application::SessionPtr session;
655
- bool expectingUploadData;
656
- shared_ptr<TempFile> uploadData;
657
-
658
- expectingUploadData = ap_should_client_block(r);
659
- if (expectingUploadData && atol(lookupHeader(r, "Content-Length"))
660
- > UPLOAD_ACCELERATION_THRESHOLD) {
661
- uploadData = receiveRequestBody(r);
662
- }
663
-
664
- try {
665
- const char *defaultUser, *environment, *spawnMethod;
666
- ServerConfig *sconfig;
667
-
668
- sconfig = getServerConfig(r->server);
669
- if (sconfig->defaultUser != NULL) {
670
- defaultUser = sconfig->defaultUser;
671
- } else {
672
- defaultUser = "nobody";
673
- }
674
- if (mapper.getApplicationType() == DirectoryMapper::RAILS) {
675
- if (config->railsEnv == NULL) {
676
- environment = DEFAULT_RAILS_ENV;
677
- } else {
678
- environment = config->railsEnv;
679
- }
680
- } else if (mapper.getApplicationType() == DirectoryMapper::RACK) {
681
- if (config->rackEnv == NULL) {
682
- environment = DEFAULT_RACK_ENV;
683
- } else {
684
- environment = config->rackEnv;
685
- }
686
- } else {
687
- environment = DEFAULT_WSGI_ENV;
688
- }
689
- if (config->spawnMethod == DirConfig::SM_CONSERVATIVE) {
690
- spawnMethod = "conservative";
691
- } else {
692
- spawnMethod = "smart";
693
- }
694
-
695
- session = getApplicationPool()->get(
696
- canonicalizePath(mapper.getPublicDirectory() + "/.."),
697
- true, defaultUser, environment, spawnMethod,
698
- mapper.getApplicationTypeString());
699
- P_TRACE(3, "Forwarding " << r->uri << " to PID " << session->getPid());
700
- } catch (const SpawnException &e) {
701
- if (e.hasErrorPage()) {
702
- r->status = 500;
703
- ap_set_content_type(r, "text/html; charset=utf-8");
704
- ap_rputs(e.getErrorPage().c_str(), r);
705
- return OK;
706
- } else {
707
- throw;
708
- }
709
- } catch (const BusyException &e) {
710
- return reportBusyException(r);
711
- }
712
- sendHeaders(r, session, mapper.getBaseURI());
713
- if (expectingUploadData) {
714
- if (uploadData != NULL) {
715
- sendRequestBody(r, session, uploadData);
716
- uploadData.reset();
717
- } else {
718
- sendRequestBody(r, session);
933
+ if (r->handler != NULL && strcmp(r->handler, "redirect-handler") == 0) {
934
+ // Check whether r->filename looks like "redirect:.../dispatch.(f)cgi"
935
+ size_t len = strlen(r->filename);
936
+ // 22 == strlen("redirect:/dispatch.cgi")
937
+ if (len >= 22 && memcmp(r->filename, "redirect:", 9) == 0
938
+ && (memcmp(r->filename + len - 13, "/dispatch.cgi", 13) == 0
939
+ || memcmp(r->filename + len - 14, "/dispatch.fcgi", 14) == 0)) {
940
+ if (note->filenameBeforeModRewrite != NULL) {
941
+ r->filename = note->filenameBeforeModRewrite;
942
+ r->canonical_filename = note->filenameBeforeModRewrite;
943
+ r->handler = note->handlerBeforeModRewrite;
719
944
  }
720
945
  }
721
- session->shutdownWriter();
722
-
723
- apr_file_t *readerPipe = NULL;
724
- int reader = session->getStream();
725
- apr_os_pipe_put(&readerPipe, &reader, r->pool);
726
-
727
- bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
728
- b = passenger_bucket_create(readerPipe, r->connection->bucket_alloc);
729
- APR_BRIGADE_INSERT_TAIL(bb, b);
730
-
731
- b = apr_bucket_eos_create(r->connection->bucket_alloc);
732
- APR_BRIGADE_INSERT_TAIL(bb, b);
733
-
734
- ap_scan_script_header_err_brigade(r, bb, NULL);
735
- ap_pass_brigade(r->output_filters, bb);
736
-
737
- Container *container = new Container();
738
- container->session = session;
739
- apr_pool_cleanup_register(r->pool, container, Container::cleanup, apr_pool_cleanup_null);
740
-
741
- return OK;
742
- } catch (const thread_interrupted &) {
743
- P_TRACE(3, "A system call was interrupted during an HTTP request. Apache "
744
- "is probably restarting or shutting down.");
745
- return HTTP_INTERNAL_SERVER_ERROR;
746
- } catch (const exception &e) {
747
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "*** Unexpected error in Passenger: %s", e.what());
748
- return HTTP_INTERNAL_SERVER_ERROR;
749
946
  }
947
+ return DECLINED;
948
+ }
949
+
950
+ /**
951
+ * mod_dir does the following:
952
+ * If r->filename is a directory, and the URI doesn't end with a slash,
953
+ * then it will redirect the browser to an URI with a slash. For example,
954
+ * if you go to http://foo.com/images, then it will redirect you to
955
+ * http://foo.com/images/.
956
+ *
957
+ * This behavior is undesired. Suppose that there is an ImagesController,
958
+ * and there's also a 'public/images' folder used for storing page cache
959
+ * files. Then we don't want mod_dir to perform the redirection.
960
+ *
961
+ * So in startBlockingModDir(), we temporarily change some fields in the
962
+ * request structure in order to block mod_dir. In endBlockingModDir() we
963
+ * revert those fields to their old value.
964
+ */
965
+ int startBlockingModDir(request_rec *r) {
966
+ RequestNote *note = getRequestNote(r);
967
+ if (note != 0 && hasModDir()) {
968
+ note->oldFileType = r->finfo.filetype;
969
+ r->finfo.filetype = APR_NOFILE;
970
+ }
971
+ return DECLINED;
972
+ }
973
+
974
+ int endBlockingModDir(request_rec *r) {
975
+ RequestNote *note = getRequestNote(r);
976
+ if (note != 0 && hasModDir()) {
977
+ r->finfo.filetype = note->oldFileType;
978
+ }
979
+ return DECLINED;
980
+ }
981
+
982
+ /**
983
+ * mod_autoindex will try to display a directory index for URIs that map to a directory.
984
+ * This is undesired because of page caching semantics. Suppose that a Rails application
985
+ * has an ImagesController which has page caching enabled, and thus also a 'public/images'
986
+ * directory. When the visitor visits /images we'll want the request to be forwarded to
987
+ * the Rails application, instead of displaying a directory index.
988
+ *
989
+ * So in this hook method, we temporarily change some fields in the request structure
990
+ * in order to block mod_autoindex. In endBlockingModAutoIndex(), we restore the request
991
+ * structure to its former state.
992
+ */
993
+ int startBlockingModAutoIndex(request_rec *r) {
994
+ RequestNote *note = getRequestNote(r);
995
+ if (note != 0 && hasModAutoIndex()) {
996
+ note->handlerBeforeModAutoIndex = r->handler;
997
+ r->handler = "";
998
+ }
999
+ return DECLINED;
1000
+ }
1001
+
1002
+ int endBlockingModAutoIndex(request_rec *r) {
1003
+ RequestNote *note = getRequestNote(r);
1004
+ if (note != 0 && hasModAutoIndex()) {
1005
+ r->handler = note->handlerBeforeModAutoIndex;
1006
+ }
1007
+ return DECLINED;
750
1008
  }
751
1009
 
752
- int
753
- mapToStorage(request_rec *r) {
1010
+ int handleRequestWhenInHighPerformanceMode(request_rec *r) {
754
1011
  DirConfig *config = getDirConfig(r);
755
- DirectoryMapper mapper(r, config);
756
- bool forwardToApplication;
757
-
758
- try {
759
- if (mapper.getBaseURI() == NULL || fileExists(r->filename)) {
760
- /*
761
- * fileExists():
762
- * If the file already exists, serve it directly.
763
- * This is for static assets like .css and .js files.
764
- */
765
- forwardToApplication = false;
766
- } else if (r->method_number == M_GET) {
767
- char *html_file;
768
- size_t len;
769
-
770
- len = strlen(r->filename);
771
- if (len > 0 && r->filename[len - 1] == '/') {
772
- html_file = apr_pstrcat(r->pool, r->filename, "index.html", NULL);
773
- } else {
774
- html_file = apr_pstrcat(r->pool, r->filename, ".html", NULL);
775
- }
776
- if (fileExists(html_file)) {
777
- /* If a .html version of the URI exists, serve it directly.
778
- * We're essentially accelerating Rails page caching.
779
- */
780
- r->filename = html_file;
781
- r->canonical_filename = html_file;
782
- forwardToApplication = false;
783
- } else {
784
- forwardToApplication = true;
785
- }
786
- } else {
787
- /*
788
- * Non-GET requests are always forwarded to the application.
789
- * This important because of REST conventions, e.g.
790
- * 'POST /foo' maps to 'FooController.create',
791
- * while 'GET /foo' maps to 'FooController.index'.
792
- * We wouldn't want our page caching support to interfere
793
- * with that.
794
- */
795
- forwardToApplication = true;
796
- }
797
-
798
- if (forwardToApplication) {
799
- /* Apache's default map_to_storage process does strange
800
- * things with the filename. Suppose that the DocumentRoot
801
- * is /website, on server http://test.com/. If we access
802
- * http://test.com/foo/bar, and /website/foo/bar does not
803
- * exist, then Apache will change the filename to
804
- * /website/foo instead of the expected /website/bar.
805
- * We make sure that doesn't happen.
806
- *
807
- * Incidentally, this also disables mod_rewrite. That is a
808
- * good thing because the default Rails .htaccess file
809
- * interferes with Passenger anyway (it delegates requests
810
- * to the CGI script dispatch.cgi).
811
- */
812
- if (config->allowModRewrite != DirConfig::ENABLED
813
- && mapper.getApplicationType() == DirectoryMapper::RAILS) {
814
- /* Of course, we only do that if all of the following
815
- * are true:
816
- * - the config allows us to. Some people have complex
817
- * mod_rewrite rules that they don't want to abandon.
818
- * Those people will have to make sure that the Rails
819
- * app's .htaccess doesn't interfere.
820
- * - this is a Rails application.
821
- */
822
- return OK;
823
- } else if (strcmp(r->uri, mapper.getBaseURI()) == 0) {
824
- /* If the request URI is the application's base URI,
825
- * then we'll want to take over control. Otherwise,
826
- * Apache will show a directory listing. This fixes issue #11.
827
- */
828
- return OK;
829
- } else {
830
- return DECLINED;
831
- }
832
- } else {
833
- return DECLINED;
834
- }
835
- } catch (const FileSystemException &e) {
1012
+ if (config->highPerformanceMode()) {
1013
+ return handleRequest(r);
1014
+ } else {
1015
+ return DECLINED;
1016
+ }
1017
+ }
1018
+
1019
+ int handleRequestWhenNotInHighPerformanceMode(request_rec *r) {
1020
+ DirConfig *config = getDirConfig(r);
1021
+ if (config->highPerformanceMode()) {
836
1022
  return DECLINED;
1023
+ } else {
1024
+ return handleRequest(r);
837
1025
  }
838
1026
  }
839
1027
  };
@@ -900,9 +1088,10 @@ init_module(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *
900
1088
  apr_pool_cleanup_null);
901
1089
  return OK;
902
1090
 
903
- } catch (const thread_interrupted &) {
1091
+ } catch (const thread_interrupted &e) {
904
1092
  P_TRACE(2, "A system call was interrupted during mod_passenger "
905
- "initialization. Apache might be restarting or shutting down.");
1093
+ "initialization. Apache might be restarting or shutting "
1094
+ "down. Backtrace:\n" << e.backtrace());
906
1095
  return DECLINED;
907
1096
 
908
1097
  } catch (const thread_resource_error &e) {
@@ -911,7 +1100,14 @@ init_module(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *
911
1100
 
912
1101
  lim.rlim_cur = 0;
913
1102
  lim.rlim_max = 0;
1103
+
1104
+ /* Solaris does not define the RLIMIT_NPROC limit. Setting it to infinity... */
1105
+ #ifdef RLIMIT_NPROC
914
1106
  getrlimit(RLIMIT_NPROC, &lim);
1107
+ #else
1108
+ lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
1109
+ #endif
1110
+
915
1111
  #ifdef PTHREAD_THREADS_MAX
916
1112
  pthread_threads_max = toString(PTHREAD_THREADS_MAX);
917
1113
  #else
@@ -951,32 +1147,52 @@ init_module(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *
951
1147
  }
952
1148
  }
953
1149
 
954
- static int
955
- handle_request(request_rec *r) {
956
- if (hooks != NULL) {
957
- return hooks->handleRequest(r);
958
- } else {
959
- return DECLINED;
1150
+ #define DEFINE_REQUEST_HOOK(c_name, cpp_name) \
1151
+ static int c_name(request_rec *r) { \
1152
+ if (OXT_LIKELY(hooks != NULL)) { \
1153
+ return hooks->cpp_name(r); \
1154
+ } else { \
1155
+ return DECLINED; \
1156
+ } \
960
1157
  }
961
- }
962
1158
 
963
- static int
964
- map_to_storage(request_rec *r) {
965
- if (hooks != NULL) {
966
- return hooks->mapToStorage(r);
967
- } else {
968
- return DECLINED;
969
- }
970
- }
1159
+ DEFINE_REQUEST_HOOK(prepare_request_when_in_high_performance_mode, prepareRequestWhenInHighPerformanceMode)
1160
+ DEFINE_REQUEST_HOOK(save_original_filename, saveOriginalFilename)
1161
+ DEFINE_REQUEST_HOOK(prepare_request_when_not_in_high_performance_mode, prepareRequestWhenNotInHighPerformanceMode)
1162
+ DEFINE_REQUEST_HOOK(save_state_before_rewrite_rules, saveStateBeforeRewriteRules)
1163
+ DEFINE_REQUEST_HOOK(undo_redirection_to_dispatch_cgi, undoRedirectionToDispatchCgi)
1164
+ DEFINE_REQUEST_HOOK(start_blocking_mod_dir, startBlockingModDir)
1165
+ DEFINE_REQUEST_HOOK(end_blocking_mod_dir, endBlockingModDir)
1166
+ DEFINE_REQUEST_HOOK(start_blocking_mod_autoindex, startBlockingModAutoIndex)
1167
+ DEFINE_REQUEST_HOOK(end_blocking_mod_autoindex, endBlockingModAutoIndex)
1168
+ DEFINE_REQUEST_HOOK(handle_request_when_in_high_performance_mode, handleRequestWhenInHighPerformanceMode)
1169
+ DEFINE_REQUEST_HOOK(handle_request_when_not_in_high_performance_mode, handleRequestWhenNotInHighPerformanceMode)
1170
+
971
1171
 
972
1172
  /**
973
1173
  * Apache hook registration function.
974
1174
  */
975
1175
  void
976
1176
  passenger_register_hooks(apr_pool_t *p) {
1177
+ static const char * const rewrite_module[] = { "mod_rewrite.c", NULL };
1178
+ static const char * const dir_module[] = { "mod_dir.c", NULL };
1179
+ static const char * const autoindex_module[] = { "mod_autoindex.c", NULL };
1180
+
977
1181
  ap_hook_post_config(init_module, NULL, NULL, APR_HOOK_MIDDLE);
978
- ap_hook_map_to_storage(map_to_storage, NULL, NULL, APR_HOOK_FIRST);
979
- ap_hook_handler(handle_request, NULL, NULL, APR_HOOK_MIDDLE);
1182
+
1183
+ ap_hook_map_to_storage(prepare_request_when_in_high_performance_mode, NULL, NULL, APR_HOOK_FIRST);
1184
+ ap_hook_map_to_storage(save_original_filename, NULL, NULL, APR_HOOK_LAST);
1185
+
1186
+ ap_hook_fixups(prepare_request_when_not_in_high_performance_mode, NULL, rewrite_module, APR_HOOK_FIRST);
1187
+ ap_hook_fixups(save_state_before_rewrite_rules, NULL, rewrite_module, APR_HOOK_LAST);
1188
+ ap_hook_fixups(undo_redirection_to_dispatch_cgi, rewrite_module, NULL, APR_HOOK_FIRST);
1189
+ ap_hook_fixups(start_blocking_mod_dir, NULL, dir_module, APR_HOOK_MIDDLE);
1190
+ ap_hook_fixups(end_blocking_mod_dir, dir_module, NULL, APR_HOOK_MIDDLE);
1191
+
1192
+ ap_hook_handler(handle_request_when_in_high_performance_mode, NULL, NULL, APR_HOOK_FIRST);
1193
+ ap_hook_handler(start_blocking_mod_autoindex, NULL, autoindex_module, APR_HOOK_LAST);
1194
+ ap_hook_handler(end_blocking_mod_autoindex, autoindex_module, NULL, APR_HOOK_FIRST);
1195
+ ap_hook_handler(handle_request_when_not_in_high_performance_mode, NULL, NULL, APR_HOOK_LAST);
980
1196
  }
981
1197
 
982
1198
  /**