passenger 4.0.27 → 4.0.28

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 (156) hide show
  1. data.tar.gz.asc +7 -7
  2. data/.gitignore +1 -0
  3. data/NEWS +22 -0
  4. data/build/preprocessor.rb +10 -0
  5. data/build/rpm.rb +74 -65
  6. data/debian.template/rules.template +8 -0
  7. data/dev/copy_boost_headers.rb +11 -2
  8. data/doc/Users guide Apache.idmap.txt +161 -145
  9. data/doc/Users guide Apache.txt +12 -1
  10. data/doc/Users guide Nginx.idmap.txt +142 -126
  11. data/doc/Users guide Nginx.txt +14 -1
  12. data/doc/Users guide Standalone.txt +1 -0
  13. data/doc/users_guide_snippets/environment_variables.txt +1 -1
  14. data/doc/users_guide_snippets/installation.txt +2 -0
  15. data/doc/users_guide_snippets/tips.txt +118 -0
  16. data/ext/apache2/Configuration.cpp +0 -6
  17. data/ext/apache2/Configuration.hpp +0 -5
  18. data/ext/apache2/ConfigurationCommands.cpp +7 -0
  19. data/ext/apache2/ConfigurationFields.hpp +2 -0
  20. data/ext/apache2/ConfigurationSetters.cpp +24 -0
  21. data/ext/apache2/CreateDirConfig.cpp +1 -0
  22. data/ext/apache2/Hooks.cpp +0 -1
  23. data/ext/apache2/MergeDirConfig.cpp +7 -0
  24. data/ext/apache2/SetHeaders.cpp +5 -1
  25. data/ext/boost/cregex.hpp +39 -0
  26. data/ext/boost/libs/regex/src/c_regex_traits.cpp +193 -0
  27. data/ext/boost/libs/regex/src/cpp_regex_traits.cpp +117 -0
  28. data/ext/boost/libs/regex/src/cregex.cpp +660 -0
  29. data/ext/boost/libs/regex/src/instances.cpp +32 -0
  30. data/ext/boost/libs/regex/src/internals.hpp +35 -0
  31. data/ext/boost/libs/regex/src/posix_api.cpp +296 -0
  32. data/ext/boost/libs/regex/src/regex.cpp +227 -0
  33. data/ext/boost/libs/regex/src/regex_debug.cpp +59 -0
  34. data/ext/boost/libs/regex/src/regex_raw_buffer.cpp +72 -0
  35. data/ext/boost/libs/regex/src/regex_traits_defaults.cpp +692 -0
  36. data/ext/boost/libs/regex/src/static_mutex.cpp +179 -0
  37. data/ext/boost/libs/regex/src/wc_regex_traits.cpp +301 -0
  38. data/ext/boost/libs/regex/src/wide_posix_api.cpp +315 -0
  39. data/ext/boost/libs/regex/src/winstances.cpp +35 -0
  40. data/ext/boost/regex.h +100 -0
  41. data/ext/boost/regex.hpp +37 -0
  42. data/ext/boost/regex/concepts.hpp +1128 -0
  43. data/ext/boost/regex/config.hpp +435 -0
  44. data/ext/boost/regex/config/borland.hpp +72 -0
  45. data/ext/boost/regex/config/cwchar.hpp +207 -0
  46. data/ext/boost/regex/mfc.hpp +190 -0
  47. data/ext/boost/regex/pattern_except.hpp +100 -0
  48. data/ext/boost/regex/pending/object_cache.hpp +165 -0
  49. data/ext/boost/regex/pending/static_mutex.hpp +179 -0
  50. data/ext/boost/regex/pending/unicode_iterator.hpp +776 -0
  51. data/ext/boost/regex/regex_traits.hpp +35 -0
  52. data/ext/boost/regex/user.hpp +93 -0
  53. data/ext/boost/regex/v4/basic_regex.hpp +782 -0
  54. data/ext/boost/regex/v4/basic_regex_creator.hpp +1571 -0
  55. data/ext/boost/regex/v4/basic_regex_parser.hpp +2874 -0
  56. data/ext/boost/regex/v4/c_regex_traits.hpp +211 -0
  57. data/ext/boost/regex/v4/char_regex_traits.hpp +81 -0
  58. data/ext/boost/regex/v4/cpp_regex_traits.hpp +1099 -0
  59. data/ext/boost/regex/v4/cregex.hpp +330 -0
  60. data/ext/boost/regex/v4/error_type.hpp +59 -0
  61. data/ext/boost/regex/v4/fileiter.hpp +455 -0
  62. data/ext/boost/regex/v4/instances.hpp +222 -0
  63. data/ext/boost/regex/v4/iterator_category.hpp +91 -0
  64. data/ext/boost/regex/v4/iterator_traits.hpp +135 -0
  65. data/ext/boost/regex/v4/match_flags.hpp +138 -0
  66. data/ext/boost/regex/v4/match_results.hpp +702 -0
  67. data/ext/boost/regex/v4/mem_block_cache.hpp +99 -0
  68. data/ext/boost/regex/v4/perl_matcher.hpp +587 -0
  69. data/ext/boost/regex/v4/perl_matcher_common.hpp +996 -0
  70. data/ext/boost/regex/v4/perl_matcher_non_recursive.hpp +1642 -0
  71. data/ext/boost/regex/v4/perl_matcher_recursive.hpp +991 -0
  72. data/ext/boost/regex/v4/primary_transform.hpp +146 -0
  73. data/ext/boost/regex/v4/protected_call.hpp +81 -0
  74. data/ext/boost/regex/v4/regbase.hpp +180 -0
  75. data/ext/boost/regex/v4/regex.hpp +202 -0
  76. data/ext/boost/regex/v4/regex_format.hpp +1156 -0
  77. data/ext/boost/regex/v4/regex_fwd.hpp +73 -0
  78. data/ext/boost/regex/v4/regex_grep.hpp +155 -0
  79. data/ext/boost/regex/v4/regex_iterator.hpp +201 -0
  80. data/ext/boost/regex/v4/regex_match.hpp +382 -0
  81. data/ext/boost/regex/v4/regex_merge.hpp +93 -0
  82. data/ext/boost/regex/v4/regex_raw_buffer.hpp +210 -0
  83. data/ext/boost/regex/v4/regex_replace.hpp +99 -0
  84. data/ext/boost/regex/v4/regex_search.hpp +217 -0
  85. data/ext/boost/regex/v4/regex_split.hpp +172 -0
  86. data/ext/boost/regex/v4/regex_token_iterator.hpp +342 -0
  87. data/ext/boost/regex/v4/regex_traits.hpp +189 -0
  88. data/ext/boost/regex/v4/regex_traits_defaults.hpp +371 -0
  89. data/ext/boost/regex/v4/regex_workaround.hpp +232 -0
  90. data/ext/boost/regex/v4/states.hpp +301 -0
  91. data/ext/boost/regex/v4/sub_match.hpp +512 -0
  92. data/ext/boost/regex/v4/syntax_type.hpp +105 -0
  93. data/ext/boost/regex/v4/u32regex_iterator.hpp +193 -0
  94. data/ext/boost/regex/v4/u32regex_token_iterator.hpp +377 -0
  95. data/ext/boost/regex/v4/w32_regex_traits.hpp +741 -0
  96. data/ext/boost/regex_fwd.hpp +33 -0
  97. data/ext/common/AgentsStarter.h +0 -11
  98. data/ext/common/ApplicationPool2/Common.h +1 -7
  99. data/ext/common/ApplicationPool2/DirectSpawner.h +3 -3
  100. data/ext/common/ApplicationPool2/Group.h +166 -69
  101. data/ext/common/ApplicationPool2/Implementation.cpp +55 -10
  102. data/ext/common/ApplicationPool2/Options.h +45 -10
  103. data/ext/common/ApplicationPool2/PipeWatcher.h +1 -2
  104. data/ext/common/ApplicationPool2/Pool.h +29 -7
  105. data/ext/common/ApplicationPool2/Process.h +22 -3
  106. data/ext/common/ApplicationPool2/Session.h +1 -0
  107. data/ext/common/ApplicationPool2/SmartSpawner.h +5 -10
  108. data/ext/common/ApplicationPool2/Spawner.h +10 -15
  109. data/ext/common/ApplicationPool2/SuperGroup.h +10 -9
  110. data/ext/common/Constants.h +1 -3
  111. data/ext/common/Hooks.h +193 -0
  112. data/ext/common/Logging.cpp +67 -2
  113. data/ext/common/Logging.h +23 -1
  114. data/ext/common/Utils.cpp +0 -21
  115. data/ext/common/Utils.h +0 -42
  116. data/ext/common/Utils/CachedFileStat.hpp +1 -1
  117. data/ext/common/Utils/StrIntUtils.h +61 -14
  118. data/ext/common/Utils/StringMap.h +4 -0
  119. data/ext/common/agents/HelperAgent/AgentOptions.h +4 -4
  120. data/ext/common/agents/HelperAgent/Main.cpp +2 -3
  121. data/ext/common/agents/HelperAgent/RequestHandler.h +65 -2
  122. data/ext/common/agents/LoggingAgent/FilterSupport.h +3 -1
  123. data/ext/common/agents/Watchdog/Main.cpp +8 -72
  124. data/ext/nginx/CacheLocationConfig.c +29 -1
  125. data/ext/nginx/Configuration.c +0 -12
  126. data/ext/nginx/Configuration.h +0 -1
  127. data/ext/nginx/ConfigurationCommands.c +10 -0
  128. data/ext/nginx/ConfigurationFields.h +2 -0
  129. data/ext/nginx/CreateLocationConfig.c +4 -0
  130. data/ext/nginx/MergeLocationConfig.c +6 -0
  131. data/ext/oxt/system_calls.cpp +7 -1
  132. data/ext/oxt/system_calls.hpp +7 -7
  133. data/helper-scripts/node-loader.js +6 -2
  134. data/helper-scripts/rack-loader.rb +5 -2
  135. data/helper-scripts/rack-preloader.rb +5 -2
  136. data/lib/phusion_passenger.rb +1 -1
  137. data/lib/phusion_passenger/apache2/config_options.rb +8 -0
  138. data/lib/phusion_passenger/constants.rb +0 -1
  139. data/lib/phusion_passenger/nginx/config_options.rb +9 -2
  140. data/lib/phusion_passenger/platform_info/apache.rb +2 -1
  141. data/lib/phusion_passenger/platform_info/compiler.rb +15 -1
  142. data/lib/phusion_passenger/platform_info/cxx_portability.rb +2 -0
  143. data/node_lib/phusion_passenger/httplib_emulation.js +85 -17
  144. data/node_lib/phusion_passenger/request_handler.js +10 -2
  145. data/rpm/Vagrantfile +32 -0
  146. data/rpm/get_distro_id.py +4 -0
  147. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +2 -2
  148. data/test/cxx/ApplicationPool2/PoolTest.cpp +60 -9
  149. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +2 -6
  150. data/test/cxx/CachedFileStatTest.cpp +5 -5
  151. data/test/cxx/RequestHandlerTest.cpp +3 -6
  152. data/test/cxx/UtilsTest.cpp +30 -0
  153. data/test/node/httplib_emulation_spec.js +491 -0
  154. data/test/node/spec_helper.js +25 -0
  155. metadata +78 -2
  156. metadata.gz.asc +7 -7
@@ -49,16 +49,12 @@ private:
49
49
  BackgroundIOCapturerPtr stderrCapturer;
50
50
  DebugDirPtr debugDir;
51
51
  const Options *options;
52
- bool forwardStderr;
53
- int forwardStderrTo;
54
52
 
55
53
  /****** Working state ******/
56
54
  unsigned long long timeout;
57
55
 
58
56
  StartupDetails() {
59
57
  options = NULL;
60
- forwardStderr = false;
61
- forwardStderrTo = STDERR_FILENO;
62
58
  timeout = 0;
63
59
  }
64
60
  };
@@ -268,13 +264,13 @@ private:
268
264
  details.stderrCapturer =
269
265
  make_shared<BackgroundIOCapturer>(
270
266
  errorPipe.first,
271
- string("[App ") + toString(pid) + " stderr] ",
272
- config->forwardStderr);
267
+ pid,
268
+ // The cast works around a compilation problem in Clang.
269
+ (const char *) "stderr");
273
270
  details.stderrCapturer->start();
274
271
  details.debugDir = debugDir;
275
272
  details.options = &options;
276
273
  details.timeout = options.startTimeout * 1000;
277
- details.forwardStderr = config->forwardStderr;
278
274
 
279
275
  {
280
276
  this_thread::restore_interruption ri(di);
@@ -290,12 +286,12 @@ private:
290
286
  PipeWatcherPtr watcher;
291
287
 
292
288
  watcher = boost::make_shared<PipeWatcher>(adminSocket.second,
293
- "stdout", pid, config->forwardStdout);
289
+ "stdout", pid);
294
290
  watcher->initialize();
295
291
  watcher->start();
296
292
 
297
293
  watcher = boost::make_shared<PipeWatcher>(errorPipe.first,
298
- "stderr", pid, config->forwardStderr);
294
+ "stderr", pid);
299
295
  watcher->initialize();
300
296
  watcher->start();
301
297
 
@@ -777,7 +773,6 @@ public:
777
773
  details.adminSocket = result.adminSocket;
778
774
  details.io = result.io;
779
775
  details.options = &options;
780
- details.forwardStderr = config->forwardStderr;
781
776
  ProcessPtr process = negotiateSpawn(details);
782
777
  P_DEBUG("Process spawning done: appRoot=" << options.appRoot <<
783
778
  ", pid=" << process->pid);
@@ -118,8 +118,8 @@ protected:
118
118
  class BackgroundIOCapturer {
119
119
  private:
120
120
  FileDescriptor fd;
121
- string prefix;
122
- bool print;
121
+ pid_t pid;
122
+ const char *channelName;
123
123
  boost::mutex dataSyncher;
124
124
  string data;
125
125
  oxt::thread *thr;
@@ -148,16 +148,16 @@ protected:
148
148
  data.append(buf, ret);
149
149
  }
150
150
  UPDATE_TRACE_POINT();
151
- if (print && ret == 1 && buf[0] == '\n') {
152
- P_INFO(prefix);
153
- } else if (print) {
151
+ if (ret == 1 && buf[0] == '\n') {
152
+ printAppOutput(pid, channelName, "", 0);
153
+ } else {
154
154
  vector<StaticString> lines;
155
155
  if (ret > 0 && buf[ret - 1] == '\n') {
156
156
  ret--;
157
157
  }
158
158
  split(StaticString(buf, ret), '\n', lines);
159
159
  foreach (const StaticString line, lines) {
160
- P_INFO(prefix << line);
160
+ printAppOutput(pid, channelName, line.data(), line.size());
161
161
  }
162
162
  }
163
163
  }
@@ -165,10 +165,10 @@ protected:
165
165
  }
166
166
 
167
167
  public:
168
- BackgroundIOCapturer(const FileDescriptor &_fd, const string &_prefix, bool _print)
168
+ BackgroundIOCapturer(const FileDescriptor &_fd, pid_t _pid, const char *_channelName)
169
169
  : fd(_fd),
170
- prefix(_prefix),
171
- print(_print),
170
+ pid(_pid),
171
+ channelName(_channelName),
172
172
  thr(NULL)
173
173
  { }
174
174
 
@@ -344,8 +344,6 @@ protected:
344
344
  FileDescriptor adminSocket;
345
345
  FileDescriptor errorPipe;
346
346
  const Options *options;
347
- bool forwardStderr;
348
- int forwardStderrTo;
349
347
  DebugDirPtr debugDir;
350
348
 
351
349
  /****** Working state ******/
@@ -359,8 +357,6 @@ protected:
359
357
  preparation = NULL;
360
358
  pid = 0;
361
359
  options = NULL;
362
- forwardStderr = false;
363
- forwardStderrTo = STDERR_FILENO;
364
360
  spawnStartTime = 0;
365
361
  timeout = 0;
366
362
  }
@@ -792,8 +788,7 @@ protected:
792
788
  if (details.stderrCapturer != NULL) {
793
789
  details.stderrCapturer->appendToBuffer(result);
794
790
  }
795
- P_LOG(config->forwardStdout ? LVL_INFO : LVL_DEBUG,
796
- "[App " << details.pid << " stdout] " << line);
791
+ printAppOutput(details.pid, "stdout", line.data(), line.size());
797
792
  }
798
793
  }
799
794
  }
@@ -192,6 +192,9 @@ private:
192
192
  static boost::mutex &getPoolSyncher(const PoolPtr &pool);
193
193
  static void runAllActions(const vector<Callback> &actions);
194
194
  string generateSecret() const;
195
+ void runInitializationHooks() const;
196
+ void runDestructionHooks() const;
197
+ void setupInitializationOrDestructionHook(HookScriptOptions &options) const;
195
198
 
196
199
  void createInterruptableThread(const boost::function<void ()> &func, const string &name,
197
200
  unsigned int stackSize);
@@ -273,8 +276,8 @@ private:
273
276
  }
274
277
 
275
278
  while (!group->getWaitlist.empty()) {
276
- getWaitlist.push(group->getWaitlist.front());
277
- group->getWaitlist.pop();
279
+ getWaitlist.push_back(group->getWaitlist.front());
280
+ group->getWaitlist.pop_front();
278
281
  }
279
282
  detachedGroups.push_back(group);
280
283
  group->shutdown(
@@ -299,7 +302,7 @@ private:
299
302
  postLockActions.push_back(boost::bind(
300
303
  waiter.callback, session, ExceptionPtr()));
301
304
  }
302
- getWaitlist.pop();
305
+ getWaitlist.pop_front();
303
306
  }
304
307
  }
305
308
 
@@ -321,9 +324,7 @@ private:
321
324
  void doDestroy(SuperGroupPtr self, unsigned int generation, ShutdownCallback callback) {
322
325
  TRACE_POINT();
323
326
 
324
- // In the future we can run more destruction code here,
325
- // without holding the lock. Note that any destruction
326
- // code may not interfere with doInitialize().
327
+ runDestructionHooks();
327
328
 
328
329
  // Wait until 'detachedGroups' is empty.
329
330
  UPDATE_TRACE_POINT();
@@ -398,7 +399,7 @@ public:
398
399
  * if !getWaitlist.empty():
399
400
  * state == INITIALIZING
400
401
  */
401
- std::queue<GetWaiter> getWaitlist;
402
+ deque<GetWaiter> getWaitlist;
402
403
 
403
404
  /**
404
405
  * Groups which are being shut down right now. These Groups contain a
@@ -575,7 +576,7 @@ public:
575
576
  SessionPtr get(const Options &newOptions, const GetCallback &callback) {
576
577
  switch (state) {
577
578
  case INITIALIZING:
578
- getWaitlist.push(GetWaiter(newOptions, callback));
579
+ getWaitlist.push_back(GetWaiter(newOptions, callback));
579
580
  verifyInvariants();
580
581
  return SessionPtr();
581
582
  case READY:
@@ -595,7 +596,7 @@ public:
595
596
  }
596
597
  case DESTROYING:
597
598
  case DESTROYED:
598
- getWaitlist.push(GetWaiter(newOptions, callback));
599
+ getWaitlist.push_back(GetWaiter(newOptions, callback));
599
600
  setState(INITIALIZING);
600
601
  createInterruptableThread(
601
602
  boost::bind(
@@ -48,8 +48,6 @@
48
48
 
49
49
  #define DEFAULT_LOG_LEVEL 0
50
50
 
51
- #define DEFAULT_MAX_INSTANCES_PER_APP 0
52
-
53
51
  #define DEFAULT_MAX_POOL_SIZE 6
54
52
 
55
53
  #define DEFAULT_NODEJS "node"
@@ -80,7 +78,7 @@
80
78
 
81
79
  #define NGINX_DOC_URL "http://www.modrails.com/documentation/Users%20guide%20Nginx.html"
82
80
 
83
- #define PASSENGER_VERSION "4.0.27"
81
+ #define PASSENGER_VERSION "4.0.28"
84
82
 
85
83
  #define POOL_HELPER_THREAD_STACK_SIZE 262144
86
84
 
@@ -0,0 +1,193 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2010-2013 Phusion
4
+ *
5
+ * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ */
25
+ #ifndef _PASSENGER_HOOKS_H_
26
+ #define _PASSENGER_HOOKS_H_
27
+
28
+ #include <string>
29
+ #include <vector>
30
+ #include <utility>
31
+
32
+ #include <oxt/backtrace.hpp>
33
+
34
+ #include <sys/types.h>
35
+ #include <sys/wait.h>
36
+ #include <cstdio>
37
+ #include <cerrno>
38
+ #include <cstring>
39
+ #include <cctype>
40
+ #include <stdlib.h>
41
+ #include <unistd.h>
42
+
43
+ #include <Logging.h>
44
+ #include <Utils.h>
45
+ #include <Utils/StrIntUtils.h>
46
+ #include <Utils/VariantMap.h>
47
+
48
+ namespace Passenger {
49
+
50
+ using namespace std;
51
+ using namespace oxt;
52
+
53
+
54
+ struct HookScriptOptions {
55
+ // Required.
56
+ string name;
57
+ string spec;
58
+
59
+ // Optional.
60
+ const VariantMap *agentsOptions;
61
+ vector< pair<string, string> > environment;
62
+
63
+ HookScriptOptions()
64
+ : agentsOptions(NULL)
65
+ { }
66
+ };
67
+
68
+ namespace {
69
+ inline vector< pair<string, string> >
70
+ agentsOptionsToEnvVars(const VariantMap &agentsOptions) {
71
+ vector< pair<string, string> > result;
72
+ VariantMap::ConstIterator it, end = agentsOptions.end();
73
+
74
+ result.reserve(agentsOptions.size());
75
+ for (it = agentsOptions.begin(); it != end; it++) {
76
+ string key = "PASSENGER_";
77
+ const char *data = it->first.data();
78
+ const char *end = it->first.data() + it->first.size();
79
+
80
+ while (data < end) {
81
+ key.append(1, toupper(*data));
82
+ data++;
83
+ }
84
+ result.push_back(make_pair(key, it->second));
85
+ }
86
+
87
+ return result;
88
+ }
89
+
90
+ inline void
91
+ setEnvVarsFromVector(const vector< pair<string, string> > &envvars) {
92
+ vector< pair<string, string> >::const_iterator it;
93
+
94
+ for (it = envvars.begin(); it != envvars.end(); it++) {
95
+ setenv(it->first.c_str(), it->second.c_str(), 1);
96
+ }
97
+ }
98
+
99
+ inline void
100
+ createHookScriptEnvironment(const HookScriptOptions &options, vector< pair<string, string> > &envvars) {
101
+ vector< pair<string, string> >::const_iterator it, end = options.environment.end();
102
+ if (options.agentsOptions) {
103
+ envvars = agentsOptionsToEnvVars(*options.agentsOptions);
104
+ }
105
+ for (it = options.environment.begin(); it != end; it++) {
106
+ envvars.push_back(*it);
107
+ }
108
+ }
109
+
110
+ inline void
111
+ parseHookScriptSpec(const HookScriptOptions &options, vector<string> &commands) {
112
+ split(options.spec, ';', commands);
113
+
114
+ vector<string>::iterator it, end = commands.end();
115
+ for (it = commands.begin(); it != end; it++) {
116
+ *it = strip(*it);
117
+ }
118
+ }
119
+ }
120
+
121
+ inline bool
122
+ runSingleHookScript(HookScriptOptions &options, const string &command,
123
+ const vector< pair<string, string> > &envvars)
124
+ {
125
+ TRACE_POINT_WITH_DATA(command.c_str());
126
+ pid_t pid;
127
+ int e, status;
128
+
129
+ P_INFO("Running " << options.name << " hook script: " << command);
130
+
131
+ pid = fork();
132
+ if (pid == 0) {
133
+ resetSignalHandlersAndMask();
134
+ disableMallocDebugging();
135
+ closeAllFileDescriptors(2);
136
+ setEnvVarsFromVector(envvars);
137
+
138
+ execlp(command.c_str(), command.c_str(), (const char * const) 0);
139
+ e = errno;
140
+ fprintf(stderr, "*** ERROR: Cannot execute %s hook script %s: %s (errno=%d)\n",
141
+ options.name.c_str(), command.c_str(), strerror(e), e);
142
+ fflush(stderr);
143
+ _exit(1);
144
+ return true; // Never reached.
145
+
146
+ } else if (pid == -1) {
147
+ e = errno;
148
+ P_ERROR("Cannot fork a process for hook script " << command <<
149
+ ": " << strerror(e) << " (errno=" << e << ")");
150
+ return false;
151
+
152
+ } else if (waitpid(pid, &status, 0) == -1) {
153
+ e = errno;
154
+ P_ERROR("Unable to wait for hook script " << command <<
155
+ " (PID " << pid << "): " << strerror(e) << " (errno=" <<
156
+ e << ")");
157
+ return false;
158
+
159
+ } else {
160
+ P_INFO("Hook script " << command << " (PID " << pid <<
161
+ ") exited with status " << WEXITSTATUS(status));
162
+ return WEXITSTATUS(status) == 0;
163
+ }
164
+ }
165
+
166
+ inline bool
167
+ runHookScripts(HookScriptOptions &options) {
168
+ TRACE_POINT();
169
+ if (options.spec.empty()) {
170
+ return true;
171
+ }
172
+
173
+ vector<string> commands;
174
+ vector< pair<string, string> > envvars;
175
+
176
+ parseHookScriptSpec(options, commands);
177
+ if (commands.empty()) {
178
+ return true;
179
+ }
180
+ createHookScriptEnvironment(options, envvars);
181
+
182
+ foreach (const string command, commands) {
183
+ if (!runSingleHookScript(options, command, envvars)) {
184
+ return false;
185
+ }
186
+ }
187
+ return true;
188
+ }
189
+
190
+
191
+ } // namespace Passenger
192
+
193
+ #endif /* _PASSENGER_HOOKS_H_ */
@@ -27,6 +27,7 @@
27
27
  #include <fcntl.h>
28
28
  #include <unistd.h>
29
29
  #include <Logging.h>
30
+ #include <StaticString.h>
30
31
  #include <Utils/StrIntUtils.h>
31
32
  #include <Utils/IOUtils.h>
32
33
 
@@ -34,6 +35,7 @@ namespace Passenger {
34
35
 
35
36
  int _logLevel = 0;
36
37
  int _logOutput = STDERR_FILENO;
38
+ static bool printAppOutputAsDebuggingMessages = false;
37
39
 
38
40
  int
39
41
  getLogLevel() {
@@ -86,8 +88,8 @@ _prepareLogEntry(std::stringstream &sstream, const char *file, unsigned int line
86
88
  " ]: ";
87
89
  }
88
90
 
89
- void
90
- _writeLogEntry(const std::string &str) {
91
+ static void
92
+ _writeLogEntry(const StaticString &str) {
91
93
  try {
92
94
  writeExact(_logOutput, str.data(), str.size());
93
95
  } catch (const SystemException &) {
@@ -101,5 +103,68 @@ _writeLogEntry(const std::string &str) {
101
103
  }
102
104
  }
103
105
 
106
+ void
107
+ _writeLogEntry(const std::string &str) {
108
+ _writeLogEntry(StaticString(str));
109
+ }
110
+
111
+ static void
112
+ realPrintAppOutput(char *buf, unsigned int bufSize,
113
+ const char *pidStr, unsigned int pidStrLen,
114
+ const char *channelName, unsigned int channelNameLen,
115
+ const char *message, unsigned int messageLen)
116
+ {
117
+ char *pos = buf;
118
+ char *end = buf + bufSize;
119
+
120
+ pos = appendData(pos, end, "App ");
121
+ pos = appendData(pos, end, pidStr, pidStrLen);
122
+ pos = appendData(pos, end, " ");
123
+ pos = appendData(pos, end, channelName, channelNameLen);
124
+ pos = appendData(pos, end, ": ");
125
+ pos = appendData(pos, end, message, messageLen);
126
+ pos = appendData(pos, end, "\n");
127
+ _writeLogEntry(StaticString(buf, pos - buf));
128
+ }
129
+
130
+ void
131
+ printAppOutput(pid_t pid, const char *channelName, const char *message, unsigned int size) {
132
+ if (printAppOutputAsDebuggingMessages) {
133
+ P_DEBUG("App " << pid << " " << channelName << ": " << StaticString(message, size));
134
+ } else {
135
+ char pidStr[sizeof("4294967295")];
136
+ unsigned int pidStrLen, channelNameLen, totalLen;
137
+
138
+ try {
139
+ pidStrLen = integerToOtherBase<pid_t, 10>(pid, pidStr, sizeof(pidStr));
140
+ } catch (const std::length_error &) {
141
+ pidStr[0] = '?';
142
+ pidStr[1] = '\0';
143
+ pidStrLen = 1;
144
+ }
145
+
146
+ channelNameLen = strlen(channelName);
147
+ totalLen = (sizeof("App X Y: \n") - 2) + pidStrLen + channelNameLen + size;
148
+ if (totalLen < 1024) {
149
+ char buf[1024];
150
+ realPrintAppOutput(buf, sizeof(buf),
151
+ pidStr, pidStrLen,
152
+ channelName, channelNameLen,
153
+ message, size);
154
+ } else {
155
+ DynamicBuffer buf(totalLen);
156
+ realPrintAppOutput(buf.data, totalLen,
157
+ pidStr, pidStrLen,
158
+ channelName, channelNameLen,
159
+ message, size);
160
+ }
161
+ }
162
+ }
163
+
164
+ void
165
+ setPrintAppOutputAsDebuggingMessages(bool enabled) {
166
+ printAppOutputAsDebuggingMessages = enabled;
167
+ }
168
+
104
169
  } // namespace Passenger
105
170