passenger 3.0.21 → 3.9.1.beta

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 (835) hide show
  1. data/DEVELOPERS.TXT +4 -10
  2. data/NEWS +19 -27
  3. data/Rakefile +20 -19
  4. data/bin/passenger +3 -2
  5. data/bin/passenger-config +35 -5
  6. data/bin/passenger-install-apache2-module +12 -12
  7. data/bin/passenger-install-nginx-module +55 -38
  8. data/bin/passenger-memory-stats +3 -1
  9. data/bin/passenger-status +7 -35
  10. data/build/agents.rb +107 -21
  11. data/build/apache2.rb +11 -46
  12. data/build/basics.rb +61 -9
  13. data/build/common_library.rb +59 -142
  14. data/build/cxx_tests.rb +111 -110
  15. data/build/documentation.rb +33 -0
  16. data/build/misc.rb +30 -12
  17. data/build/nginx.rb +10 -39
  18. data/build/oxt_tests.rb +1 -0
  19. data/build/ruby_extension.rb +1 -5
  20. data/build/test_basics.rb +3 -2
  21. data/dev/copy_boost_headers.rb +2 -1
  22. data/doc/Architectural overview.html +49 -90
  23. data/doc/DebuggingAndStressTesting.txt.md +49 -0
  24. data/doc/Packaging.txt.md +254 -0
  25. data/doc/Security of user switching support.html +35 -66
  26. data/doc/Users guide Apache.html +588 -758
  27. data/doc/Users guide Apache.idmap.txt +253 -136
  28. data/doc/Users guide Apache.txt +154 -109
  29. data/doc/Users guide Nginx.html +544 -660
  30. data/doc/Users guide Nginx.idmap.txt +179 -91
  31. data/doc/Users guide Nginx.txt +192 -118
  32. data/doc/Users guide Standalone.html +65 -48
  33. data/doc/Users guide Standalone.idmap.txt +10 -2
  34. data/doc/Users guide Standalone.txt +4 -0
  35. data/doc/images/glyphicons-halflings-white.png +0 -0
  36. data/doc/images/glyphicons-halflings.png +0 -0
  37. data/doc/images/phusion_banner_small.png +0 -0
  38. data/doc/images/{smart-lv2.png → smart.png} +0 -0
  39. data/doc/images/{smart-lv2.svg → smart.svg} +0 -0
  40. data/doc/templates/bootstrap.min.css +397 -0
  41. data/doc/templates/markdown.html.erb +117 -0
  42. data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +2 -1
  43. data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +26 -48
  44. data/doc/users_guide_snippets/passenger_spawn_method.txt +18 -30
  45. data/doc/users_guide_snippets/support_information.txt +30 -0
  46. data/ext/apache2/Bucket.cpp +9 -26
  47. data/ext/apache2/Bucket.h +13 -10
  48. data/ext/apache2/Configuration.cpp +70 -58
  49. data/ext/apache2/Configuration.hpp +19 -47
  50. data/ext/apache2/DirectoryMapper.h +7 -7
  51. data/ext/apache2/Hooks.cpp +150 -313
  52. data/ext/boost/algorithm/string/detail/case_conv.hpp +4 -2
  53. data/ext/boost/algorithm/string/detail/find_format.hpp +20 -20
  54. data/ext/boost/algorithm/string/detail/find_format_all.hpp +23 -23
  55. data/ext/boost/algorithm/string/detail/find_format_store.hpp +2 -2
  56. data/ext/boost/algorithm/string/detail/formatter.hpp +25 -0
  57. data/ext/boost/algorithm/string/formatter.hpp +20 -3
  58. data/ext/boost/assert.hpp +85 -4
  59. data/ext/boost/bind/bind.hpp +1 -1
  60. data/ext/boost/concept/detail/backward_compatibility.hpp +1 -1
  61. data/ext/boost/concept_check.hpp +140 -64
  62. data/ext/boost/config.hpp +1 -1
  63. data/ext/boost/config/auto_link.hpp +8 -6
  64. data/ext/boost/config/compiler/borland.hpp +12 -2
  65. data/ext/boost/config/compiler/clang.hpp +89 -30
  66. data/ext/boost/config/compiler/codegear.hpp +3 -2
  67. data/ext/boost/config/compiler/common_edg.hpp +7 -5
  68. data/ext/boost/config/compiler/cray.hpp +61 -0
  69. data/ext/boost/config/compiler/digitalmars.hpp +9 -1
  70. data/ext/boost/config/compiler/gcc.hpp +33 -24
  71. data/ext/boost/config/compiler/gcc_xml.hpp +4 -0
  72. data/ext/boost/config/compiler/hp_acc.hpp +12 -1
  73. data/ext/boost/config/compiler/intel.hpp +78 -4
  74. data/ext/boost/config/compiler/metrowerks.hpp +4 -1
  75. data/ext/boost/config/compiler/mpw.hpp +4 -1
  76. data/ext/boost/config/compiler/nvcc.hpp +8 -66
  77. data/ext/boost/config/compiler/pathscale.hpp +80 -0
  78. data/ext/boost/config/compiler/pgi.hpp +5 -5
  79. data/ext/boost/config/compiler/sunpro_cc.hpp +4 -1
  80. data/ext/boost/config/compiler/vacpp.hpp +37 -13
  81. data/ext/boost/config/compiler/visualc.hpp +24 -11
  82. data/ext/boost/config/platform/bsd.hpp +1 -1
  83. data/ext/boost/config/platform/cray.hpp +18 -0
  84. data/ext/boost/config/platform/cygwin.hpp +10 -0
  85. data/ext/boost/config/platform/linux.hpp +5 -0
  86. data/ext/boost/config/platform/macos.hpp +5 -4
  87. data/ext/boost/config/platform/symbian.hpp +5 -2
  88. data/ext/boost/config/platform/vms.hpp +25 -0
  89. data/ext/boost/config/platform/win32.hpp +7 -1
  90. data/ext/boost/config/select_compiler_config.hpp +8 -25
  91. data/ext/boost/config/select_platform_config.hpp +8 -1
  92. data/ext/boost/config/select_stdlib_config.hpp +9 -1
  93. data/ext/boost/config/stdlib/dinkumware.hpp +6 -9
  94. data/ext/boost/config/stdlib/libcomo.hpp +1 -4
  95. data/ext/boost/config/stdlib/libcpp.hpp +36 -0
  96. data/ext/boost/config/stdlib/libstdcpp3.hpp +37 -11
  97. data/ext/boost/config/stdlib/modena.hpp +1 -4
  98. data/ext/boost/config/stdlib/msl.hpp +1 -4
  99. data/ext/boost/config/stdlib/roguewave.hpp +9 -6
  100. data/ext/boost/config/stdlib/sgi.hpp +12 -4
  101. data/ext/boost/config/stdlib/stlport.hpp +11 -4
  102. data/ext/boost/config/stdlib/vacpp.hpp +11 -4
  103. data/ext/boost/config/suffix.hpp +71 -6
  104. data/ext/boost/config/warning_disable.hpp +1 -1
  105. data/ext/boost/container/container_fwd.hpp +177 -0
  106. data/ext/boost/cstdint.hpp +17 -12
  107. data/ext/boost/current_function.hpp +2 -1
  108. data/ext/boost/date_time/c_time.hpp +17 -1
  109. data/ext/boost/date_time/compiler_config.hpp +13 -15
  110. data/ext/boost/date_time/date_formatting.hpp +7 -1
  111. data/ext/boost/date_time/filetime_functions.hpp +4 -4
  112. data/ext/boost/date_time/gregorian_calendar.ipp +2 -2
  113. data/ext/boost/date_time/strings_from_facet.hpp +3 -3
  114. data/ext/boost/date_time/time_facet.hpp +101 -101
  115. data/ext/boost/detail/endian.hpp +4 -2
  116. data/ext/boost/detail/fenv.hpp +74 -0
  117. data/ext/boost/detail/sp_typeinfo.hpp +6 -0
  118. data/ext/boost/exception/detail/clone_current_exception.hpp +47 -0
  119. data/ext/boost/exception/detail/exception_ptr.hpp +194 -122
  120. data/ext/boost/exception/detail/type_info.hpp +3 -3
  121. data/ext/boost/exception/diagnostic_information.hpp +37 -21
  122. data/ext/boost/exception/exception.hpp +21 -1
  123. data/ext/boost/exception/info.hpp +0 -1
  124. data/ext/boost/function.hpp +2 -2
  125. data/ext/boost/function/function_base.hpp +15 -9
  126. data/ext/boost/function/function_template.hpp +26 -48
  127. data/ext/boost/integer_fwd.hpp +0 -16
  128. data/ext/boost/integer_traits.hpp +2 -2
  129. data/ext/boost/iterator.hpp +1 -1
  130. data/ext/boost/iterator/iterator_adaptor.hpp +1 -7
  131. data/ext/boost/iterator/iterator_facade.hpp +13 -13
  132. data/ext/boost/iterator/transform_iterator.hpp +5 -20
  133. data/ext/boost/lexical_cast.hpp +1655 -673
  134. data/ext/boost/math/policies/policy.hpp +982 -0
  135. data/ext/boost/math/special_functions/detail/fp_traits.hpp +570 -0
  136. data/ext/boost/math/special_functions/detail/round_fwd.hpp +80 -0
  137. data/ext/boost/math/special_functions/fpclassify.hpp +533 -0
  138. data/ext/boost/math/special_functions/math_fwd.hpp +1070 -0
  139. data/ext/boost/math/special_functions/sign.hpp +145 -0
  140. data/ext/boost/math/tools/config.hpp +321 -0
  141. data/ext/boost/math/tools/promotion.hpp +150 -0
  142. data/ext/boost/math/tools/real_cast.hpp +29 -0
  143. data/ext/boost/math/tools/user.hpp +97 -0
  144. data/ext/boost/move/move.hpp +1222 -0
  145. data/ext/boost/mpl/O1_size.hpp +40 -0
  146. data/ext/boost/mpl/O1_size_fwd.hpp +24 -0
  147. data/ext/boost/mpl/advance.hpp +76 -0
  148. data/ext/boost/mpl/advance_fwd.hpp +28 -0
  149. data/ext/boost/mpl/at.hpp +52 -0
  150. data/ext/boost/mpl/at_fwd.hpp +24 -0
  151. data/ext/boost/mpl/aux_/O1_size_impl.hpp +87 -0
  152. data/ext/boost/mpl/aux_/advance_backward.hpp +128 -0
  153. data/ext/boost/mpl/aux_/advance_forward.hpp +127 -0
  154. data/ext/boost/mpl/aux_/arithmetic_op.hpp +92 -0
  155. data/ext/boost/mpl/aux_/at_impl.hpp +45 -0
  156. data/ext/boost/mpl/aux_/begin_end_impl.hpp +101 -0
  157. data/ext/boost/mpl/aux_/clear_impl.hpp +35 -0
  158. data/ext/boost/mpl/aux_/comparison_op.hpp +83 -0
  159. data/ext/boost/mpl/aux_/config/forwarding.hpp +27 -0
  160. data/ext/boost/mpl/aux_/config/typeof.hpp +38 -0
  161. data/ext/boost/mpl/aux_/contains_impl.hpp +61 -0
  162. data/ext/boost/mpl/aux_/find_if_pred.hpp +31 -0
  163. data/ext/boost/mpl/aux_/fold_impl.hpp +43 -0
  164. data/ext/boost/mpl/aux_/has_begin.hpp +23 -0
  165. data/ext/boost/mpl/aux_/has_size.hpp +23 -0
  166. data/ext/boost/mpl/aux_/has_tag.hpp +23 -0
  167. data/ext/boost/mpl/aux_/inserter_algorithm.hpp +159 -0
  168. data/ext/boost/mpl/aux_/is_msvc_eti_arg.hpp +64 -0
  169. data/ext/boost/mpl/aux_/iter_apply.hpp +47 -0
  170. data/ext/boost/mpl/aux_/iter_fold_if_impl.hpp +210 -0
  171. data/ext/boost/mpl/aux_/iter_fold_impl.hpp +42 -0
  172. data/ext/boost/mpl/aux_/lambda_spec.hpp +49 -0
  173. data/ext/boost/mpl/aux_/largest_int.hpp +63 -0
  174. data/ext/boost/mpl/aux_/msvc_eti_base.hpp +77 -0
  175. data/ext/boost/mpl/aux_/msvc_type.hpp +62 -0
  176. data/ext/boost/mpl/aux_/numeric_cast_utils.hpp +77 -0
  177. data/ext/boost/mpl/aux_/numeric_op.hpp +315 -0
  178. data/ext/boost/mpl/aux_/preprocessed/gcc/advance_backward.hpp +97 -0
  179. data/ext/boost/mpl/aux_/preprocessed/gcc/advance_forward.hpp +97 -0
  180. data/ext/boost/mpl/aux_/preprocessed/gcc/equal_to.hpp +94 -0
  181. data/ext/boost/mpl/aux_/preprocessed/gcc/fold_impl.hpp +180 -0
  182. data/ext/boost/mpl/aux_/preprocessed/gcc/greater.hpp +94 -0
  183. data/ext/boost/mpl/aux_/preprocessed/gcc/greater_equal.hpp +94 -0
  184. data/ext/boost/mpl/aux_/preprocessed/gcc/iter_fold_if_impl.hpp +133 -0
  185. data/ext/boost/mpl/aux_/preprocessed/gcc/iter_fold_impl.hpp +180 -0
  186. data/ext/boost/mpl/aux_/preprocessed/gcc/less.hpp +94 -0
  187. data/ext/boost/mpl/aux_/preprocessed/gcc/less_equal.hpp +94 -0
  188. data/ext/boost/mpl/aux_/preprocessed/gcc/list.hpp +323 -0
  189. data/ext/boost/mpl/aux_/preprocessed/gcc/minus.hpp +146 -0
  190. data/ext/boost/mpl/aux_/preprocessed/gcc/not_equal_to.hpp +94 -0
  191. data/ext/boost/mpl/aux_/preprocessed/gcc/plus.hpp +146 -0
  192. data/ext/boost/mpl/aux_/preprocessed/gcc/reverse_fold_impl.hpp +231 -0
  193. data/ext/boost/mpl/aux_/preprocessed/gcc/times.hpp +146 -0
  194. data/ext/boost/mpl/aux_/preprocessed/gcc/vector.hpp +323 -0
  195. data/ext/boost/mpl/aux_/preprocessor/default_params.hpp +67 -0
  196. data/ext/boost/mpl/aux_/push_back_impl.hpp +70 -0
  197. data/ext/boost/mpl/aux_/push_front_impl.hpp +71 -0
  198. data/ext/boost/mpl/aux_/reverse_fold_impl.hpp +44 -0
  199. data/ext/boost/mpl/aux_/size_impl.hpp +52 -0
  200. data/ext/boost/mpl/aux_/traits_lambda_spec.hpp +63 -0
  201. data/ext/boost/mpl/back_fwd.hpp +24 -0
  202. data/ext/boost/mpl/back_inserter.hpp +34 -0
  203. data/ext/boost/mpl/begin_end.hpp +57 -0
  204. data/ext/boost/mpl/begin_end_fwd.hpp +27 -0
  205. data/ext/boost/mpl/clear.hpp +39 -0
  206. data/ext/boost/mpl/clear_fwd.hpp +24 -0
  207. data/ext/boost/mpl/comparison.hpp +24 -0
  208. data/ext/boost/mpl/contains.hpp +41 -0
  209. data/ext/boost/mpl/contains_fwd.hpp +25 -0
  210. data/ext/boost/mpl/deref.hpp +41 -0
  211. data/ext/boost/mpl/distance.hpp +78 -0
  212. data/ext/boost/mpl/distance_fwd.hpp +28 -0
  213. data/ext/boost/mpl/empty_fwd.hpp +24 -0
  214. data/ext/boost/mpl/equal_to.hpp +21 -0
  215. data/ext/boost/mpl/find.hpp +38 -0
  216. data/ext/boost/mpl/find_if.hpp +50 -0
  217. data/ext/boost/mpl/fold.hpp +48 -0
  218. data/ext/boost/mpl/front_fwd.hpp +24 -0
  219. data/ext/boost/mpl/front_inserter.hpp +33 -0
  220. data/ext/boost/mpl/greater.hpp +21 -0
  221. data/ext/boost/mpl/greater_equal.hpp +21 -0
  222. data/ext/boost/mpl/inserter.hpp +32 -0
  223. data/ext/boost/mpl/iter_fold.hpp +49 -0
  224. data/ext/boost/mpl/iter_fold_if.hpp +117 -0
  225. data/ext/boost/mpl/iterator_range.hpp +42 -0
  226. data/ext/boost/mpl/iterator_tags.hpp +27 -0
  227. data/ext/boost/mpl/less.hpp +21 -0
  228. data/ext/boost/mpl/less_equal.hpp +21 -0
  229. data/ext/boost/mpl/limits/list.hpp +21 -0
  230. data/ext/boost/mpl/limits/vector.hpp +21 -0
  231. data/ext/boost/mpl/list.hpp +57 -0
  232. data/ext/boost/mpl/list/aux_/O1_size.hpp +33 -0
  233. data/ext/boost/mpl/list/aux_/begin_end.hpp +44 -0
  234. data/ext/boost/mpl/list/aux_/clear.hpp +34 -0
  235. data/ext/boost/mpl/list/aux_/empty.hpp +34 -0
  236. data/ext/boost/mpl/list/aux_/front.hpp +33 -0
  237. data/ext/boost/mpl/list/aux_/include_preprocessed.hpp +35 -0
  238. data/ext/boost/mpl/list/aux_/item.hpp +55 -0
  239. data/ext/boost/mpl/list/aux_/iterator.hpp +76 -0
  240. data/ext/boost/mpl/list/aux_/pop_front.hpp +34 -0
  241. data/ext/boost/mpl/list/aux_/preprocessed/plain/list10.hpp +149 -0
  242. data/ext/boost/mpl/list/aux_/preprocessed/plain/list20.hpp +169 -0
  243. data/ext/boost/mpl/list/aux_/push_back.hpp +36 -0
  244. data/ext/boost/mpl/list/aux_/push_front.hpp +39 -0
  245. data/ext/boost/mpl/list/aux_/size.hpp +33 -0
  246. data/ext/boost/mpl/list/aux_/tag.hpp +24 -0
  247. data/ext/boost/mpl/list/list0.hpp +42 -0
  248. data/ext/boost/mpl/list/list10.hpp +43 -0
  249. data/ext/boost/mpl/list/list20.hpp +43 -0
  250. data/ext/boost/mpl/long.hpp +22 -0
  251. data/ext/boost/mpl/long_fwd.hpp +27 -0
  252. data/ext/boost/mpl/minus.hpp +21 -0
  253. data/ext/boost/mpl/multiplies.hpp +53 -0
  254. data/ext/boost/mpl/negate.hpp +81 -0
  255. data/ext/boost/mpl/not_equal_to.hpp +21 -0
  256. data/ext/boost/mpl/numeric_cast.hpp +41 -0
  257. data/ext/boost/mpl/pair.hpp +70 -0
  258. data/ext/boost/mpl/plus.hpp +21 -0
  259. data/ext/boost/mpl/pop_back_fwd.hpp +24 -0
  260. data/ext/boost/mpl/pop_front_fwd.hpp +24 -0
  261. data/ext/boost/mpl/prior.hpp +19 -0
  262. data/ext/boost/mpl/push_back.hpp +53 -0
  263. data/ext/boost/mpl/push_back_fwd.hpp +24 -0
  264. data/ext/boost/mpl/push_front.hpp +52 -0
  265. data/ext/boost/mpl/push_front_fwd.hpp +24 -0
  266. data/ext/boost/mpl/remove_if.hpp +83 -0
  267. data/ext/boost/mpl/reverse_fold.hpp +50 -0
  268. data/ext/boost/mpl/same_as.hpp +55 -0
  269. data/ext/boost/mpl/sequence_tag.hpp +124 -0
  270. data/ext/boost/mpl/sequence_tag_fwd.hpp +26 -0
  271. data/ext/boost/mpl/size.hpp +42 -0
  272. data/ext/boost/mpl/size_fwd.hpp +24 -0
  273. data/ext/boost/mpl/tag.hpp +52 -0
  274. data/ext/boost/mpl/times.hpp +21 -0
  275. data/ext/boost/mpl/vector.hpp +57 -0
  276. data/ext/boost/mpl/vector/aux_/O1_size.hpp +56 -0
  277. data/ext/boost/mpl/vector/aux_/at.hpp +116 -0
  278. data/ext/boost/mpl/vector/aux_/back.hpp +59 -0
  279. data/ext/boost/mpl/vector/aux_/begin_end.hpp +49 -0
  280. data/ext/boost/mpl/vector/aux_/clear.hpp +55 -0
  281. data/ext/boost/mpl/vector/aux_/empty.hpp +68 -0
  282. data/ext/boost/mpl/vector/aux_/front.hpp +56 -0
  283. data/ext/boost/mpl/vector/aux_/include_preprocessed.hpp +55 -0
  284. data/ext/boost/mpl/vector/aux_/item.hpp +103 -0
  285. data/ext/boost/mpl/vector/aux_/iterator.hpp +130 -0
  286. data/ext/boost/mpl/vector/aux_/pop_back.hpp +40 -0
  287. data/ext/boost/mpl/vector/aux_/pop_front.hpp +40 -0
  288. data/ext/boost/mpl/vector/aux_/preprocessed/plain/vector10.hpp +829 -0
  289. data/ext/boost/mpl/vector/aux_/preprocessed/plain/vector20.hpp +1144 -0
  290. data/ext/boost/mpl/vector/aux_/preprocessed/typeof_based/vector10.hpp +139 -0
  291. data/ext/boost/mpl/vector/aux_/preprocessed/typeof_based/vector20.hpp +159 -0
  292. data/ext/boost/mpl/vector/aux_/push_back.hpp +40 -0
  293. data/ext/boost/mpl/vector/aux_/push_front.hpp +40 -0
  294. data/ext/boost/mpl/vector/aux_/size.hpp +49 -0
  295. data/ext/boost/mpl/vector/aux_/tag.hpp +32 -0
  296. data/ext/boost/mpl/vector/aux_/vector0.hpp +52 -0
  297. data/ext/boost/mpl/vector/vector0.hpp +34 -0
  298. data/ext/boost/mpl/vector/vector10.hpp +45 -0
  299. data/ext/boost/mpl/vector/vector20.hpp +45 -0
  300. data/ext/boost/none.hpp +1 -1
  301. data/ext/boost/numeric/conversion/bounds.hpp +24 -0
  302. data/ext/boost/numeric/conversion/cast.hpp +61 -0
  303. data/ext/boost/numeric/conversion/conversion_traits.hpp +39 -0
  304. data/ext/boost/numeric/conversion/converter.hpp +68 -0
  305. data/ext/boost/numeric/conversion/converter_policies.hpp +186 -0
  306. data/ext/boost/numeric/conversion/detail/bounds.hpp +58 -0
  307. data/ext/boost/numeric/conversion/detail/conversion_traits.hpp +97 -0
  308. data/ext/boost/numeric/conversion/detail/converter.hpp +602 -0
  309. data/ext/boost/numeric/conversion/detail/int_float_mixture.hpp +72 -0
  310. data/ext/boost/numeric/conversion/detail/is_subranged.hpp +234 -0
  311. data/ext/boost/numeric/conversion/detail/meta.hpp +120 -0
  312. data/ext/boost/numeric/conversion/detail/numeric_cast_traits.hpp +138 -0
  313. data/ext/boost/numeric/conversion/detail/preprocessed/numeric_cast_traits_common.hpp +1741 -0
  314. data/ext/boost/numeric/conversion/detail/preprocessed/numeric_cast_traits_long_long.hpp +347 -0
  315. data/ext/boost/numeric/conversion/detail/sign_mixture.hpp +72 -0
  316. data/ext/boost/numeric/conversion/detail/udt_builtin_mixture.hpp +69 -0
  317. data/ext/boost/numeric/conversion/int_float_mixture_enum.hpp +29 -0
  318. data/ext/boost/numeric/conversion/numeric_cast_traits.hpp +31 -0
  319. data/ext/boost/numeric/conversion/sign_mixture_enum.hpp +29 -0
  320. data/ext/boost/numeric/conversion/udt_builtin_mixture_enum.hpp +26 -0
  321. data/ext/boost/operators.hpp +3 -1
  322. data/ext/boost/optional/optional.hpp +146 -79
  323. data/ext/boost/optional/optional_fwd.hpp +8 -1
  324. data/ext/boost/preprocessor/cat.hpp +2 -2
  325. data/ext/boost/preprocessor/config/config.hpp +39 -4
  326. data/ext/boost/preprocessor/facilities/intercept.hpp +277 -0
  327. data/ext/boost/preprocessor/facilities/overload.hpp +25 -0
  328. data/ext/boost/preprocessor/iteration/detail/iter/forward1.hpp +3 -3
  329. data/ext/boost/preprocessor/iteration/iterate.hpp +3 -3
  330. data/ext/boost/preprocessor/punctuation/paren.hpp +23 -0
  331. data/ext/boost/preprocessor/repetition/enum_shifted_params.hpp +44 -0
  332. data/ext/boost/preprocessor/seq/cat.hpp +5 -4
  333. data/ext/boost/preprocessor/seq/size.hpp +0 -1
  334. data/ext/boost/preprocessor/tuple/eat.hpp +83 -34
  335. data/ext/boost/preprocessor/tuple/elem.hpp +161 -355
  336. data/ext/boost/preprocessor/tuple/rem.hpp +110 -48
  337. data/ext/boost/preprocessor/tuple/to_list.hpp +90 -36
  338. data/ext/boost/preprocessor/variadic/elem.hpp +94 -0
  339. data/ext/boost/preprocessor/variadic/size.hpp +30 -0
  340. data/ext/boost/range/begin.hpp +17 -6
  341. data/ext/boost/range/concepts.hpp +37 -2
  342. data/ext/boost/range/detail/safe_bool.hpp +72 -0
  343. data/ext/boost/range/end.hpp +14 -9
  344. data/ext/boost/range/iterator_range_core.hpp +120 -12
  345. data/ext/boost/range/size.hpp +21 -5
  346. data/ext/boost/smart_ptr/detail/shared_count.hpp +88 -0
  347. data/ext/boost/smart_ptr/detail/sp_counted_base.hpp +3 -0
  348. data/ext/boost/smart_ptr/detail/sp_counted_base_aix.hpp +142 -0
  349. data/ext/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp +9 -0
  350. data/ext/boost/smart_ptr/detail/sp_counted_impl.hpp +10 -2
  351. data/ext/boost/smart_ptr/detail/sp_has_sync.hpp +5 -1
  352. data/ext/boost/smart_ptr/detail/spinlock.hpp +4 -1
  353. data/ext/boost/smart_ptr/detail/spinlock_gcc_arm.hpp +20 -3
  354. data/ext/boost/smart_ptr/detail/spinlock_pool.hpp +4 -0
  355. data/ext/boost/smart_ptr/make_shared.hpp +591 -22
  356. data/ext/boost/smart_ptr/shared_array.hpp +29 -1
  357. data/ext/boost/smart_ptr/shared_ptr.hpp +29 -13
  358. data/ext/boost/smart_ptr/weak_ptr.hpp +24 -12
  359. data/ext/boost/src/pthread/once.cpp +9 -7
  360. data/ext/boost/src/pthread/thread.cpp +32 -28
  361. data/ext/boost/src/pthread/timeconv.inl +4 -5
  362. data/ext/boost/src/tss_null.cpp +5 -1
  363. data/ext/boost/static_assert.hpp +8 -2
  364. data/ext/boost/thread/detail/config.hpp +19 -4
  365. data/ext/boost/thread/detail/move.hpp +11 -5
  366. data/ext/boost/thread/detail/thread.hpp +59 -43
  367. data/ext/boost/thread/exceptions.hpp +9 -9
  368. data/ext/boost/thread/future.hpp +150 -82
  369. data/ext/boost/thread/locks.hpp +101 -60
  370. data/ext/boost/thread/pthread/condition_variable.hpp +79 -32
  371. data/ext/boost/thread/pthread/condition_variable_fwd.hpp +12 -3
  372. data/ext/boost/thread/pthread/mutex.hpp +17 -14
  373. data/ext/boost/thread/pthread/once.hpp +3 -4
  374. data/ext/boost/thread/pthread/pthread_mutex_scoped_lock.hpp +12 -2
  375. data/ext/boost/thread/pthread/recursive_mutex.hpp +19 -19
  376. data/ext/boost/thread/pthread/shared_mutex.hpp +13 -13
  377. data/ext/boost/thread/pthread/thread_data.hpp +40 -12
  378. data/ext/boost/thread/thread_time.hpp +5 -0
  379. data/ext/boost/throw_exception.hpp +1 -1
  380. data/ext/boost/token_functions.hpp +34 -10
  381. data/ext/boost/type_traits/add_rvalue_reference.hpp +66 -0
  382. data/ext/boost/type_traits/alignment_of.hpp +1 -1
  383. data/ext/boost/type_traits/detail/bool_trait_def.hpp +26 -3
  384. data/ext/boost/type_traits/detail/bool_trait_undef.hpp +3 -2
  385. data/ext/boost/type_traits/detail/cv_traits_impl.hpp +1 -1
  386. data/ext/boost/type_traits/detail/size_t_trait_def.hpp +6 -4
  387. data/ext/boost/type_traits/detail/type_trait_def.hpp +8 -2
  388. data/ext/boost/type_traits/function_traits.hpp +1 -1
  389. data/ext/boost/type_traits/has_nothrow_constructor.hpp +53 -0
  390. data/ext/boost/type_traits/has_nothrow_copy.hpp +19 -5
  391. data/ext/boost/type_traits/has_trivial_constructor.hpp +51 -0
  392. data/ext/boost/type_traits/has_trivial_copy.hpp +20 -5
  393. data/ext/boost/type_traits/has_trivial_destructor.hpp +12 -5
  394. data/ext/boost/type_traits/intrinsics.hpp +119 -71
  395. data/ext/boost/type_traits/is_const.hpp +5 -5
  396. data/ext/boost/type_traits/is_convertible.hpp +14 -13
  397. data/ext/boost/type_traits/is_enum.hpp +1 -1
  398. data/ext/boost/type_traits/is_floating_point.hpp +27 -0
  399. data/ext/boost/type_traits/is_function.hpp +3 -3
  400. data/ext/boost/type_traits/is_fundamental.hpp +1 -1
  401. data/ext/boost/type_traits/is_member_function_pointer.hpp +2 -2
  402. data/ext/boost/type_traits/is_member_pointer.hpp +2 -2
  403. data/ext/boost/type_traits/is_pod.hpp +11 -3
  404. data/ext/boost/type_traits/is_pointer.hpp +2 -2
  405. data/ext/boost/type_traits/is_signed.hpp +8 -3
  406. data/ext/boost/type_traits/is_union.hpp +8 -0
  407. data/ext/boost/type_traits/is_unsigned.hpp +9 -4
  408. data/ext/boost/type_traits/is_volatile.hpp +5 -5
  409. data/ext/boost/type_traits/remove_cv.hpp +4 -3
  410. data/ext/boost/type_traits/remove_pointer.hpp +51 -2
  411. data/ext/boost/type_traits/remove_reference.hpp +2 -2
  412. data/ext/boost/type_traits/type_with_alignment.hpp +8 -2
  413. data/ext/boost/utility/declval.hpp +44 -0
  414. data/ext/boost/utility/detail/in_place_factory_prefix.hpp +36 -0
  415. data/ext/boost/utility/detail/in_place_factory_suffix.hpp +23 -0
  416. data/ext/boost/utility/detail/result_of_iterate.hpp +142 -0
  417. data/ext/boost/utility/in_place_factory.hpp +88 -0
  418. data/ext/boost/utility/result_of.hpp +103 -0
  419. data/ext/boost/utility/swap.hpp +55 -0
  420. data/ext/common/AnsiColorConstants.h +36 -0
  421. data/ext/common/ApplicationPool2/Common.h +87 -0
  422. data/ext/common/ApplicationPool2/ComponentInfo.h +53 -0
  423. data/ext/common/ApplicationPool2/Group.h +648 -0
  424. data/ext/common/ApplicationPool2/Implementation.cpp +580 -0
  425. data/ext/common/ApplicationPool2/Options.h +576 -0
  426. data/ext/common/ApplicationPool2/PipeWatcher.h +61 -0
  427. data/ext/common/ApplicationPool2/Pool.h +1181 -0
  428. data/ext/common/ApplicationPool2/Process.h +425 -0
  429. data/ext/common/ApplicationPool2/README.md +96 -0
  430. data/ext/common/ApplicationPool2/Session.h +158 -0
  431. data/ext/common/ApplicationPool2/Socket.h +246 -0
  432. data/ext/common/ApplicationPool2/Spawner.h +2212 -0
  433. data/ext/common/ApplicationPool2/SuperGroup.h +749 -0
  434. data/ext/common/BackgroundEventLoop.cpp +129 -0
  435. data/ext/common/BackgroundEventLoop.h +61 -0
  436. data/ext/common/Constants.h +3 -1
  437. data/ext/common/EventedBufferedInput.h +331 -0
  438. data/ext/common/EventedMessageServer.h +17 -34
  439. data/ext/common/EventedServer.h +2 -2
  440. data/ext/common/Exceptions.h +71 -19
  441. data/ext/common/FileDescriptor.h +8 -6
  442. data/ext/common/HttpConstants.h +167 -0
  443. data/ext/common/IniFile.h +24 -0
  444. data/ext/common/Logging.h +62 -849
  445. data/ext/common/MessageReadersWriters.h +19 -0
  446. data/ext/common/MessageServer.h +11 -14
  447. data/ext/common/MultiLibeio.cpp +198 -0
  448. data/ext/common/MultiLibeio.h +67 -0
  449. data/ext/common/ResourceLocator.h +24 -41
  450. data/ext/common/SafeLibev.h +186 -14
  451. data/ext/common/StaticString.h +23 -3
  452. data/ext/common/UnionStation.h +972 -0
  453. data/ext/common/Utils.cpp +168 -24
  454. data/ext/common/Utils.h +25 -3
  455. data/ext/common/Utils/CachedFileStat.hpp +4 -3
  456. data/ext/common/Utils/FileChangeChecker.h +2 -2
  457. data/ext/common/Utils/HashMap.h +50 -0
  458. data/ext/common/Utils/IOUtils.cpp +229 -68
  459. data/ext/common/Utils/IOUtils.h +134 -3
  460. data/ext/common/Utils/Lock.h +28 -0
  461. data/ext/common/Utils/MemoryBarrier.h +52 -0
  462. data/ext/common/Utils/PriorityQueue.h +54 -0
  463. data/ext/common/Utils/ProcessMetricsCollector.h +9 -11
  464. data/ext/common/Utils/ScopeGuard.h +50 -1
  465. data/ext/common/Utils/SmallVector.h +653 -0
  466. data/ext/common/Utils/StrIntUtils.cpp +26 -2
  467. data/ext/common/Utils/StrIntUtils.h +18 -2
  468. data/ext/common/Utils/StringMap.h +125 -8
  469. data/ext/common/Utils/Template.h +212 -0
  470. data/ext/common/Utils/fib.c +699 -0
  471. data/ext/common/Utils/fib.h +101 -0
  472. data/ext/common/Utils/fibpriv.h +67 -0
  473. data/ext/common/Utils/json-forwards.h +249 -0
  474. data/ext/common/Utils/json.h +1855 -0
  475. data/ext/common/Utils/jsoncpp.cpp +4230 -0
  476. data/ext/common/agents/Base.cpp +1126 -0
  477. data/ext/common/{AgentBase.h → agents/Base.h} +5 -1
  478. data/ext/common/agents/EnvPrinter.c +16 -0
  479. data/ext/common/agents/HelperAgent/AgentOptions.h +81 -0
  480. data/ext/common/{HelperAgent → agents/HelperAgent}/BacktracesServer.h +3 -2
  481. data/ext/common/agents/HelperAgent/FileBackedPipe.h +732 -0
  482. data/ext/common/agents/HelperAgent/Main.cpp +497 -0
  483. data/ext/common/agents/HelperAgent/RequestHandler.cpp +283 -0
  484. data/ext/common/agents/HelperAgent/RequestHandler.h +2139 -0
  485. data/ext/common/agents/HelperAgent/ScgiRequestParser.h +451 -0
  486. data/ext/common/{LoggingAgent → agents/LoggingAgent}/DataStoreId.h +1 -1
  487. data/ext/common/{LoggingAgent → agents/LoggingAgent}/FilterSupport.cpp +1 -1
  488. data/ext/common/{LoggingAgent → agents/LoggingAgent}/FilterSupport.h +0 -0
  489. data/ext/common/{LoggingAgent → agents/LoggingAgent}/LoggingServer.h +18 -16
  490. data/ext/common/{LoggingAgent → agents/LoggingAgent}/Main.cpp +15 -13
  491. data/ext/common/{LoggingAgent → agents/LoggingAgent}/RemoteSender.h +6 -6
  492. data/ext/common/agents/SpawnPreparer.cpp +127 -0
  493. data/ext/common/{Watchdog.cpp → agents/Watchdog/Main.cpp} +63 -25
  494. data/ext/libeio/Changes +72 -0
  495. data/ext/{google/COPYING → libeio/LICENSE} +17 -9
  496. data/ext/libeio/Makefile.am +15 -0
  497. data/ext/libeio/Makefile.in +694 -0
  498. data/ext/libeio/aclocal.m4 +9418 -0
  499. data/ext/libeio/autogen.sh +3 -0
  500. data/ext/libeio/config.guess +1501 -0
  501. data/ext/libeio/config.h.in +136 -0
  502. data/ext/libeio/config.sub +1705 -0
  503. data/ext/libeio/configure +14822 -0
  504. data/ext/libeio/configure.ac +22 -0
  505. data/ext/libeio/demo.c +194 -0
  506. data/ext/libeio/ecb.h +457 -0
  507. data/ext/libeio/eio.c +2816 -0
  508. data/ext/libeio/eio.h +411 -0
  509. data/ext/libeio/install-sh +520 -0
  510. data/ext/libeio/libeio.m4 +211 -0
  511. data/ext/libeio/ltmain.sh +9636 -0
  512. data/ext/libeio/missing +376 -0
  513. data/ext/libeio/xthread.h +166 -0
  514. data/ext/libev/Changes +125 -7
  515. data/ext/libev/Makefile.am +5 -3
  516. data/ext/libev/Makefile.in +209 -120
  517. data/ext/libev/aclocal.m4 +6027 -4619
  518. data/ext/libev/autogen.sh +1 -4
  519. data/ext/libev/config.h.in +11 -7
  520. data/ext/libev/configure +7312 -14993
  521. data/ext/libev/configure.ac +12 -5
  522. data/ext/libev/depcomp +630 -0
  523. data/ext/libev/ev++.h +48 -32
  524. data/ext/libev/ev.c +1173 -391
  525. data/ext/libev/ev.h +315 -181
  526. data/ext/libev/ev_epoll.c +66 -15
  527. data/ext/libev/ev_kqueue.c +20 -18
  528. data/ext/libev/ev_poll.c +27 -23
  529. data/ext/libev/ev_port.c +39 -19
  530. data/ext/libev/ev_select.c +23 -17
  531. data/ext/libev/ev_vars.h +25 -8
  532. data/ext/libev/ev_win32.c +6 -6
  533. data/ext/libev/ev_wrap.h +22 -2
  534. data/ext/libev/event.c +18 -17
  535. data/ext/libev/event.h +16 -4
  536. data/ext/libev/libev.m4 +10 -6
  537. data/ext/libev/ltmain.sh +7353 -5811
  538. data/ext/nginx/Configuration.c +74 -42
  539. data/ext/nginx/Configuration.h +3 -5
  540. data/ext/nginx/ContentHandler.c +26 -83
  541. data/ext/nginx/ContentHandler.h +1 -1
  542. data/ext/nginx/config +13 -9
  543. data/ext/nginx/ngx_http_passenger_module.c +3 -7
  544. data/ext/oxt/detail/backtrace_enabled.hpp +5 -102
  545. data/ext/oxt/detail/context.hpp +90 -0
  546. data/ext/oxt/detail/spin_lock_darwin.hpp +4 -0
  547. data/ext/oxt/detail/spin_lock_gcc_x86.hpp +4 -0
  548. data/ext/oxt/detail/spin_lock_pthreads.hpp +14 -0
  549. data/ext/oxt/detail/tracable_exception_enabled.hpp +2 -2
  550. data/ext/oxt/dynamic_thread_group.hpp +27 -1
  551. data/ext/oxt/implementation.cpp +415 -0
  552. data/ext/oxt/{thread.cpp → initialize.hpp} +13 -6
  553. data/ext/oxt/macros.hpp +32 -1
  554. data/ext/oxt/spin_lock.hpp +6 -11
  555. data/ext/oxt/system_calls.cpp +204 -16
  556. data/ext/oxt/system_calls.hpp +85 -45
  557. data/ext/oxt/thread.hpp +13 -117
  558. data/ext/ruby/passenger_native_support.c +82 -237
  559. data/helper-scripts/backtrace-sanitizer.rb +114 -0
  560. data/helper-scripts/classic-rails-loader.rb +135 -0
  561. data/helper-scripts/classic-rails-preloader.rb +161 -0
  562. data/helper-scripts/node-loader.js +314 -0
  563. data/helper-scripts/rack-loader.rb +104 -0
  564. data/helper-scripts/rack-preloader.rb +132 -0
  565. data/helper-scripts/wsgi-loader.py +231 -0
  566. data/helper-scripts/wsgi-preloader.py +1 -0
  567. data/lib/phusion_passenger.rb +159 -61
  568. data/lib/phusion_passenger/abstract_installer.rb +182 -87
  569. data/lib/phusion_passenger/admin_tools/server_instance.rb +25 -19
  570. data/lib/phusion_passenger/analytics_logger.rb +5 -4
  571. data/lib/phusion_passenger/classic_rails/{request_handler.rb → thread_handler_extension.rb} +4 -40
  572. data/lib/phusion_passenger/classic_rails_extensions/init.rb +5 -3
  573. data/lib/phusion_passenger/common_library.rb +441 -0
  574. data/lib/phusion_passenger/console_text_template.rb +4 -16
  575. data/lib/phusion_passenger/constants.rb +1 -8
  576. data/lib/phusion_passenger/debug_logging.rb +5 -2
  577. data/lib/phusion_passenger/dependencies.rb +51 -13
  578. data/lib/phusion_passenger/loader_shared_helpers.rb +318 -0
  579. data/lib/phusion_passenger/message_channel.rb +3 -47
  580. data/lib/phusion_passenger/message_client.rb +2 -2
  581. data/lib/phusion_passenger/native_support.rb +36 -15
  582. data/lib/phusion_passenger/packaging.rb +8 -11
  583. data/lib/phusion_passenger/platform_info.rb +25 -17
  584. data/lib/phusion_passenger/platform_info/apache.rb +10 -7
  585. data/lib/phusion_passenger/platform_info/binary_compatibility.rb +10 -30
  586. data/lib/phusion_passenger/platform_info/compiler.rb +93 -34
  587. data/lib/phusion_passenger/platform_info/ruby.rb +37 -97
  588. data/lib/phusion_passenger/preloader_shared_helpers.rb +121 -0
  589. data/lib/phusion_passenger/public_api.rb +1 -4
  590. data/lib/phusion_passenger/rack/{request_handler.rb → thread_handler_extension.rb} +14 -63
  591. data/lib/phusion_passenger/rails3_extensions/init.rb +9 -8
  592. data/lib/phusion_passenger/request_handler.rb +500 -0
  593. data/lib/phusion_passenger/request_handler/thread_handler.rb +360 -0
  594. data/lib/phusion_passenger/ruby_core_enhancements.rb +142 -0
  595. data/lib/phusion_passenger/standalone/command.rb +36 -15
  596. data/lib/phusion_passenger/standalone/package_runtime_command.rb +16 -8
  597. data/lib/phusion_passenger/standalone/runtime_installer.rb +169 -72
  598. data/lib/phusion_passenger/standalone/start_command.rb +44 -39
  599. data/lib/phusion_passenger/standalone/utils.rb +5 -5
  600. data/lib/phusion_passenger/utils.rb +35 -914
  601. data/lib/phusion_passenger/utils/ansi_colors.rb +59 -0
  602. data/lib/phusion_passenger/utils/file_system_watcher.rb +1 -1
  603. data/lib/phusion_passenger/utils/robust_interruption.rb +134 -0
  604. data/lib/phusion_passenger/utils/tee_input.rb +174 -0
  605. data/lib/phusion_passenger/utils/tmpio.rb +33 -0
  606. data/lib/phusion_passenger/utils/unseekable_socket.rb +6 -0
  607. data/resources/mime.types +5 -1
  608. data/{lib/phusion_passenger/templates → resources}/standalone_default_root/index.html +0 -0
  609. data/{lib/phusion_passenger → resources}/templates/apache2/apache_must_be_compiled_with_compatible_mpm.txt.erb +0 -0
  610. data/{lib/phusion_passenger → resources}/templates/apache2/config_snippets.txt.erb +0 -0
  611. data/{lib/phusion_passenger → resources}/templates/apache2/deployment_example.txt.erb +0 -0
  612. data/{lib/phusion_passenger → resources}/templates/apache2/no_write_permission_to_passenger_root.txt.erb +0 -0
  613. data/{lib/phusion_passenger → resources}/templates/apache2/possible_solutions_for_compilation_and_installation_problems.txt.erb +0 -0
  614. data/{lib/phusion_passenger → resources}/templates/apache2/run_installer_as_root.txt.erb +0 -0
  615. data/{lib/phusion_passenger → resources}/templates/apache2/welcome.txt.erb +0 -0
  616. data/{lib/phusion_passenger → resources}/templates/error_layout.css +6 -0
  617. data/resources/templates/error_layout.html.template +89 -0
  618. data/resources/templates/general_error.html.template +1 -0
  619. data/resources/templates/general_error_with_html.html.template +1 -0
  620. data/{lib/phusion_passenger → resources}/templates/nginx/ask_for_extra_configure_flags.txt.erb +0 -0
  621. data/{lib/phusion_passenger → resources}/templates/nginx/cannot_write_to_dir.txt.erb +0 -0
  622. data/{lib/phusion_passenger → resources}/templates/nginx/config_snippets.txt.erb +0 -0
  623. data/{lib/phusion_passenger → resources}/templates/nginx/config_snippets_inserted.txt.erb +0 -0
  624. data/{lib/phusion_passenger → resources}/templates/nginx/confirm_extra_configure_flags.txt.erb +0 -0
  625. data/{lib/phusion_passenger → resources}/templates/nginx/deployment_example.txt.erb +0 -0
  626. data/resources/templates/nginx/not_available_when_natively_packaged.txt.erb +8 -0
  627. data/{lib/phusion_passenger → resources}/templates/nginx/pcre_could_not_be_downloaded.txt.erb +0 -0
  628. data/{lib/phusion_passenger → resources}/templates/nginx/pcre_could_not_be_extracted.txt.erb +0 -0
  629. data/{lib/phusion_passenger → resources}/templates/nginx/possible_solutions_for_compilation_and_installation_problems.txt.erb +0 -0
  630. data/{lib/phusion_passenger → resources}/templates/nginx/possible_solutions_for_download_and_extraction_problems.txt.erb +0 -0
  631. data/{lib/phusion_passenger → resources}/templates/nginx/query_download_and_install.txt.erb +0 -0
  632. data/{lib/phusion_passenger → resources}/templates/nginx/run_installer_as_root.txt.erb +0 -0
  633. data/{lib/phusion_passenger → resources}/templates/nginx/welcome.txt.erb +0 -0
  634. data/{lib/phusion_passenger → resources}/templates/standalone/cannot_write_to_dir.txt.erb +0 -0
  635. data/{lib/phusion_passenger → resources}/templates/standalone/config.erb +26 -5
  636. data/{lib/phusion_passenger → resources}/templates/standalone/possible_solutions_for_download_and_extraction_problems.txt.erb +0 -0
  637. data/{lib/phusion_passenger → resources}/templates/standalone/run_installer_as_root.txt.erb +0 -0
  638. data/{lib/phusion_passenger → resources}/templates/standalone/welcome.txt.erb +0 -0
  639. data/resources/templates/undisclosed_error.html.template +25 -0
  640. data/test/config.json.example +42 -0
  641. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +86 -0
  642. data/test/cxx/ApplicationPool2/OptionsTest.cpp +44 -0
  643. data/test/cxx/ApplicationPool2/PoolTest.cpp +1234 -0
  644. data/test/cxx/ApplicationPool2/ProcessTest.cpp +131 -0
  645. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +229 -0
  646. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +744 -0
  647. data/test/cxx/BufferedIOTest.cpp +7 -7
  648. data/test/cxx/CxxTestMain.cpp +65 -2
  649. data/test/cxx/FileBackedPipeTest.cpp +626 -0
  650. data/test/cxx/FileChangeCheckerTest.cpp +20 -18
  651. data/test/cxx/FilterSupportTest.cpp +5 -5
  652. data/test/cxx/IOUtilsTest.cpp +11 -4
  653. data/test/cxx/MessageReadersWritersTest.cpp +1 -1
  654. data/test/cxx/MessageServerTest.cpp +31 -30
  655. data/test/cxx/RequestHandlerTest.cpp +777 -0
  656. data/test/cxx/ScgiRequestParserTest.cpp +36 -16
  657. data/test/cxx/ServerInstanceDirTest.cpp +1 -1
  658. data/test/cxx/StringMapTest.cpp +61 -0
  659. data/test/cxx/TemplateTest.cpp +118 -0
  660. data/test/cxx/TestSupport.cpp +25 -68
  661. data/test/cxx/TestSupport.h +81 -41
  662. data/test/cxx/{LoggingTest.cpp → UnionStationTest.cpp} +79 -74
  663. data/test/cxx/UtilsTest.cpp +59 -5
  664. data/test/integration_tests/apache2_tests.rb +2 -2
  665. data/test/integration_tests/nginx_tests.rb +1 -1
  666. data/test/integration_tests/spec_helper.rb +7 -5
  667. data/test/oxt/oxt_test_main.cpp +2 -0
  668. data/test/oxt/syscall_interruption_test.cpp +1 -0
  669. data/test/ruby/classic_rails/loader_spec.rb +48 -0
  670. data/test/ruby/classic_rails/preloader_spec.rb +54 -0
  671. data/test/ruby/rack/loader_spec.rb +62 -0
  672. data/test/ruby/rack/preloader_spec.rb +74 -0
  673. data/test/ruby/{abstract_request_handler_spec.rb → request_handler_spec.rb} +31 -68
  674. data/test/ruby/shared/loader_spec.rb +241 -0
  675. data/test/ruby/shared/rails/analytics_logging_extensions_spec.rb +141 -182
  676. data/test/ruby/shared/ruby_loader_spec.rb +55 -0
  677. data/test/ruby/spec_helper.rb +8 -53
  678. data/test/ruby/utils/file_system_watcher_spec.rb +9 -1
  679. data/test/ruby/utils_spec.rb +10 -683
  680. data/test/stub/rack/config.ru +28 -3
  681. data/test/stub/rack/start.rb +47 -0
  682. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/Rakefile +0 -0
  683. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/controllers/application_controller.rb +0 -2
  684. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/controllers/bar_controller_1.rb +0 -0
  685. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/controllers/bar_controller_2.rb +0 -0
  686. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/controllers/foo_controller.rb +0 -0
  687. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/helpers/application_helper.rb +0 -0
  688. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/boot.rb +0 -0
  689. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/database.yml +3 -3
  690. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/environment.rb +5 -2
  691. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/environments/development.rb +0 -0
  692. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/environments/production.rb +0 -0
  693. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/environments/staging.rb +0 -0
  694. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/initializers/inflections.rb +0 -0
  695. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/initializers/mime_types.rb +0 -0
  696. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/routes.rb +1 -0
  697. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/about +0 -0
  698. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/console +0 -0
  699. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/dbconsole +0 -0
  700. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/destroy +0 -0
  701. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/generate +0 -0
  702. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/performance/benchmarker +0 -0
  703. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/performance/profiler +0 -0
  704. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/performance/request +0 -0
  705. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/plugin +0 -0
  706. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/process/inspector +0 -0
  707. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/process/reaper +0 -0
  708. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/process/spawner +0 -0
  709. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/runner +0 -0
  710. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/server +0 -0
  711. data/test/stub/{rails_apps/3.0/empty → rails3.0}/Gemfile +0 -0
  712. data/test/stub/rails3.0/Gemfile.lock +80 -0
  713. data/test/stub/{rails_apps/3.0/empty → rails3.0}/Rakefile +0 -0
  714. data/test/stub/{rails_apps/3.0/empty → rails3.0}/app/controllers/application_controller.rb +0 -0
  715. data/test/stub/{rails_apps/3.0/empty → rails3.0}/app/helpers/application_helper.rb +0 -0
  716. data/test/stub/{rails_apps/3.0/empty → rails3.0}/app/views/layouts/application.html.erb +0 -0
  717. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config.ru +0 -0
  718. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/application.rb +0 -0
  719. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/boot.rb +0 -0
  720. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/database.yml +0 -0
  721. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/environment.rb +0 -0
  722. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/environments/development.rb +0 -0
  723. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/environments/production.rb +0 -0
  724. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/environments/test.rb +0 -0
  725. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/backtrace_silencers.rb +0 -0
  726. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/inflections.rb +0 -0
  727. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/mime_types.rb +0 -0
  728. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/passenger.rb +0 -0
  729. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/secret_token.rb +0 -0
  730. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/session_store.rb +0 -0
  731. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/locales/en.yml +0 -0
  732. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/routes.rb +0 -0
  733. data/test/stub/{rails_apps/3.0/empty → rails3.0}/db/seeds.rb +0 -0
  734. data/test/stub/{rails_apps/3.0/empty → rails3.0}/doc/README_FOR_APP +0 -0
  735. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/404.html +0 -0
  736. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/422.html +0 -0
  737. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/500.html +0 -0
  738. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/favicon.ico +0 -0
  739. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/index.html +0 -0
  740. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/robots.txt +0 -0
  741. data/test/stub/{rails_apps/3.0/empty → rails3.0}/script/rails +0 -0
  742. data/test/stub/{rails_apps/3.0/empty → rails3.0}/test/performance/browsing_test.rb +0 -0
  743. data/test/stub/{rails_apps/3.0/empty → rails3.0}/test/test_helper.rb +0 -0
  744. data/test/stub/start_error.pl +24 -0
  745. data/test/stub/wsgi/passenger_wsgi.py +71 -3
  746. data/test/support/apache2_controller.rb +2 -2
  747. data/test/support/placebo-preloader.rb +88 -0
  748. data/test/support/test_helper.rb +1 -14
  749. data/test/tut/tut.h +11 -4
  750. metadata +590 -326
  751. data.tar.gz.asc +0 -12
  752. data/PACKAGING.TXT +0 -25
  753. data/build/config.rb +0 -46
  754. data/ext/apache2/HelperAgent.cpp +0 -364
  755. data/ext/boost/call_traits.hpp +0 -24
  756. data/ext/boost/detail/call_traits.hpp +0 -164
  757. data/ext/common/AbstractSpawnManager.h +0 -110
  758. data/ext/common/AgentBase.cpp +0 -432
  759. data/ext/common/ApplicationPool/Client.h +0 -788
  760. data/ext/common/ApplicationPool/Interface.h +0 -295
  761. data/ext/common/ApplicationPool/Pool.h +0 -1327
  762. data/ext/common/ApplicationPool/Server.h +0 -479
  763. data/ext/common/MessageChannel.h +0 -494
  764. data/ext/common/PoolOptions.h +0 -518
  765. data/ext/common/Process.h +0 -253
  766. data/ext/common/Session.h +0 -436
  767. data/ext/common/SpawnManager.h +0 -611
  768. data/ext/google/ChangeLog +0 -167
  769. data/ext/google/dense_hash_map +0 -310
  770. data/ext/google/dense_hash_set +0 -287
  771. data/ext/google/sparse_hash_map +0 -294
  772. data/ext/google/sparse_hash_set +0 -275
  773. data/ext/google/sparsehash/densehashtable.h +0 -1062
  774. data/ext/google/sparsehash/sparseconfig.h +0 -55
  775. data/ext/google/sparsehash/sparsehashtable.h +0 -1015
  776. data/ext/google/sparsetable +0 -1468
  777. data/ext/google/type_traits.h +0 -250
  778. data/ext/nginx/HelperAgent.cpp +0 -1355
  779. data/ext/nginx/ScgiRequestParser.h +0 -375
  780. data/ext/oxt/backtrace.cpp +0 -185
  781. data/ext/oxt/tracable_exception.cpp +0 -89
  782. data/helper-scripts/passenger-spawn-server +0 -106
  783. data/lib/phusion_passenger/abstract_request_handler.rb +0 -766
  784. data/lib/phusion_passenger/abstract_server.rb +0 -372
  785. data/lib/phusion_passenger/abstract_server_collection.rb +0 -335
  786. data/lib/phusion_passenger/app_process.rb +0 -174
  787. data/lib/phusion_passenger/classic_rails/application_spawner.rb +0 -344
  788. data/lib/phusion_passenger/classic_rails/framework_spawner.rb +0 -311
  789. data/lib/phusion_passenger/exceptions.rb +0 -103
  790. data/lib/phusion_passenger/html_template.rb +0 -107
  791. data/lib/phusion_passenger/rack/application_spawner.rb +0 -231
  792. data/lib/phusion_passenger/spawn_manager.rb +0 -359
  793. data/lib/phusion_passenger/templates/app_exited_during_initialization.html.erb +0 -38
  794. data/lib/phusion_passenger/templates/app_init_error.html.erb +0 -64
  795. data/lib/phusion_passenger/templates/database_error.html.erb +0 -66
  796. data/lib/phusion_passenger/templates/error_layout.html.erb +0 -39
  797. data/lib/phusion_passenger/templates/framework_init_error.html.erb +0 -39
  798. data/lib/phusion_passenger/templates/general_error.html.erb +0 -22
  799. data/lib/phusion_passenger/templates/load_error.html.erb +0 -46
  800. data/lib/phusion_passenger/templates/version_not_found.html.erb +0 -34
  801. data/lib/phusion_passenger/utils/rewindable_input.rb +0 -125
  802. data/lib/phusion_passenger/wsgi/application_spawner.rb +0 -108
  803. data/test/config.yml.example +0 -41
  804. data/test/cxx/ApplicationPool_PoolTest.cpp +0 -33
  805. data/test/cxx/ApplicationPool_PoolTestCases.cpp +0 -1029
  806. data/test/cxx/ApplicationPool_ServerTest.cpp +0 -308
  807. data/test/cxx/ApplicationPool_Server_PoolTest.cpp +0 -80
  808. data/test/cxx/MessageChannelTest.cpp +0 -557
  809. data/test/cxx/PoolOptionsTest.cpp +0 -116
  810. data/test/cxx/SpawnManagerTest.cpp +0 -161
  811. data/test/ruby/abstract_server_collection_spec.rb +0 -247
  812. data/test/ruby/abstract_server_spec.rb +0 -61
  813. data/test/ruby/app_process_spec.rb +0 -43
  814. data/test/ruby/classic_rails/application_spawner_spec.rb +0 -89
  815. data/test/ruby/classic_rails/framework_spawner_spec.rb +0 -92
  816. data/test/ruby/rack/application_spawner_spec.rb +0 -116
  817. data/test/ruby/shared/abstract_server_spec.rb +0 -23
  818. data/test/ruby/shared/spawners/classic_rails/framework_spawner_spec.rb +0 -38
  819. data/test/ruby/shared/spawners/classic_rails/lack_of_rails_gem_version_spec.rb +0 -19
  820. data/test/ruby/shared/spawners/classic_rails/spawner_spec.rb +0 -15
  821. data/test/ruby/shared/spawners/non_preloading_spawner_spec.rb +0 -27
  822. data/test/ruby/shared/spawners/preloading_spawner_spec.rb +0 -29
  823. data/test/ruby/shared/spawners/reload_all_spec.rb +0 -36
  824. data/test/ruby/shared/spawners/reload_single_spec.rb +0 -52
  825. data/test/ruby/shared/spawners/spawn_server_spec.rb +0 -28
  826. data/test/ruby/shared/spawners/spawner_spec.rb +0 -273
  827. data/test/ruby/shared/utils/pseudo_io_spec.rb +0 -60
  828. data/test/ruby/spawn_manager_spec.rb +0 -134
  829. data/test/ruby/wsgi/application_spawner_spec.rb +0 -50
  830. data/test/stub/message_channel.rb +0 -11
  831. data/test/stub/message_channel_2.rb +0 -12
  832. data/test/stub/message_channel_3.rb +0 -19
  833. data/test/stub/rails_apps/3.0/empty/Gemfile.lock +0 -73
  834. data/test/stub/spawn_server.rb +0 -22
  835. metadata.gz.asc +0 -12
@@ -52,6 +52,12 @@ dd {
52
52
  font-family: 'Bitstream Vera Sans Mono', 'Courier New', Monospace;
53
53
  }
54
54
 
55
+ pre {
56
+ overflow: auto;
57
+ white-space: pre-wrap;
58
+ text-align: left;
59
+ }
60
+
55
61
  table.backtrace th {
56
62
  background: #8470a6;
57
63
  color: white;
@@ -0,0 +1,89 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5
+ <meta name="generator" content="Phusion Passenger">
6
+ <title>{{TITLE}}</title>
7
+ <style type="text/css">
8
+ {{CSS|raw}}
9
+ </style>
10
+ <link rel="stylesheet" type="text/css" href="http://www.modrails.com/error_pages/1.0/error_page.css">
11
+ <style type="text/css">
12
+ dd {
13
+ text-align: left;
14
+ }
15
+
16
+ dd pre {
17
+ margin-top: 0;
18
+ margin-bottom: 0;
19
+ }
20
+ </style>
21
+ </head>
22
+
23
+ <body>
24
+
25
+ <div id="site_container">
26
+ <div id="site_header">
27
+ <ul class="corporate_identity">
28
+ <li class="logo"><a href="https://www.phusionpassenger.com"><span>Phusion Passenger</span></a></li>
29
+ </ul>
30
+ </div>
31
+ <div id="site_body">
32
+ <h1 class="error_title">{{TITLE}}</h1>
33
+ <div id="content">
34
+ {{CONTENT|raw}}
35
+
36
+ <dl>
37
+ <dt>Application root</dt>
38
+ <dd>{{APP_ROOT}}</dd>
39
+ <dt>Environment (value of RAILS_ENV, RACK_ENV, WSGI_ENV and PASSENGER_ENV)</dt>
40
+ <dd>{{ENVIRONMENT}}</dd>
41
+ {{if IS_RUBY_APP}}
42
+ <dt>Ruby interpreter command</dt>
43
+ <dd><pre>{{RUBY}}</pre></dd>
44
+ {{/if}}
45
+ <dt>User and groups</dt>
46
+ <dd><pre>{{USER_INFO|default=Unknown}}</pre></dd>
47
+ <dt>Environment variables</dt>
48
+ <dd><pre>{{ENVVARS|default=Unknown}}</pre></dd>
49
+ <dt>Ulimits</dt>
50
+ <dd><pre>{{ULIMIT|default=Unknown}}</pre></dd>
51
+ {{if RUBY_INFO}}
52
+ <dt>General Ruby interpreter information</dt>
53
+ <dd><pre>{{RUBY_INFO}}</pre></dd>
54
+ {{/if}}
55
+ {{if RBCONFIG}}
56
+ <dt>Ruby configuration (RbConfig::CONFIG)</dt>
57
+ <dd><pre>{{RBCONFIG}}</pre></dd>
58
+ {{/if}}
59
+ {{if ACTIVATED_GEMS}}
60
+ <dt>Activated Ruby gems</dt>
61
+ <dd><pre>{{ACTIVATED_GEMS}}</pre></dd>
62
+ {{/if}}
63
+ {{if LOAD_PATH}}
64
+ <dt>Ruby load path ($LOAD_PATH)</dt>
65
+ <dd><pre>{{LOAD_PATH}}</pre></dd>
66
+ {{/if}}
67
+ {{if LOADED_LIBS}}
68
+ <dt>Ruby loaded libraries ($LOADED_FEATURES)</dt>
69
+ <dd><pre>{{LOADED_LIBS}}</pre></dd>
70
+ {{/if}}
71
+ </dl>
72
+ </div>
73
+ </div>
74
+ <div id="site_footer">
75
+ <!--
76
+ You are free to modify the footer as you see fit,
77
+ but we kindly ask of you to preserve to following
78
+ text. Thank you.
79
+ -->
80
+ <div class="container">
81
+ Powered by <a href="https://www.phusionpassenger.com/">Phusion Passenger</a>,
82
+ <tt>mod_rails</tt> / <tt>mod_rack</tt> for Apache and Nginx.
83
+ </div>
84
+ </div>
85
+ </div>
86
+
87
+ </body>
88
+ </html>
89
+
@@ -0,0 +1 @@
1
+ <pre>{{MESSAGE}}</pre>
@@ -0,0 +1,8 @@
1
+ <red>passenger-install-nginx-module is not available when packaged</red>
2
+
3
+ This Phusion Passenger installation is provided by your packager (as opposed to being installed from source). As such, you cannot use passenger-install-nginx-module. If you want to use passenger-install-nginx-module, please install Phusion Passenger from source by downloading it from <b>www.modrails.com</b>.
4
+
5
+ For more information about using Phusion Passenger for Nginx, please consult the documentation at one of the following places:
6
+
7
+ * <b><%= PhusionPassenger.doc_dir %>/Users Guide Nginx.html</b>
8
+ * <b>http://www.modrails.com/documentation.html</b>
@@ -37,9 +37,9 @@ events {
37
37
 
38
38
  http {
39
39
  log_format debug '[$time_local] $msec "$request" $status conn=$connection sent=$bytes_sent body_sent=$body_bytes_sent';
40
- include '<%= PhusionPassenger::RESOURCES_DIR %>/mime.types';
40
+ include '<%= PhusionPassenger.resources_dir %>/mime.types';
41
41
  passenger_ruby <%= PlatformInfo.ruby_command %>;
42
- passenger_root '<%= passenger_root %>';
42
+ passenger_root '<%= @location_config_filename %>';
43
43
  passenger_abort_on_startup_error on;
44
44
  passenger_user_switching off;
45
45
  passenger_max_pool_size <%= @options[:max_pool_size] %>;
@@ -47,7 +47,6 @@ http {
47
47
  <% if @options[:user] %>passenger_default_user <%= @options[:user] %>;<% end %>
48
48
  <% if debugging? %>passenger_log_level 2;<% end %>
49
49
  <% if @options[:rolling_restarts] %>passenger_rolling_restarts on;<% end %>
50
- <% if @options[:resist_deployment_errors] %>passenger_resist_deployment_errors on;<% end %>
51
50
 
52
51
  <% if @options[:union_station_gateway_address] %>
53
52
  union_station_gateway_address <%= @options[:union_station_gateway_address] %>;
@@ -69,14 +68,14 @@ http {
69
68
  # Default server entry.
70
69
  server {
71
70
  listen <%= nginx_listen_address %>;
72
- root '<%= LIBDIR %>/phusion_passenger/templates/standalone_default_root';
71
+ root '<%= PhusionPassenger.resources_dir %>/standalone_default_root';
73
72
  }
74
73
  <% end %>
75
74
 
76
75
  <% if @options[:ping_port] %>
77
76
  server {
78
77
  listen <%= nginx_listen_address(@options, true) %>;
79
- root '<%= LIBDIR %>/phusion_passenger/templates/standalone_default_root';
78
+ root '<%= PhusionPassenger.resources_dir %>/standalone_default_root';
80
79
  }
81
80
  <% end %>
82
81
 
@@ -93,6 +92,28 @@ http {
93
92
  union_station_support on;
94
93
  union_station_key <%= app[:union_station_key] %>;
95
94
  <% end %>
95
+
96
+ location ~ ^/assets/ {
97
+ error_page 490 = @static_asset;
98
+ error_page 491 = @dynamic_request;
99
+ recursive_error_pages on;
100
+
101
+ if (-f $request_filename) {
102
+ return 490;
103
+ }
104
+ if (!-f $request_filename) {
105
+ return 491;
106
+ }
107
+ }
108
+ location @static_asset {
109
+ gzip_static on;
110
+ expires max;
111
+ add_header Cache-Control public;
112
+ add_header ETag "";
113
+ }
114
+ location @dynamic_request {
115
+ passenger_enabled on;
116
+ }
96
117
  }
97
118
  passenger_pre_start http://<%= nginx_listen_address(app) %>;
98
119
  <% end %>
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class="dialog">
21
+ <h1>We're sorry, but something went wrong.</h1>
22
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
23
+ </div>
24
+ </body>
25
+ </html>
@@ -0,0 +1,42 @@
1
+ {
2
+ //// This file contains system-specific configuration options that the test suite needs.
3
+ //// Please customize it for your system.
4
+
5
+ // These are the usernames and group names of normal, non-administrator
6
+ // users and groups. Preferably, these are user and group accounts that
7
+ // are normally not used.
8
+ //
9
+ // These users and groups MUST be able to access this 'test' directory,
10
+ // otherwise the tests will fail.
11
+
12
+ //// Good values for OS X:
13
+ "normal_user_1": "_www",
14
+ "normal_user_2": "daemon",
15
+ // Must not be "nobody".
16
+ "default_user": "_sandbox",
17
+ // Must not be normal_user_1's primary group.
18
+ "normal_group_1": "daemon",
19
+ // Must not be normal_user_2's primary group.
20
+ "normal_group_2": "_sandbox",
21
+ // Must not be default_user's primary group. Must not be "nobody".
22
+ "default_group": "_www",
23
+
24
+ ///// Good values for Linux and FreeBSD. Same restrictions apply.
25
+ //"normal_user_1": "games",
26
+ //"normal_user_2": "daemon",
27
+ //"default_user": "man",
28
+ //"normal_group_1": "daemon",
29
+ //"normal_group_2": "man",
30
+ //"default_group": "games",
31
+
32
+ // A nonexistant username, group name, user ID and group ID.
33
+ "nonexistant_user": "xxxxxxxxxxxxxxxxxxx",
34
+ "nonexistant_group": "xxxxxxxxxxxxxxxxxxx",
35
+ "nonexistant_uid": 9999,
36
+ "nonexistant_gid": 9999,
37
+
38
+ // If you want to run the Nginx integration tests, then set the following
39
+ // config option to the full path of the Nginx binary. This Nginx binary *must*
40
+ // be compiled with Phusion Passenger support!
41
+ // nginx: /usr/local/sbin/nginx
42
+ }
@@ -0,0 +1,86 @@
1
+ #include <TestSupport.h>
2
+ #include <ApplicationPool2/Spawner.h>
3
+ #include <Utils/json.h>
4
+
5
+ using namespace Passenger;
6
+ using namespace Passenger::ApplicationPool2;
7
+
8
+ namespace tut {
9
+ struct ApplicationPool2_DirectSpawnerTest {
10
+ ServerInstanceDirPtr serverInstanceDir;
11
+ ServerInstanceDir::GenerationPtr generation;
12
+ BackgroundEventLoop bg;
13
+
14
+ ApplicationPool2_DirectSpawnerTest() {
15
+ createServerInstanceDirAndGeneration(serverInstanceDir, generation);
16
+ bg.start();
17
+ }
18
+
19
+ ~ApplicationPool2_DirectSpawnerTest() {
20
+ unlink("stub/wsgi/passenger_wsgi.pyc");
21
+ }
22
+
23
+ shared_ptr<DirectSpawner> createSpawner(const Options &options) {
24
+ return make_shared<DirectSpawner>(bg.safe,
25
+ *resourceLocator, generation);
26
+ }
27
+
28
+ Options createOptions() {
29
+ Options options;
30
+ options.spawnMethod = "direct";
31
+ options.loadShellEnvvars = false;
32
+ return options;
33
+ }
34
+ };
35
+
36
+ DEFINE_TEST_GROUP_WITH_LIMIT(ApplicationPool2_DirectSpawnerTest, 90);
37
+
38
+ #include "SpawnerTestCases.cpp"
39
+
40
+ TEST_METHOD(80) {
41
+ // If the application didn't start within the timeout
42
+ // then whatever was written to stderr is used as the
43
+ // SpawnException error page.
44
+ Options options = createOptions();
45
+ options.appRoot = "stub";
46
+ options.startCommand = "perl\1" "-e\1" "print STDERR \"hello world\\n\"; sleep(60)";
47
+ options.startupFile = ".";
48
+ options.startTimeout = 300;
49
+
50
+ DirectSpawner spawner(bg.safe, *resourceLocator, generation);
51
+ spawner.forwardStderr = false;
52
+
53
+ try {
54
+ spawner.spawn(options);
55
+ fail("Timeout expected");
56
+ } catch (const SpawnException &e) {
57
+ ensure_equals(e.getErrorKind(),
58
+ SpawnException::APP_STARTUP_TIMEOUT);
59
+ ensure_equals(e.getErrorPage(),
60
+ "hello world\n");
61
+ }
62
+ }
63
+
64
+ TEST_METHOD(81) {
65
+ // If the application crashed during startup without returning
66
+ // a proper error response, then its stderr output is used
67
+ // as error response instead.
68
+ Options options = createOptions();
69
+ options.appRoot = "stub";
70
+ options.startCommand = "perl\1" "-e\1" "print STDERR \"hello world\\n\"";
71
+ options.startupFile = ".";
72
+
73
+ DirectSpawner spawner(bg.safe, *resourceLocator, generation);
74
+ spawner.forwardStderr = false;
75
+
76
+ try {
77
+ spawner.spawn(options);
78
+ fail("SpawnException expected");
79
+ } catch (const SpawnException &e) {
80
+ ensure_equals(e.getErrorKind(),
81
+ SpawnException::APP_STARTUP_PROTOCOL_ERROR);
82
+ ensure_equals(e.getErrorPage(),
83
+ "hello world\n");
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,44 @@
1
+ #include <TestSupport.h>
2
+ #include <ApplicationPool2/Process.h>
3
+
4
+ using namespace Passenger;
5
+ using namespace Passenger::ApplicationPool2;
6
+ using namespace std;
7
+
8
+ namespace tut {
9
+ struct ApplicationPool2_OptionsTest {
10
+ ApplicationPool2_OptionsTest() {
11
+ }
12
+ };
13
+
14
+ DEFINE_TEST_GROUP(ApplicationPool2_OptionsTest);
15
+
16
+ TEST_METHOD(1) {
17
+ // Test persist().
18
+ char appRoot[] = "appRoot";
19
+ char processTitle[] = "processTitle";
20
+ char fooKey[] = "PASSENGER_FOO";
21
+ char fooValue[] = "foo";
22
+ char barKey[] = "PASSENGER_BAR";
23
+ char barValue[] = "bar";
24
+
25
+ Options options;
26
+ options.appRoot = appRoot;
27
+ options.processTitle = processTitle;
28
+ options.environmentVariables.push_back(make_pair(fooKey, fooValue));
29
+ options.environmentVariables.push_back(make_pair(barKey, barValue));
30
+
31
+ Options options2 = options.copyAndPersist();
32
+ appRoot[0] = processTitle[0] = 'x';
33
+ fooKey[0] = fooValue[0] = 'x';
34
+ barKey[0] = barValue[0] = 'x';
35
+
36
+ ensure_equals(options2.appRoot, "appRoot");
37
+ ensure_equals(options2.processTitle, "processTitle");
38
+ ensure_equals(options2.environmentVariables.size(), 2u);
39
+ ensure_equals(options2.environmentVariables[0].first, "PASSENGER_FOO");
40
+ ensure_equals(options2.environmentVariables[0].second, "foo");
41
+ ensure_equals(options2.environmentVariables[1].first, "PASSENGER_BAR");
42
+ ensure_equals(options2.environmentVariables[1].second, "bar");
43
+ }
44
+ }
@@ -0,0 +1,1234 @@
1
+ #include <TestSupport.h>
2
+ #include <ApplicationPool2/Pool.h>
3
+ #include <Utils/IOUtils.h>
4
+ #include <Utils/StrIntUtils.h>
5
+ #include <Utils/json.h>
6
+ #include <MessageReadersWriters.h>
7
+ #include <map>
8
+ #include <vector>
9
+ #include <cerrno>
10
+ #include <signal.h>
11
+
12
+ using namespace std;
13
+ using namespace Passenger;
14
+ using namespace Passenger::ApplicationPool2;
15
+
16
+ namespace tut {
17
+ struct ApplicationPool2_PoolTest {
18
+ ServerInstanceDirPtr serverInstanceDir;
19
+ ServerInstanceDir::GenerationPtr generation;
20
+ BackgroundEventLoop bg;
21
+ SpawnerFactoryPtr spawnerFactory;
22
+ PoolPtr pool;
23
+ GetCallback callback;
24
+ SessionPtr currentSession;
25
+ ExceptionPtr currentException;
26
+ AtomicInt number;
27
+ boost::mutex syncher;
28
+ list<SessionPtr> sessions;
29
+ bool retainSessions;
30
+
31
+ ApplicationPool2_PoolTest() {
32
+ createServerInstanceDirAndGeneration(serverInstanceDir, generation);
33
+ retainSessions = false;
34
+ spawnerFactory = make_shared<SpawnerFactory>(bg.safe, *resourceLocator, generation);
35
+ pool = make_shared<Pool>(bg.safe.get(), spawnerFactory);
36
+ bg.start();
37
+ callback = boost::bind(&ApplicationPool2_PoolTest::_callback, this, _1, _2);
38
+ }
39
+
40
+ ~ApplicationPool2_PoolTest() {
41
+ // Explicitly destroy these here because they can run
42
+ // additional code that depend on other fields in this
43
+ // class.
44
+ setLogLevel(0);
45
+ TRACE_POINT();
46
+ pool->destroy();
47
+ UPDATE_TRACE_POINT();
48
+ pool.reset();
49
+ UPDATE_TRACE_POINT();
50
+ lock_guard<boost::mutex> l(syncher);
51
+ currentSession.reset();
52
+ sessions.clear();
53
+ }
54
+
55
+ Options createOptions() {
56
+ Options options;
57
+ options.spawnMethod = "dummy";
58
+ options.appRoot = "stub/rack";
59
+ options.startCommand = "ruby\1" "start.rb";
60
+ options.startupFile = "start.rb";
61
+ options.loadShellEnvvars = false;
62
+ options.user = testConfig["normal_user_1"].asCString();
63
+ options.defaultUser = testConfig["default_user"].asCString();
64
+ options.defaultGroup = testConfig["default_group"].asCString();
65
+ return options;
66
+ }
67
+
68
+ void _callback(const SessionPtr &session, const ExceptionPtr &e) {
69
+ SessionPtr oldSession;
70
+ {
71
+ LockGuard l(syncher);
72
+ oldSession = currentSession;
73
+ currentSession = session;
74
+ currentException = e;
75
+ number++;
76
+ if (retainSessions && session != NULL) {
77
+ sessions.push_back(session);
78
+ }
79
+ }
80
+ // destroy old session object outside the lock.
81
+ }
82
+
83
+ void sendHeaders(int connection, ...) {
84
+ va_list ap;
85
+ const char *arg;
86
+ vector<StaticString> args;
87
+
88
+ va_start(ap, connection);
89
+ while ((arg = va_arg(ap, const char *)) != NULL) {
90
+ args.push_back(StaticString(arg, strlen(arg) + 1));
91
+ }
92
+ va_end(ap);
93
+
94
+ shared_array<StaticString> args_array(new StaticString[args.size() + 1]);
95
+ unsigned int totalSize = 0;
96
+ for (unsigned int i = 0; i < args.size(); i++) {
97
+ args_array[i + 1] = args[i];
98
+ totalSize += args[i].size();
99
+ }
100
+ char sizeHeader[sizeof(uint32_t)];
101
+ Uint32Message::generate(sizeHeader, totalSize);
102
+ args_array[0] = StaticString(sizeHeader, sizeof(uint32_t));
103
+
104
+ gatheredWrite(connection, args_array.get(), args.size() + 1, NULL);
105
+ }
106
+
107
+ string stripHeaders(const string &str) {
108
+ string::size_type pos = str.find("\r\n\r\n");
109
+ if (pos == string::npos) {
110
+ return str;
111
+ } else {
112
+ string result = str;
113
+ result.erase(0, pos + 4);
114
+ return result;
115
+ }
116
+ }
117
+
118
+ string sendRequest(const Options &options, const char *path) {
119
+ int oldNumber = number;
120
+ pool->asyncGet(options, callback);
121
+ EVENTUALLY(5,
122
+ result = number == oldNumber + 1;
123
+ );
124
+ if (currentException != NULL) {
125
+ P_ERROR("get() exception: " << currentException->what());
126
+ abort();
127
+ }
128
+ currentSession->initiate();
129
+ sendHeaders(currentSession->fd(),
130
+ "PATH_INFO", path,
131
+ "REQUEST_METHOD", "GET",
132
+ NULL);
133
+ shutdown(currentSession->fd(), SHUT_WR);
134
+ string body = stripHeaders(readAll(currentSession->fd()));
135
+ ProcessPtr process = currentSession->getProcess();
136
+ currentSession.reset();
137
+ EVENTUALLY(5,
138
+ result = process->utilization() == 0;
139
+ );
140
+ return body;
141
+ }
142
+ };
143
+
144
+ DEFINE_TEST_GROUP_WITH_LIMIT(ApplicationPool2_PoolTest, 100);
145
+
146
+ TEST_METHOD(1) {
147
+ // Test initial state.
148
+ ensure(!pool->atFullCapacity());
149
+ }
150
+
151
+
152
+ /*********** Test asyncGet() behavior on a single SuperGroup and Group ***********/
153
+
154
+ TEST_METHOD(2) {
155
+ // asyncGet() actions on empty pools cannot be immediately satisfied.
156
+ // Instead a new process will be spawned. In the mean time get()
157
+ // actions are put on a wait list which will be processed as soon
158
+ // as the new process is done spawning.
159
+ Options options = createOptions();
160
+
161
+ ScopedLock l(pool->syncher);
162
+ pool->asyncGet(options, callback, false);
163
+ ensure_equals(number, 0);
164
+ ensure(pool->getWaitlist.empty());
165
+ ensure(!pool->superGroups.empty());
166
+ l.unlock();
167
+
168
+ EVENTUALLY(5,
169
+ result = pool->getProcessCount() == 1;
170
+ );
171
+ ensure_equals(number, 1);
172
+ ensure(currentSession != NULL);
173
+ ensure(currentException == NULL);
174
+ }
175
+
176
+ TEST_METHOD(3) {
177
+ // If one matching process already exists and it's not at full
178
+ // capacity then asyncGet() will immediately use it.
179
+ Options options = createOptions();
180
+
181
+ // Spawn a process and opens a session with it.
182
+ pool->asyncGet(options, callback);
183
+ EVENTUALLY(5,
184
+ result = number == 1;
185
+ );
186
+
187
+ // Close the session so that the process is now idle.
188
+ ProcessPtr process = currentSession->getProcess();
189
+ currentSession.reset();
190
+ ensure_equals(process->utilization(), 0);
191
+ ensure(!process->atFullCapacity());
192
+
193
+ // Verify test assertion.
194
+ ScopedLock l(pool->syncher);
195
+ pool->asyncGet(options, callback, false);
196
+ ensure_equals("callback is immediately called", number, 2);
197
+ }
198
+
199
+ TEST_METHOD(4) {
200
+ // If one matching process already exists but it's at full capacity,
201
+ // and the limits prevent spawning of a new process,
202
+ // then asyncGet() will put the get action on the group's wait
203
+ // queue. When the process is no longer at full capacity it will
204
+ // process the request.
205
+
206
+ // Spawn a process and verify that it's at full capacity.
207
+ // Keep its session open.
208
+ Options options = createOptions();
209
+ options.appGroupName = "test";
210
+ pool->setMax(1);
211
+ pool->asyncGet(options, callback);
212
+ EVENTUALLY(5,
213
+ result = number == 1;
214
+ );
215
+ SessionPtr session1 = currentSession;
216
+ ProcessPtr process = session1->getProcess();
217
+ currentSession.reset();
218
+ ensure_equals(process->sessions, 1);
219
+ ensure(process->atFullCapacity());
220
+
221
+ // Now call asyncGet() again.
222
+ pool->asyncGet(options, callback);
223
+ ensure_equals("callback is not yet called", number, 1);
224
+ ensure_equals("the get action has been put on the wait list",
225
+ pool->superGroups.get("test")->defaultGroup->getWaitlist.size(), 1u);
226
+
227
+ session1.reset();
228
+ ensure_equals("callback is called after the process becomes idle",
229
+ number, 2);
230
+ ensure_equals("the get wait list has been processed",
231
+ pool->superGroups.get("test")->defaultGroup->getWaitlist.size(), 0u);
232
+ ensure_equals(process->sessions, 1);
233
+ }
234
+
235
+ TEST_METHOD(5) {
236
+ // If one matching process already exists but it's at full capacity,
237
+ // and the limits and pool capacity allow spawning of a new process,
238
+ // then get() will put the get action on the group's wait
239
+ // queue while spawning a process in the background.
240
+ // Either the existing process or the newly spawned process
241
+ // will process the action, whichever becomes first available.
242
+
243
+ // Here we test the case in which the existing process becomes
244
+ // available first.
245
+
246
+ // Spawn a regular process and keep its session open.
247
+ Options options = createOptions();
248
+ pool->asyncGet(options, callback);
249
+ EVENTUALLY(5,
250
+ result = number == 1;
251
+ );
252
+ SessionPtr session1 = currentSession;
253
+ ProcessPtr process1 = currentSession->getProcess();
254
+ currentSession.reset();
255
+
256
+ // Now spawn a process that never finishes.
257
+ SpawnerPtr spawner = process1->getGroup()->spawner;
258
+ dynamic_pointer_cast<DummySpawner>(spawner)->spawnTime = 5000000;
259
+ pool->asyncGet(options, callback);
260
+
261
+ // Release the session on the first process.
262
+ session1.reset();
263
+
264
+ ensure_equals("The callback should have been called twice now", number, 2);
265
+ ensure_equals("The first process handled the second asyncGet() request",
266
+ currentSession->getProcess(), process1);
267
+ }
268
+
269
+ TEST_METHOD(6) {
270
+ // Here we test the case in which the new process becomes
271
+ // available first.
272
+
273
+ // Spawn a regular process.
274
+ Options options = createOptions();
275
+ pool->asyncGet(options, callback);
276
+ EVENTUALLY(5,
277
+ result = number == 1;
278
+ );
279
+ SessionPtr session1 = currentSession;
280
+ ProcessPtr process1 = currentSession->getProcess();
281
+ currentSession.reset();
282
+
283
+ // As long as we don't release process1 the following get
284
+ // action will be processed by the newly spawned process.
285
+ pool->asyncGet(options, callback);
286
+ EVENTUALLY(5,
287
+ result = pool->getProcessCount() == 2;
288
+ );
289
+ ensure_equals(number, 2);
290
+ ensure(currentSession->getProcess() != process1);
291
+ }
292
+
293
+ TEST_METHOD(7) {
294
+ // If multiple matching processes exist, and one of them is idle,
295
+ // then asyncGet() will use that.
296
+
297
+ // Spawn 3 processes and keep a session open with 1 of them.
298
+ Options options = createOptions();
299
+ options.minProcesses = 3;
300
+ pool->asyncGet(options, callback);
301
+ EVENTUALLY(5,
302
+ result = number == 1;
303
+ );
304
+ EVENTUALLY(5,
305
+ result = pool->getProcessCount() == 3;
306
+ );
307
+ SessionPtr session1 = currentSession;
308
+ ProcessPtr process1 = currentSession->getProcess();
309
+ currentSession.reset();
310
+
311
+ // Now open another session. It should complete immediately
312
+ // and should not use the first process.
313
+ ScopedLock l(pool->syncher);
314
+ pool->asyncGet(options, callback, false);
315
+ ensure_equals("asyncGet() completed immediately", number, 2);
316
+ SessionPtr session2 = currentSession;
317
+ ProcessPtr process2 = currentSession->getProcess();
318
+ l.unlock();
319
+ currentSession.reset();
320
+ ensure(process2 != process1);
321
+
322
+ // Now open yet another session. It should also complete immediately
323
+ // and should not use the first or the second process.
324
+ l.lock();
325
+ pool->asyncGet(options, callback, false);
326
+ ensure_equals("asyncGet() completed immediately", number, 3);
327
+ SessionPtr session3 = currentSession;
328
+ ProcessPtr process3 = currentSession->getProcess();
329
+ l.unlock();
330
+ currentSession.reset();
331
+ ensure(process3 != process1);
332
+ ensure(process3 != process2);
333
+ }
334
+
335
+ TEST_METHOD(8) {
336
+ // If multiple matching processes exist, then asyncGet() will use
337
+ // the one with the smallest utilization number.
338
+
339
+ // Spawn 2 processes, each with a concurrency of 2.
340
+ Options options = createOptions();
341
+ options.minProcesses = 2;
342
+ pool->setMax(2);
343
+ GroupPtr group = pool->findOrCreateGroup(options);
344
+ dynamic_pointer_cast<DummySpawner>(group->spawner)->concurrency = 2;
345
+ {
346
+ LockGuard l(pool->syncher);
347
+ group->spawn();
348
+ }
349
+ EVENTUALLY(5,
350
+ result = pool->getProcessCount() == 2;
351
+ );
352
+
353
+ // asyncGet() selects some process.
354
+ pool->asyncGet(options, callback);
355
+ ensure_equals(number, 1);
356
+ SessionPtr session1 = currentSession;
357
+ ProcessPtr process1 = currentSession->getProcess();
358
+ currentSession.reset();
359
+
360
+ // The first process now has 1 session, so next asyncGet() should
361
+ // select the other process.
362
+ pool->asyncGet(options, callback);
363
+ ensure_equals(number, 2);
364
+ SessionPtr session2 = currentSession;
365
+ ProcessPtr process2 = currentSession->getProcess();
366
+ currentSession.reset();
367
+ ensure("(1)", process1 != process2);
368
+
369
+ // Both processes now have an equal number of sessions. Next asyncGet()
370
+ // can select either.
371
+ pool->asyncGet(options, callback);
372
+ ensure_equals(number, 3);
373
+ SessionPtr session3 = currentSession;
374
+ ProcessPtr process3 = currentSession->getProcess();
375
+ currentSession.reset();
376
+
377
+ // One process now has the lowest number of sessions. Next
378
+ // asyncGet() should select that one.
379
+ pool->asyncGet(options, callback);
380
+ ensure_equals(number, 4);
381
+ SessionPtr session4 = currentSession;
382
+ ProcessPtr process4 = currentSession->getProcess();
383
+ currentSession.reset();
384
+ ensure(process3 != process4);
385
+ }
386
+
387
+ TEST_METHOD(9) {
388
+ // If multiple matching processes exist, and all of them are at full capacity,
389
+ // and no more processes may be spawned,
390
+ // then asyncGet() will put the action on the group's wait queue.
391
+ // The process that first becomes not at full capacity will process the action.
392
+
393
+ // Spawn 2 processes and open 4 sessions.
394
+ Options options = createOptions();
395
+ options.appGroupName = "test";
396
+ options.minProcesses = 2;
397
+ pool->setMax(2);
398
+ GroupPtr group = pool->findOrCreateGroup(options);
399
+ dynamic_pointer_cast<DummySpawner>(group->spawner)->concurrency = 2;
400
+
401
+ vector<SessionPtr> sessions;
402
+ int expectedNumber = 1;
403
+ for (int i = 0; i < 4; i++) {
404
+ pool->asyncGet(options, callback);
405
+ EVENTUALLY(5,
406
+ result = number == expectedNumber;
407
+ );
408
+ expectedNumber++;
409
+ sessions.push_back(currentSession);
410
+ currentSession.reset();
411
+ }
412
+ EVENTUALLY(5,
413
+ result = pool->getProcessCount() == 2;
414
+ );
415
+
416
+ SuperGroupPtr superGroup = pool->superGroups.get("test");
417
+ ensure_equals(superGroup->groups[0]->getWaitlist.size(), 0u);
418
+ ensure(pool->atFullCapacity());
419
+
420
+ // Now try to open another session.
421
+ pool->asyncGet(options, callback);
422
+ ensure_equals("The get request has been put on the wait list",
423
+ pool->superGroups.get("test")->groups[0]->getWaitlist.size(), 1u);
424
+
425
+ // Close an existing session so that one process is no
426
+ // longer at full capacity.
427
+ sessions[0].reset();
428
+ ensure_equals("The get request has been removed from the wait list",
429
+ pool->superGroups.get("test")->groups[0]->getWaitlist.size(), 0u);
430
+ ensure(pool->atFullCapacity());
431
+ }
432
+
433
+ TEST_METHOD(10) {
434
+ // If multiple matching processes exist, and all of them are at full capacity,
435
+ // and a new process may be spawned,
436
+ // then asyncGet() will put the action on the group's wait queue and spawn the
437
+ // new process.
438
+ // The process that first becomes not at full capacity
439
+ // or the newly spawned process
440
+ // will process the action, whichever is earlier.
441
+ // Here we test the case where an existing process is earlier.
442
+
443
+ // Spawn 2 processes and open 4 sessions.
444
+ Options options = createOptions();
445
+ options.minProcesses = 2;
446
+ pool->setMax(3);
447
+ GroupPtr group = pool->findOrCreateGroup(options);
448
+ dynamic_pointer_cast<DummySpawner>(group->spawner)->concurrency = 2;
449
+
450
+ vector<SessionPtr> sessions;
451
+ int expectedNumber = 1;
452
+ for (int i = 0; i < 4; i++) {
453
+ pool->asyncGet(options, callback);
454
+ EVENTUALLY(5,
455
+ result = number == expectedNumber;
456
+ );
457
+ expectedNumber++;
458
+ sessions.push_back(currentSession);
459
+ currentSession.reset();
460
+ }
461
+ EVENTUALLY(5,
462
+ result = pool->getProcessCount() == 2;
463
+ );
464
+
465
+ // The next asyncGet() should spawn a new process and the action should be queued.
466
+ ScopedLock l(pool->syncher);
467
+ dynamic_pointer_cast<DummySpawner>(group->spawner)->spawnTime = 5000000;
468
+ pool->asyncGet(options, callback, false);
469
+ ensure(group->spawning());
470
+ ensure_equals(group->getWaitlist.size(), 1u);
471
+ l.unlock();
472
+
473
+ // Close one of the sessions. Now it will process the action.
474
+ ProcessPtr process = sessions[0]->getProcess();
475
+ sessions[0].reset();
476
+ ensure_equals(number, 5);
477
+ ensure_equals(currentSession->getProcess(), process);
478
+ ensure_equals(group->getWaitlist.size(), 0u);
479
+ ensure_equals(pool->getProcessCount(), 2u);
480
+ }
481
+
482
+ TEST_METHOD(11) {
483
+ // Here we test the case where the newly spawned process is earlier.
484
+
485
+ // Spawn 2 processes and open 4 sessions.
486
+ Options options = createOptions();
487
+ options.minProcesses = 2;
488
+ pool->setMax(3);
489
+ GroupPtr group = pool->findOrCreateGroup(options);
490
+ dynamic_pointer_cast<DummySpawner>(group->spawner)->concurrency = 2;
491
+
492
+ vector<SessionPtr> sessions;
493
+ int expectedNumber = 1;
494
+ for (int i = 0; i < 4; i++) {
495
+ pool->asyncGet(options, callback);
496
+ EVENTUALLY(5,
497
+ result = number == expectedNumber;
498
+ );
499
+ expectedNumber++;
500
+ sessions.push_back(currentSession);
501
+ currentSession.reset();
502
+ }
503
+ EVENTUALLY(5,
504
+ result = pool->getProcessCount() == 2;
505
+ );
506
+
507
+ // The next asyncGet() should spawn a new process. After it's done
508
+ // spawning it will process the action.
509
+ pool->asyncGet(options, callback);
510
+ EVENTUALLY(5,
511
+ result = pool->getProcessCount() == 3;
512
+ );
513
+ EVENTUALLY(5,
514
+ result = number == 5;
515
+ );
516
+ ensure_equals(currentSession->getProcess()->pid, 3);
517
+ ensure_equals(group->getWaitlist.size(), 0u);
518
+ }
519
+
520
+
521
+ /*********** Test asyncGet() behavior on multiple SuperGroups,
522
+ each with a single Group ***********/
523
+
524
+ TEST_METHOD(20) {
525
+ // If the pool is full, and one tries to asyncGet() from a nonexistant group,
526
+ // then it will kill the oldest idle process and spawn a new process.
527
+ Options options = createOptions();
528
+ pool->setMax(2);
529
+
530
+ // Get from /foo and close its session immediately.
531
+ options.appRoot = "/foo";
532
+ pool->asyncGet(options, callback);
533
+ EVENTUALLY(5,
534
+ result = number == 1;
535
+ );
536
+ ProcessPtr process1 = currentSession->getProcess();
537
+ GroupPtr group1 = process1->getGroup();
538
+ SuperGroupPtr superGroup1 = group1->getSuperGroup();
539
+ currentSession.reset();
540
+
541
+ // Get from /bar and keep its session open.
542
+ options.appRoot = "/bar";
543
+ pool->asyncGet(options, callback);
544
+ EVENTUALLY(5,
545
+ result = number == 2;
546
+ );
547
+ SessionPtr session2 = currentSession;
548
+ currentSession.reset();
549
+
550
+ // Get from /baz. The process for /foo should be killed now.
551
+ options.appRoot = "/baz";
552
+ pool->asyncGet(options, callback);
553
+ EVENTUALLY(5,
554
+ result = number == 3;
555
+ );
556
+
557
+ ensure_equals(pool->getProcessCount(), 2u);
558
+ ensure(!superGroup1->detached());
559
+ ensure_equals(superGroup1->getProcessCount(), 0u);
560
+ }
561
+
562
+ TEST_METHOD(21) {
563
+ // If the pool is full, and one tries to asyncGet() from a nonexistant group,
564
+ // and all existing processes are non-idle, then it will
565
+ // kill the oldest process and spawn a new process.
566
+ Options options = createOptions();
567
+ pool->setMax(2);
568
+
569
+ // Get from /foo and close its session immediately.
570
+ options.appRoot = "/foo";
571
+ pool->asyncGet(options, callback);
572
+ EVENTUALLY(5,
573
+ result = number == 1;
574
+ );
575
+ SessionPtr session1 = currentSession;
576
+ ProcessPtr process1 = currentSession->getProcess();
577
+ GroupPtr group1 = process1->getGroup();
578
+ SuperGroupPtr superGroup1 = group1->getSuperGroup();
579
+
580
+ // Get from /bar and keep its session open.
581
+ options.appRoot = "/bar";
582
+ pool->asyncGet(options, callback);
583
+ EVENTUALLY(5,
584
+ result = number == 2;
585
+ );
586
+ SessionPtr session2 = currentSession;
587
+ currentSession.reset();
588
+
589
+ // Get from /baz. The process for /foo should be killed now.
590
+ options.appRoot = "/baz";
591
+ pool->asyncGet(options, callback);
592
+ EVENTUALLY(5,
593
+ result = number == 3;
594
+ );
595
+
596
+ ensure_equals(pool->getProcessCount(), 2u);
597
+ ensure(!superGroup1->detached());
598
+ ensure_equals(superGroup1->getProcessCount(), 0u);
599
+ }
600
+
601
+
602
+ /*********** Test detachProcess() ***********/
603
+
604
+ TEST_METHOD(30) {
605
+ // detachProcess() detaches the process from the group.
606
+ Options options = createOptions();
607
+ options.appGroupName = "test";
608
+ options.minProcesses = 2;
609
+ pool->asyncGet(options, callback);
610
+ EVENTUALLY(5,
611
+ result = pool->getProcessCount() == 2;
612
+ );
613
+ EVENTUALLY(5,
614
+ result = number == 1;
615
+ );
616
+
617
+ pool->detachProcess(currentSession->getProcess());
618
+ ensure(currentSession->getProcess()->detached());
619
+ LockGuard l(pool->syncher);
620
+ ensure_equals(pool->superGroups.get("test")->defaultGroup->count, 1);
621
+ }
622
+
623
+ TEST_METHOD(31) {
624
+ // If the containing group had waiters on it, and detachProcess()
625
+ // detaches the only process in the group, then a new process
626
+ // is automatically spawned to handle the waiters.
627
+ Options options = createOptions();
628
+ options.appGroupName = "test";
629
+ pool->setMax(1);
630
+ pool->spawnerFactory->dummySpawnTime = 1000000;
631
+
632
+ pool->asyncGet(options, callback);
633
+ EVENTUALLY(5,
634
+ result = number == 1;
635
+ );
636
+ SessionPtr session1 = currentSession;
637
+ currentSession.reset();
638
+
639
+ pool->asyncGet(options, callback);
640
+
641
+ {
642
+ LockGuard l(pool->syncher);
643
+ ensure_equals(pool->superGroups.get("test")->defaultGroup->getWaitlist.size(), 1u);
644
+ }
645
+
646
+ pool->detachProcess(session1->getProcess());
647
+ {
648
+ LockGuard l(pool->syncher);
649
+ ensure(pool->superGroups.get("test")->defaultGroup->spawning());
650
+ ensure_equals(pool->superGroups.get("test")->defaultGroup->count, 0);
651
+ ensure_equals(pool->superGroups.get("test")->defaultGroup->getWaitlist.size(), 1u);
652
+ }
653
+ }
654
+
655
+ TEST_METHOD(32) {
656
+ // If the pool had waiters on it then detachProcess() will
657
+ // automatically create the SuperGroups that were requested
658
+ // by the waiters.
659
+ Options options = createOptions();
660
+ options.appGroupName = "test";
661
+ pool->setMax(1);
662
+ pool->spawnerFactory->dummySpawnTime = 30000;
663
+
664
+ // Begin spawning a process.
665
+ pool->asyncGet(options, callback);
666
+ ensure(pool->atFullCapacity());
667
+
668
+ // asyncGet() on another group should now put it on the waiting list.
669
+ Options options2 = createOptions();
670
+ options2.appGroupName = "test2";
671
+ pool->spawnerFactory->dummySpawnTime = 90000;
672
+ pool->asyncGet(options2, callback);
673
+ {
674
+ LockGuard l(pool->syncher);
675
+ ensure_equals(pool->getWaitlist.size(), 1u);
676
+ }
677
+
678
+ // Eventually the dummy process for "test" is now done spawning.
679
+ // We then detach it.
680
+ EVENTUALLY(5,
681
+ result = number == 1;
682
+ );
683
+ SessionPtr session1 = currentSession;
684
+ currentSession.reset();
685
+ pool->detachProcess(session1->getProcess());
686
+ {
687
+ LockGuard l(pool->syncher);
688
+ ensure(pool->superGroups.get("test2") != NULL);
689
+ ensure_equals(pool->getWaitlist.size(), 0u);
690
+ }
691
+ }
692
+
693
+ TEST_METHOD(33) {
694
+ // A SuperGroup does not become garbage collectable
695
+ // after detaching all its processes.
696
+ Options options = createOptions();
697
+ pool->asyncGet(options, callback);
698
+ EVENTUALLY(5,
699
+ result = number == 1;
700
+ );
701
+ ProcessPtr process = currentSession->getProcess();
702
+ currentSession.reset();
703
+ SuperGroupPtr superGroup = process->getSuperGroup();
704
+ pool->detachProcess(process);
705
+ LockGuard l(pool->syncher);
706
+ ensure_equals(pool->superGroups.size(), 1u);
707
+ ensure(!superGroup->detached());
708
+ ensure(!superGroup->garbageCollectable());
709
+ }
710
+
711
+
712
+ /*********** Test disabling and enabling processes ***********/
713
+
714
+ TEST_METHOD(40) {
715
+ // Disabling a process under idle conditions should succeed immediately.
716
+ /*
717
+ Options options = createOptions();
718
+ options.minProcesses = 2;
719
+ options.noop = true;
720
+ pool->asyncGet(options, callback);
721
+ EVENTUALLY(5,
722
+ result = number == 1;
723
+ );
724
+ EVENTUALLY(5,
725
+ result = pool->getProcessCount() == 2;
726
+ );
727
+
728
+ options.minProcesses = 0;
729
+ options.noop = false;
730
+ vector<ProcessPtr> processes = pool->getProcesses();
731
+ ensure_equals(processes, );
732
+ */
733
+ }
734
+
735
+ // Disabling the sole process in a group should trigger a new process spawn.
736
+ // Disabling should succeed after the new process has been spawned.
737
+
738
+ // Duppose that a previous disable command triggered a new process spawn,
739
+ // and the spawn fails. Then the processes which were marked as 'disabled'
740
+ // should be marked 'enabled' again, and the callbacks for the previous
741
+ // disable commands should be called.
742
+
743
+ // asyncGet() should not select a process that's being disabled, unless
744
+ // it's the only process in the group.
745
+
746
+ // Disabling a process that's already being disabled should result in the
747
+ // callback being called after disabling is done.
748
+
749
+ // Enabling a process that's being disabled should immediately mark the process
750
+ // as being enabled and should call all the queued disable command callbacks.
751
+
752
+ // Enabling a process that's disabled works.
753
+
754
+
755
+ /*********** Other tests ***********/
756
+
757
+ TEST_METHOD(50) {
758
+ // The pool is considered to be at full capacity if and only
759
+ // if all SuperGroups are at full capacity.
760
+ Options options = createOptions();
761
+ Options options2 = createOptions();
762
+ options2.appGroupName = "test";
763
+
764
+ pool->setMax(2);
765
+ pool->asyncGet(options, callback);
766
+ EVENTUALLY(5,
767
+ result = number == 1;
768
+ );
769
+
770
+ pool->asyncGet(options2, callback);
771
+ EVENTUALLY(5,
772
+ result = number == 2;
773
+ );
774
+
775
+ ensure_equals(pool->getProcessCount(), 2u);
776
+ ensure(pool->atFullCapacity());
777
+ pool->detachSuperGroup(pool->getSuperGroup("test"));
778
+ ensure(!pool->atFullCapacity());
779
+ }
780
+
781
+ TEST_METHOD(51) {
782
+ // If the pool is at full capacity, then increasing 'max' will cause
783
+ // new processes to be spawned. Any queued get requests are processed
784
+ // as those new processes become available or as existing processes
785
+ // become available.
786
+ Options options = createOptions();
787
+ retainSessions = true;
788
+ pool->setMax(1);
789
+
790
+ pool->asyncGet(options, callback);
791
+ pool->asyncGet(options, callback);
792
+ pool->asyncGet(options, callback);
793
+ EVENTUALLY(5,
794
+ result = number == 1;
795
+ );
796
+
797
+ pool->setMax(4);
798
+ EVENTUALLY(5,
799
+ result = number == 3;
800
+ );
801
+ ensure_equals(pool->getProcessCount(), 3u);
802
+ }
803
+
804
+ TEST_METHOD(52) {
805
+ // Each spawned process has a GUPID, which can be looked up
806
+ // through findProcessByGupid().
807
+ Options options = createOptions();
808
+ pool->asyncGet(options, callback);
809
+ EVENTUALLY(5,
810
+ result = number == 1;
811
+ );
812
+ string gupid = currentSession->getProcess()->gupid;
813
+ ensure(!gupid.empty());
814
+ ensure_equals(currentSession->getProcess(), pool->findProcessByGupid(gupid));
815
+ }
816
+
817
+ TEST_METHOD(53) {
818
+ // findProcessByGupid() returns a NULL pointer if there is
819
+ // no matching process.
820
+ ensure(pool->findProcessByGupid("none") == NULL);
821
+ }
822
+
823
+ TEST_METHOD(54) {
824
+ // Test process idle cleaning.
825
+ Options options = createOptions();
826
+ retainSessions = true;
827
+ pool->setMaxIdleTime(50000);
828
+ pool->asyncGet(options, callback);
829
+ pool->asyncGet(options, callback);
830
+ EVENTUALLY(2,
831
+ result = number == 2;
832
+ );
833
+ ensure_equals(pool->getProcessCount(), 2u);
834
+
835
+ currentSession.reset();
836
+ sessions.pop_back();
837
+
838
+ // One of the processes still has a session open and should
839
+ // not be idle cleaned.
840
+ EVENTUALLY(2,
841
+ result = pool->getProcessCount() == 1;
842
+ );
843
+ SHOULD_NEVER_HAPPEN(150,
844
+ result = pool->getProcessCount() == 0;
845
+ );
846
+
847
+ // It shouldn't clean more processes than minInstances allows.
848
+ sessions.clear();
849
+ SHOULD_NEVER_HAPPEN(150,
850
+ result = pool->getProcessCount() == 0;
851
+ );
852
+ }
853
+
854
+ TEST_METHOD(55) {
855
+ // Test spawner idle cleaning.
856
+ Options options = createOptions();
857
+ options.appGroupName = "test1";
858
+ Options options2 = createOptions();
859
+ options2.appGroupName = "test2";
860
+
861
+ retainSessions = true;
862
+ pool->setMaxIdleTime(50000);
863
+ pool->asyncGet(options, callback);
864
+ pool->asyncGet(options2, callback);
865
+ EVENTUALLY(2,
866
+ result = number == 2;
867
+ );
868
+ ensure_equals(pool->getProcessCount(), 2u);
869
+
870
+ EVENTUALLY(2,
871
+ SpawnerPtr spawner = pool->getSuperGroup("test1")->defaultGroup->spawner;
872
+ result = static_pointer_cast<DummySpawner>(spawner)->cleanCount >= 1;
873
+ );
874
+ EVENTUALLY(2,
875
+ SpawnerPtr spawner = pool->getSuperGroup("test2")->defaultGroup->spawner;
876
+ result = static_pointer_cast<DummySpawner>(spawner)->cleanCount >= 1;
877
+ );
878
+ }
879
+
880
+ TEST_METHOD(56) {
881
+ // It should restart the app if restart.txt is created or updated.
882
+ TempDirCopy dir("stub/wsgi", "tmp.wsgi");
883
+ Options options = createOptions();
884
+ options.appRoot = "tmp.wsgi";
885
+ options.appType = "wsgi";
886
+ options.spawnMethod = "direct";
887
+ ProcessPtr process;
888
+ pool->setMax(1);
889
+
890
+ // Send normal request.
891
+ ensure_equals(sendRequest(options, "/"), "hello <b>world</b>");
892
+
893
+ // Modify application; it shouldn't have effect yet.
894
+ writeFile("tmp.wsgi/passenger_wsgi.py",
895
+ "def application(env, start_response):\n"
896
+ " start_response('200 OK', [('Content-Type', 'text/html')])\n"
897
+ " return ['restarted']\n");
898
+ ensure_equals(sendRequest(options, "/"), "hello <b>world</b>");
899
+
900
+ // Create restart.txt and send request again. The change should now be activated.
901
+ touchFile("tmp.wsgi/tmp/restart.txt", 1);
902
+ ensure_equals(sendRequest(options, "/"), "restarted");
903
+
904
+ // Modify application again; it shouldn't have effect yet.
905
+ writeFile("tmp.wsgi/passenger_wsgi.py",
906
+ "def application(env, start_response):\n"
907
+ " start_response('200 OK', [('Content-Type', 'text/html')])\n"
908
+ " return ['restarted 2']\n");
909
+ ensure_equals(sendRequest(options, "/"), "restarted");
910
+
911
+ // Touch restart.txt and send request again. The change should now be activated.
912
+ touchFile("tmp.wsgi/tmp/restart.txt", 2);
913
+ ensure_equals(sendRequest(options, "/"), "restarted 2");
914
+ }
915
+
916
+ TEST_METHOD(57) {
917
+ // Test spawn exceptions.
918
+ TempDirCopy dir("stub/wsgi", "tmp.wsgi");
919
+ Options options = createOptions();
920
+ options.appRoot = "tmp.wsgi";
921
+ options.appType = "wsgi";
922
+ options.spawnMethod = "direct";
923
+ spawnerFactory->forwardStderr = false;
924
+
925
+ writeFile("tmp.wsgi/passenger_wsgi.py",
926
+ "import sys\n"
927
+ "sys.stderr.write('Something went wrong!')\n"
928
+ "exit(1)\n");
929
+ pool->asyncGet(options, callback);
930
+ EVENTUALLY(5,
931
+ result = number == 1;
932
+ );
933
+
934
+ ensure(currentException != NULL);
935
+ shared_ptr<SpawnException> e = dynamic_pointer_cast<SpawnException>(currentException);
936
+ ensure_equals(e->getErrorPage(), "Something went wrong!");
937
+ }
938
+
939
+ TEST_METHOD(58) {
940
+ // If a process fails to spawn, then it stops trying to spawn minProcesses processes.
941
+ TempDirCopy dir("stub/wsgi", "tmp.wsgi");
942
+ Options options = createOptions();
943
+ options.appRoot = "tmp.wsgi";
944
+ options.appType = "wsgi";
945
+ options.spawnMethod = "direct";
946
+ options.minProcesses = 4;
947
+ spawnerFactory->forwardStderr = false;
948
+
949
+ writeFile("tmp.wsgi/counter", "0");
950
+ // Our application starts successfully the first two times,
951
+ // and fails all the other times.
952
+ writeFile("tmp.wsgi/passenger_wsgi.py",
953
+ "import sys\n"
954
+
955
+ "def application(env, start_response):\n"
956
+ " pass\n"
957
+
958
+ "counter = int(open('counter', 'r').read())\n"
959
+ "f = open('counter', 'w')\n"
960
+ "f.write(str(counter + 1))\n"
961
+ "f.close()\n"
962
+ "if counter >= 2:\n"
963
+ " sys.stderr.write('Something went wrong!')\n"
964
+ " exit(1)\n");
965
+
966
+ pool->asyncGet(options, callback);
967
+ EVENTUALLY(5,
968
+ result = number == 1;
969
+ );
970
+ EVENTUALLY(5,
971
+ result = pool->getProcessCount() == 2;
972
+ );
973
+ EVENTUALLY(2,
974
+ result = !pool->getSuperGroup("tmp.wsgi")->defaultGroup->spawning();
975
+ );
976
+ SHOULD_NEVER_HAPPEN(500,
977
+ result = pool->getProcessCount() > 2;
978
+ );
979
+ }
980
+
981
+ TEST_METHOD(59) {
982
+ // It removes the process from the pool if session->initiate() fails.
983
+ Options options = createOptions();
984
+ options.appRoot = "stub/wsgi";
985
+ options.appType = "wsgi";
986
+ options.spawnMethod = "direct";
987
+
988
+ pool->asyncGet(options, callback);
989
+ EVENTUALLY(5,
990
+ result = number == 1;
991
+ );
992
+ pid_t pid = currentSession->getPid();
993
+
994
+ kill(pid, SIGTERM);
995
+ // Wait until process is gone.
996
+ EVENTUALLY(5,
997
+ result = kill(pid, 0) == -1 && (errno == ESRCH || errno == EPERM || errno == ECHILD);
998
+ );
999
+
1000
+ try {
1001
+ currentSession->initiate();
1002
+ fail("Initiate is supposed to fail");
1003
+ } catch (const SystemException &e) {
1004
+ ensure_equals(e.code(), ECONNREFUSED);
1005
+ }
1006
+ ensure_equals(pool->getProcessCount(), 0u);
1007
+ }
1008
+
1009
+ TEST_METHOD(60) {
1010
+ // When a process has become idle, and there are waiters on the pool,
1011
+ // consider detaching it in order to satisfy a waiter.
1012
+ Options options1 = createOptions();
1013
+ Options options2 = createOptions();
1014
+ options2.appRoot = "stub/wsgi";
1015
+ options2.allowTrashingNonIdleProcesses = false;
1016
+
1017
+ retainSessions = true;
1018
+ pool->setMax(2);
1019
+ pool->asyncGet(options1, callback);
1020
+ pool->asyncGet(options1, callback);
1021
+ EVENTUALLY(3,
1022
+ result = pool->getProcessCount() == 2;
1023
+ );
1024
+ pool->asyncGet(options2, callback);
1025
+ ensure_equals(pool->getWaitlist.size(), 1u);
1026
+ ensure_equals(number, 2);
1027
+
1028
+ currentSession.reset();
1029
+ sessions.pop_front();
1030
+ EVENTUALLY(3,
1031
+ result = number == 3;
1032
+ );
1033
+ ensure_equals(pool->getProcessCount(), 2u);
1034
+ SuperGroupPtr superGroup1 = pool->superGroups.get("stub/rack");
1035
+ SuperGroupPtr superGroup2 = pool->superGroups.get("stub/rack");
1036
+ ensure_equals(superGroup1->defaultGroup->count, 1);
1037
+ ensure_equals(superGroup2->defaultGroup->count, 1);
1038
+ }
1039
+
1040
+ TEST_METHOD(61) {
1041
+ // A process is detached after processing maxRequests sessions.
1042
+ {
1043
+ Ticket ticket;
1044
+ Options options = createOptions();
1045
+ options.maxRequests = 5;
1046
+ pool->setMax(1);
1047
+ pool->get(options, &ticket).reset();
1048
+
1049
+ vector<ProcessPtr> processes = pool->getProcesses();
1050
+ ensure_equals(processes.size(), 1u);
1051
+ pid_t origPid = processes[0]->pid;
1052
+
1053
+ for (int i = 0; i < 3; i++) {
1054
+ pool->get(options, &ticket).reset();
1055
+ processes = pool->getProcesses();
1056
+ ensure_equals(processes.size(), 1u);
1057
+ ensure_equals(processes[0]->pid, origPid);
1058
+ }
1059
+
1060
+ pool->get(options, &ticket).reset();
1061
+ }
1062
+ EVENTUALLY(2,
1063
+ result = pool->getProcessCount() == 0;
1064
+ );
1065
+ }
1066
+
1067
+ TEST_METHOD(62) {
1068
+ // If we restart while spawning is in progress, then the spawn
1069
+ // loop will exit as soon as it has detected that we're restarting.
1070
+ TempDirCopy dir("stub/wsgi", "tmp.wsgi");
1071
+ spawnerFactory->dummySpawnTime = 20000;
1072
+ spawnerFactory->dummySpawnerCreationSleepTime = 100000;
1073
+
1074
+ Options options = createOptions();
1075
+ options.appRoot = "tmp.wsgi";
1076
+ options.minProcesses = 3;
1077
+
1078
+ // Trigger spawn loop. The spawn loop itself won't take longer than 3*20=60 msec.
1079
+ pool->findOrCreateGroup(options);
1080
+ ScopedLock l(pool->syncher);
1081
+ pool->asyncGet(options, callback, false);
1082
+ // Wait until spawn loop tries to grab the lock.
1083
+ EVENTUALLY(3,
1084
+ LockGuard l2(pool->debugSyncher);
1085
+ result = pool->spawnLoopIteration == 1;
1086
+ );
1087
+ l.unlock();
1088
+
1089
+ // At this point, the spawn loop is about to attach its first spawned
1090
+ // process to the group. We wait until it has succeeded doing so.
1091
+ // Remaining maximum time in the spawn loop: 2*20=40 msec.
1092
+ EVENTUALLY2(200, 0,
1093
+ result = pool->getProcessCount() == 1;
1094
+ );
1095
+
1096
+ // Trigger restart. It will immediately detach the sole process in the pool,
1097
+ // and it will finish after approximately 100 msec,
1098
+ // allowing the spawn loop to detect that the restart flag is true.
1099
+ touchFile("tmp.wsgi/tmp/restart.txt");
1100
+ pool->asyncGet(options, callback);
1101
+ ensure_equals("(1)", pool->getProcessCount(), 0u);
1102
+
1103
+ // The spawn loop will succeed at spawning the second process.
1104
+ // Upon attaching it, it should detect the restart the stop,
1105
+ // so that it never spawns the third process.
1106
+ SHOULD_NEVER_HAPPEN(300,
1107
+ LockGuard l2(pool->debugSyncher);
1108
+ result = pool->spawnLoopIteration > 2;
1109
+ );
1110
+ ensure_equals("(2)", pool->getProcessCount(), 1u);
1111
+ }
1112
+
1113
+ TEST_METHOD(63) {
1114
+ // If a get() request comes in while the restart is in progress, then
1115
+ // that get() request will be put into the get waiters list, which will
1116
+ // be processed after spawning is done.
1117
+
1118
+ // Spawn 2 processes.
1119
+ TempDirCopy dir("stub/wsgi", "tmp.wsgi");
1120
+ Options options = createOptions();
1121
+ options.appRoot = "tmp.wsgi";
1122
+ options.minProcesses = 2;
1123
+ pool->asyncGet(options, callback);
1124
+ EVENTUALLY(2,
1125
+ result = pool->getProcessCount() == 2;
1126
+ );
1127
+
1128
+ // Trigger a restart. The creation of the new spawner should take a while.
1129
+ spawnerFactory->dummySpawnerCreationSleepTime = 20000;
1130
+ touchFile("tmp.wsgi/tmp/restart.txt");
1131
+ pool->asyncGet(options, callback);
1132
+ GroupPtr group = pool->findOrCreateGroup(options);
1133
+ ensure_equals(pool->getProcessCount(), 0u);
1134
+ ensure_equals(group->getWaitlist.size(), 1u);
1135
+
1136
+ // Now that the restart is in progress, perform a get().
1137
+ pool->asyncGet(options, callback);
1138
+ ensure_equals(group->getWaitlist.size(), 2u);
1139
+ EVENTUALLY(2,
1140
+ result = number == 3;
1141
+ );
1142
+ ensure_equals("The restart function respects minProcesses",
1143
+ pool->getProcessCount(), 2u);
1144
+ }
1145
+
1146
+ TEST_METHOD(64) {
1147
+ // If a process fails to spawn, it sends a SpawnException result to all get waiters.
1148
+ TempDirCopy dir("stub/wsgi", "tmp.wsgi");
1149
+ Options options = createOptions();
1150
+ options.appRoot = "tmp.wsgi";
1151
+ options.appType = "wsgi";
1152
+ options.spawnMethod = "direct";
1153
+ spawnerFactory->forwardStderr = false;
1154
+ pool->setMax(1);
1155
+
1156
+ writeFile("tmp.wsgi/passenger_wsgi.py",
1157
+ "import os, time, sys\n"
1158
+ "\n"
1159
+ "def file_exists(filename):\n"
1160
+ " try:\n"
1161
+ " os.stat(filename)\n"
1162
+ " return True\n"
1163
+ " except OSError:\n"
1164
+ " return False\n"
1165
+ "\n"
1166
+ "f = open('spawned.txt', 'w')\n"
1167
+ "f.write(str(os.getpid()))\n"
1168
+ "f.close()\n"
1169
+ "while not file_exists('continue.txt'):\n"
1170
+ " time.sleep(0.05)\n"
1171
+ "sys.stderr.write('Something went wrong!')\n"
1172
+ "exit(1)\n");
1173
+
1174
+ retainSessions = true;
1175
+ pool->asyncGet(options, callback);
1176
+ pool->asyncGet(options, callback);
1177
+ pool->asyncGet(options, callback);
1178
+ pool->asyncGet(options, callback);
1179
+
1180
+ EVENTUALLY(5,
1181
+ result = fileExists("tmp.wsgi/spawned.txt");
1182
+ );
1183
+ usleep(20000);
1184
+ writeFile("tmp.wsgi/passenger_wsgi.py", readAll("stub/wsgi/passenger_wsgi.py"));
1185
+ pid_t pid = (pid_t) stringToLL(readAll("tmp.wsgi/spawned.txt"));
1186
+ kill(pid, SIGTERM);
1187
+ EVENTUALLY(5,
1188
+ result = number == 4;
1189
+ );
1190
+ ensure_equals(pool->getProcessCount(), 0u);
1191
+ ensure(sessions.empty());
1192
+ }
1193
+
1194
+ TEST_METHOD(65) {
1195
+ // If a process fails to spawn, the existing processes
1196
+ // are kept alive.
1197
+ TempDirCopy dir("stub/wsgi", "tmp.wsgi");
1198
+ Options options = createOptions();
1199
+ options.appRoot = "tmp.wsgi";
1200
+ options.appType = "wsgi";
1201
+ options.spawnMethod = "direct";
1202
+ options.minProcesses = 2;
1203
+ spawnerFactory->forwardStderr = false;
1204
+
1205
+ // Spawn 2 processes.
1206
+ retainSessions = true;
1207
+ pool->asyncGet(options, callback);
1208
+ pool->asyncGet(options, callback);
1209
+ EVENTUALLY(5,
1210
+ result = number == 2;
1211
+ );
1212
+ ensure_equals(pool->getProcessCount(), 2u);
1213
+
1214
+ // Mess up the application and spawn a new one.
1215
+ writeFile("tmp.wsgi/passenger_wsgi.py",
1216
+ "import sys\n"
1217
+ "sys.stderr.write('Something went wrong!')\n"
1218
+ "exit(1)\n");
1219
+ try {
1220
+ Ticket ticket;
1221
+ currentSession = pool->get(options, &ticket);
1222
+ fail("SpawnException expected");
1223
+ } catch (const SpawnException &) {
1224
+ ensure_equals(pool->getProcessCount(), 2u);
1225
+ }
1226
+ }
1227
+
1228
+ // Persistent connections.
1229
+ // If one closes the session before it has reached EOF, and process's maximum concurrency
1230
+ // has already been reached, then the pool should ping the process so that it can detect
1231
+ // when the session's connection has been released by the app.
1232
+
1233
+ /*****************************/
1234
+ }