passenger 4.0.48 → 4.0.49

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 (218) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +36 -2
  5. data/.travis.yml +1 -1
  6. data/CHANGELOG +16 -0
  7. data/Rakefile +0 -1
  8. data/build/apache2.rb +4 -4
  9. data/build/common_library.rb +18 -18
  10. data/build/cplusplus_support.rb +2 -2
  11. data/build/documentation.rb +1 -1
  12. data/build/integration_tests.rb +12 -4
  13. data/build/misc.rb +12 -7
  14. data/build/packaging.rb +14 -14
  15. data/build/preprocessor.rb +10 -10
  16. data/build/rake_extensions.rb +11 -11
  17. data/build/ruby_extension.rb +2 -2
  18. data/dev/ci/inituidgid +24 -0
  19. data/dev/ci/run_jenkins.sh +57 -0
  20. data/dev/ci/run_rpm_tests.sh +77 -0
  21. data/dev/{run_travis.sh → ci/run_travis.sh} +60 -4
  22. data/doc/Users guide Nginx.txt +2 -2
  23. data/doc/users_guide_snippets/environment_variables.txt +0 -2
  24. data/doc/users_guide_snippets/tips.txt +20 -1
  25. data/ext/apache2/Bucket.cpp +18 -18
  26. data/ext/apache2/Bucket.h +4 -4
  27. data/ext/apache2/Configuration.cpp +7 -7
  28. data/ext/apache2/Configuration.hpp +43 -43
  29. data/ext/apache2/DirectoryMapper.h +5 -5
  30. data/ext/apache2/Hooks.cpp +142 -142
  31. data/ext/apache2/MergeDirConfig.cpp +40 -40
  32. data/ext/common/Account.h +17 -17
  33. data/ext/common/AccountsDatabase.h +9 -9
  34. data/ext/common/AgentsStarter.cpp +2 -2
  35. data/ext/common/AgentsStarter.h +40 -40
  36. data/ext/common/ApplicationPool2/Common.h +10 -6
  37. data/ext/common/ApplicationPool2/ComponentInfo.h +2 -2
  38. data/ext/common/ApplicationPool2/DirectSpawner.h +17 -17
  39. data/ext/common/ApplicationPool2/DummySpawner.h +5 -5
  40. data/ext/common/ApplicationPool2/Group.h +54 -38
  41. data/ext/common/ApplicationPool2/Implementation.cpp +76 -49
  42. data/ext/common/ApplicationPool2/Options.h +98 -91
  43. data/ext/common/ApplicationPool2/Pool.h +70 -69
  44. data/ext/common/ApplicationPool2/Process.h +21 -21
  45. data/ext/common/ApplicationPool2/Session.h +11 -11
  46. data/ext/common/ApplicationPool2/SmartSpawner.h +60 -60
  47. data/ext/common/ApplicationPool2/Socket.h +19 -19
  48. data/ext/common/ApplicationPool2/Spawner.h +64 -72
  49. data/ext/common/ApplicationPool2/SpawnerFactory.h +4 -4
  50. data/ext/common/ApplicationPool2/SuperGroup.h +41 -41
  51. data/ext/common/BackgroundEventLoop.cpp +1 -1
  52. data/ext/common/BackgroundEventLoop.h +2 -2
  53. data/ext/common/Constants.h +1 -1
  54. data/ext/common/EventedBufferedInput.h +5 -5
  55. data/ext/common/EventedClient.h +51 -51
  56. data/ext/common/EventedMessageServer.h +39 -39
  57. data/ext/common/EventedServer.h +32 -32
  58. data/ext/common/Exceptions.h +23 -23
  59. data/ext/common/FileDescriptor.h +18 -18
  60. data/ext/common/Logging.cpp +1 -1
  61. data/ext/common/MessageClient.h +27 -27
  62. data/ext/common/MessageReadersWriters.h +79 -79
  63. data/ext/common/MessageServer.h +59 -59
  64. data/ext/common/RandomGenerator.h +12 -12
  65. data/ext/common/ResourceLocator.h +8 -8
  66. data/ext/common/SafeLibev.h +54 -25
  67. data/ext/common/ServerInstanceDir.h +31 -31
  68. data/ext/common/StaticString.h +50 -48
  69. data/ext/common/Utils.cpp +73 -78
  70. data/ext/common/Utils.h +6 -6
  71. data/ext/common/Utils/Base64.cpp +3 -3
  72. data/ext/common/Utils/Base64.h +7 -7
  73. data/ext/common/Utils/BlockingQueue.h +9 -9
  74. data/ext/common/Utils/BufferedIO.h +17 -17
  75. data/ext/common/Utils/CachedFileStat.hpp +16 -16
  76. data/ext/common/Utils/Dechunker.h +25 -25
  77. data/ext/common/Utils/FileChangeChecker.h +10 -10
  78. data/ext/common/Utils/MemZeroGuard.h +5 -5
  79. data/ext/common/Utils/MemoryBarrier.h +1 -1
  80. data/ext/common/Utils/MessageIO.h +61 -61
  81. data/ext/common/Utils/ProcessMetricsCollector.h +40 -40
  82. data/ext/common/Utils/ScopeGuard.h +7 -7
  83. data/ext/common/Utils/SpeedMeter.h +1 -1
  84. data/ext/common/Utils/StrIntUtils.cpp +13 -13
  85. data/ext/common/Utils/StrIntUtils.h +3 -3
  86. data/ext/common/Utils/StringScanning.h +5 -5
  87. data/ext/common/Utils/SystemMetricsCollector.h +2 -2
  88. data/ext/common/Utils/SystemTime.h +10 -10
  89. data/ext/common/Utils/Template.h +2 -2
  90. data/ext/common/Utils/Timer.h +6 -6
  91. data/ext/common/Utils/VariantMap.h +29 -29
  92. data/ext/common/agents/Base.cpp +19 -19
  93. data/ext/common/agents/HelperAgent/AgentOptions.h +1 -1
  94. data/ext/common/agents/HelperAgent/FileBackedPipe.h +6 -6
  95. data/ext/common/agents/HelperAgent/Main.cpp +44 -43
  96. data/ext/common/agents/HelperAgent/RequestHandler.cpp +4 -4
  97. data/ext/common/agents/HelperAgent/RequestHandler.h +29 -28
  98. data/ext/common/agents/HelperAgent/ScgiRequestParser.h +56 -50
  99. data/ext/common/agents/LoggingAgent/AdminController.h +8 -8
  100. data/ext/common/agents/LoggingAgent/DataStoreId.h +17 -17
  101. data/ext/common/agents/LoggingAgent/FilterSupport.h +167 -167
  102. data/ext/common/agents/LoggingAgent/LoggingServer.h +122 -122
  103. data/ext/common/agents/LoggingAgent/Main.cpp +7 -7
  104. data/ext/common/agents/LoggingAgent/RemoteSender.h +54 -54
  105. data/ext/common/agents/SpawnPreparer.cpp +4 -4
  106. data/ext/common/agents/TempDirToucher.c +2 -2
  107. data/ext/common/agents/Watchdog/AgentWatcher.cpp +47 -47
  108. data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +7 -7
  109. data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +7 -7
  110. data/ext/common/agents/Watchdog/Main.cpp +22 -22
  111. data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +9 -9
  112. data/ext/libeio/eio.c +1 -1
  113. data/ext/nginx/Configuration.c +30 -30
  114. data/ext/nginx/Configuration.h +1 -1
  115. data/ext/nginx/ContentHandler.c +54 -54
  116. data/ext/nginx/ContentHandler.h +3 -3
  117. data/ext/nginx/StaticContentHandler.c +2 -2
  118. data/ext/nginx/ngx_http_passenger_module.c +21 -21
  119. data/ext/oxt/detail/backtrace_enabled.hpp +1 -1
  120. data/ext/oxt/detail/context.hpp +1 -1
  121. data/ext/oxt/detail/spin_lock_darwin.hpp +4 -4
  122. data/ext/oxt/detail/spin_lock_gcc_x86.hpp +3 -3
  123. data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
  124. data/ext/oxt/detail/tracable_exception_disabled.hpp +1 -1
  125. data/ext/oxt/dynamic_thread_group.hpp +18 -18
  126. data/ext/oxt/implementation.cpp +9 -8
  127. data/ext/oxt/macros.hpp +2 -2
  128. data/ext/oxt/system_calls.cpp +11 -11
  129. data/ext/oxt/system_calls.hpp +13 -13
  130. data/ext/oxt/thread.hpp +22 -14
  131. data/ext/ruby/passenger_native_support.c +55 -55
  132. data/lib/phusion_passenger.rb +24 -24
  133. data/lib/phusion_passenger/common_library.rb +2 -0
  134. data/lib/phusion_passenger/loader_shared_helpers.rb +18 -18
  135. data/lib/phusion_passenger/packaging.rb +9 -4
  136. data/lib/phusion_passenger/platform_info/apache.rb +45 -31
  137. data/lib/phusion_passenger/platform_info/compiler.rb +11 -11
  138. data/lib/phusion_passenger/rack/thread_handler_extension.rb +1 -1
  139. data/lib/phusion_passenger/request_handler/thread_handler.rb +8 -8
  140. data/lib/phusion_passenger/standalone/app_finder.rb +16 -16
  141. data/lib/phusion_passenger/standalone/command.rb +22 -22
  142. data/packaging/rpm/LICENSE.txt +19 -0
  143. data/packaging/rpm/Makefile +13 -0
  144. data/packaging/rpm/README.md +41 -0
  145. data/packaging/rpm/Vagrantfile +38 -0
  146. data/{rpm/Vagrantfile → packaging/rpm/Vagrantfile.centos} +0 -0
  147. data/packaging/rpm/build +170 -0
  148. data/packaging/rpm/create_project +41 -0
  149. data/packaging/rpm/git_update +88 -0
  150. data/packaging/rpm/image/Dockerfile +37 -0
  151. data/packaging/rpm/image/Gemfile +3 -0
  152. data/packaging/rpm/image/Gemfile.lock +12 -0
  153. data/packaging/rpm/image/RPM-GPG-KEY-amazon-ga +19 -0
  154. data/packaging/rpm/image/amazon2014-i386.cfg +96 -0
  155. data/packaging/rpm/image/amazon2014-x86_64.cfg +96 -0
  156. data/packaging/rpm/image/site-defaults.cfg +168 -0
  157. data/packaging/rpm/internal/build_tasks.rb +238 -0
  158. data/packaging/rpm/internal/dummygpg +11 -0
  159. data/packaging/rpm/internal/exec_build +42 -0
  160. data/packaging/rpm/internal/get_distro_arch +14 -0
  161. data/packaging/rpm/internal/get_distro_id +10 -0
  162. data/packaging/rpm/internal/git_update +27 -0
  163. data/packaging/rpm/internal/inituidgid +17 -0
  164. data/packaging/rpm/internal/my_init +344 -0
  165. data/packaging/rpm/internal/python27 +3 -0
  166. data/packaging/rpm/internal/repo_update +46 -0
  167. data/packaging/rpm/internal/setuser +26 -0
  168. data/packaging/rpm/internal/tracking_helper +40 -0
  169. data/packaging/rpm/jenkins_release +99 -0
  170. data/packaging/rpm/lib/build_tasks_support.rb +402 -0
  171. data/packaging/rpm/lib/preprocessor.rb +341 -0
  172. data/packaging/rpm/nginx_spec/404.html +119 -0
  173. data/packaging/rpm/nginx_spec/50x.html +119 -0
  174. data/packaging/rpm/nginx_spec/index.html +116 -0
  175. data/packaging/rpm/nginx_spec/nginx-auto-cc-gcc.patch +13 -0
  176. data/packaging/rpm/nginx_spec/nginx-logo.png +0 -0
  177. data/packaging/rpm/nginx_spec/nginx-upgrade +13 -0
  178. data/packaging/rpm/nginx_spec/nginx-upgrade.8 +151 -0
  179. data/packaging/rpm/nginx_spec/nginx.conf +131 -0
  180. data/packaging/rpm/nginx_spec/nginx.init +144 -0
  181. data/packaging/rpm/nginx_spec/nginx.logrotate +13 -0
  182. data/packaging/rpm/nginx_spec/nginx.service +15 -0
  183. data/packaging/rpm/nginx_spec/nginx.spec.template +559 -0
  184. data/packaging/rpm/nginx_spec/nginx.sysconfig +4 -0
  185. data/packaging/rpm/nginx_spec/passenger.conf +9 -0
  186. data/packaging/rpm/nginx_spec/poweredby.png +0 -0
  187. data/{rpm → packaging/rpm/passenger_spec}/apache-passenger.conf.in +0 -0
  188. data/{rpm → packaging/rpm/passenger_spec}/config.json +0 -0
  189. data/{rpm → packaging/rpm/passenger_spec}/passenger.logrotate +0 -0
  190. data/{rpm → packaging/rpm/passenger_spec}/passenger.spec.template +58 -31
  191. data/{rpm → packaging/rpm/passenger_spec}/passenger_dynamic_thread_group.patch +0 -0
  192. data/{rpm → packaging/rpm/passenger_spec}/passenger_tests_default_config_example.patch +0 -0
  193. data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch +0 -0
  194. data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-gcc47-include-sys_types.patch +0 -0
  195. data/packaging/rpm/repo_update +114 -0
  196. data/packaging/rpm/setup-system +60 -0
  197. data/packaging/rpm/shell +10 -0
  198. data/resources/templates/standalone/config.erb +3 -1
  199. data/test/config.json.rpm-automation +1 -1
  200. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +11 -11
  201. data/test/cxx/ApplicationPool2/OptionsTest.cpp +5 -5
  202. data/test/cxx/ApplicationPool2/PoolTest.cpp +129 -89
  203. data/test/cxx/ApplicationPool2/ProcessTest.cpp +15 -15
  204. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +22 -22
  205. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +11 -11
  206. data/test/cxx/ScgiRequestParserTest.cpp +75 -61
  207. data/test/cxx/UtilsTest.cpp +86 -85
  208. data/test/gdbinit.example +3 -0
  209. data/test/integration_tests/nginx_tests.rb +3 -3
  210. data/test/integration_tests/source_packaging_test.rb +3 -1
  211. data/test/stub/nginx/nginx.conf.erb +8 -1
  212. data/test/support/nginx_controller.rb +7 -7
  213. metadata +62 -17
  214. metadata.gz.asc +7 -7
  215. data/build/rpm.rb +0 -128
  216. data/dev/rpmtool +0 -21
  217. data/dev/test_rpm_packaging.sh +0 -28
  218. data/rpm/get_distro_id.py +0 -4
@@ -69,11 +69,11 @@ public:
69
69
  return *it;
70
70
  }
71
71
  }
72
-
72
+
73
73
  ProcessPtr &operator[](unsigned int index) {
74
74
  return get(index);
75
75
  }
76
-
76
+
77
77
  iterator last_iterator() {
78
78
  if (empty()) {
79
79
  return end();
@@ -128,7 +128,7 @@ class Process: public boost::enable_shared_from_this<Process> {
128
128
  // Actually private, but marked public so that unit tests can access the fields.
129
129
  public:
130
130
  friend class Group;
131
-
131
+
132
132
  /** A mutex to protect access to `lifeStatus`. */
133
133
  mutable boost::mutex lifetimeSyncher;
134
134
 
@@ -137,11 +137,11 @@ public:
137
137
  * Read-only; only set once during initialization.
138
138
  */
139
139
  boost::weak_ptr<Group> group;
140
-
140
+
141
141
  /** A subset of 'sockets': all sockets that speak the
142
142
  * "session" protocol, sorted by socket.busyness(). */
143
143
  PriorityQueue<Socket> sessionSockets;
144
-
144
+
145
145
  /** The iterator inside the associated Group's process list. */
146
146
  ProcessList::iterator it;
147
147
  /** The handle inside the associated Group's process priority queue. */
@@ -201,13 +201,13 @@ public:
201
201
  concurrency = 0;
202
202
  }
203
203
  }
204
-
204
+
205
205
  public:
206
206
  /*************************************************************
207
207
  * Read-only fields, set once during initialization and never
208
208
  * written to again. Reading is thread-safe.
209
209
  *************************************************************/
210
-
210
+
211
211
  /** Process PID. */
212
212
  pid_t pid;
213
213
  /** An ID that uniquely identifies this Process in the Group, for
@@ -245,13 +245,13 @@ public:
245
245
  * processes are never added to Group.enabledProcesses.
246
246
  */
247
247
  bool requiresShutdown;
248
-
248
+
249
249
  /*************************************************************
250
250
  * Information used by Pool. Do not write to these from
251
251
  * outside the Pool. If you read these make sure the Pool
252
252
  * isn't concurrently modifying.
253
253
  *************************************************************/
254
-
254
+
255
255
  /** Time at which we finished spawning this process, i.e. when this
256
256
  * process was finished initializing. Microseconds resolution.
257
257
  */
@@ -319,7 +319,7 @@ public:
319
319
  time_t shutdownStartTime;
320
320
  /** Collected by Pool::collectAnalytics(). */
321
321
  ProcessMetrics metrics;
322
-
322
+
323
323
  Process(pid_t _pid,
324
324
  const string &_gupid,
325
325
  const string &_connectPassword,
@@ -365,15 +365,15 @@ public:
365
365
  watcher->initialize();
366
366
  watcher->start();
367
367
  }
368
-
368
+
369
369
  if (OXT_LIKELY(sockets != NULL)) {
370
370
  indexSessionSockets();
371
371
  }
372
-
372
+
373
373
  lastUsed = SystemTime::getUsec();
374
374
  spawnEndTime = lastUsed;
375
375
  }
376
-
376
+
377
377
  ~Process() {
378
378
  if (OXT_UNLIKELY(!isDead() && requiresShutdown)) {
379
379
  P_BUG("You must call Process::triggerShutdown() and Process::cleanup() before actually "
@@ -400,7 +400,7 @@ public:
400
400
  assert(!isDead());
401
401
  return group.lock();
402
402
  }
403
-
403
+
404
404
  void setGroup(const GroupPtr &group) {
405
405
  assert(this->group.lock() == NULL || this->group.lock() == group);
406
406
  this->group = group;
@@ -536,7 +536,7 @@ public:
536
536
  return 0;
537
537
  }
538
538
  }
539
-
539
+
540
540
  int busyness() const {
541
541
  /* Different processes within a Group may have different
542
542
  * 'concurrency' values. We want:
@@ -557,7 +557,7 @@ public:
557
557
  return (int) (((long long) sessions * INT_MAX) / (double) concurrency);
558
558
  }
559
559
  }
560
-
560
+
561
561
  /**
562
562
  * Whether we've reached the maximum number of concurrent sessions for this
563
563
  * process.
@@ -574,7 +574,7 @@ public:
574
574
  bool canBeRoutedTo() const {
575
575
  return !isTotallyBusy();
576
576
  }
577
-
577
+
578
578
  /**
579
579
  * Create a new communication session with this process. This will connect to one
580
580
  * of the session sockets or reuse an existing connection. See Session for
@@ -596,13 +596,13 @@ public:
596
596
  return boost::make_shared<Session>(shared_from_this(), socket);
597
597
  }
598
598
  }
599
-
599
+
600
600
  void sessionClosed(Session *session) {
601
601
  Socket *socket = session->getSocket();
602
-
602
+
603
603
  assert(socket->sessions > 0);
604
604
  assert(sessions > 0);
605
-
605
+
606
606
  socket->sessions--;
607
607
  this->sessions--;
608
608
  processed++;
@@ -636,7 +636,7 @@ public:
636
636
  stream << "<last_used_desc>" << distanceOfTimeInWords(lastUsed / 1000000).c_str() << " ago</last_used_desc>";
637
637
  stream << "<uptime>" << uptime() << "</uptime>";
638
638
  if (!codeRevision.empty()) {
639
- stream << "<code_revision>" << codeRevision << "</code_revision>";
639
+ stream << "<code_revision>" << escapeForXml(codeRevision) << "</code_revision>";
640
640
  }
641
641
  switch (lifeStatus) {
642
642
  case ALIVE:
@@ -57,11 +57,11 @@ private:
57
57
  ProcessPtr process;
58
58
  /** Socket to use for this session. Guaranteed to be alive thanks to the 'process' reference. */
59
59
  Socket *socket;
60
-
60
+
61
61
  Connection connection;
62
62
  FileDescriptor theFd;
63
63
  bool closed;
64
-
64
+
65
65
  void deinitiate(bool success) {
66
66
  connection.fail = !success;
67
67
  socket->checkinConnection(connection);
@@ -74,7 +74,7 @@ private:
74
74
  onInitiateFailure(this);
75
75
  }
76
76
  }
77
-
77
+
78
78
  void callOnClose() {
79
79
  if (OXT_LIKELY(onClose != NULL)) {
80
80
  onClose(this);
@@ -85,7 +85,7 @@ private:
85
85
  public:
86
86
  Callback onInitiateFailure;
87
87
  Callback onClose;
88
-
88
+
89
89
  Session(const ProcessPtr &_process, Socket *_socket)
90
90
  : process(_process),
91
91
  socket(_socket),
@@ -93,7 +93,7 @@ public:
93
93
  onInitiateFailure(NULL),
94
94
  onClose(NULL)
95
95
  { }
96
-
96
+
97
97
  ~Session() {
98
98
  TRACE_POINT();
99
99
  // If user doesn't close() explicitly, we penalize performance.
@@ -112,7 +112,7 @@ public:
112
112
  const GroupPtr getGroup() const;
113
113
  void requestOOBW();
114
114
  int kill(int signo);
115
-
115
+
116
116
  bool isClosed() const {
117
117
  return closed;
118
118
  }
@@ -125,7 +125,7 @@ public:
125
125
  assert(!closed);
126
126
  return process;
127
127
  }
128
-
128
+
129
129
  Socket *getSocket() const {
130
130
  return socket;
131
131
  }
@@ -133,7 +133,7 @@ public:
133
133
  const string &getProtocol() const {
134
134
  return socket->protocol;
135
135
  }
136
-
136
+
137
137
  void initiate() {
138
138
  assert(!closed);
139
139
  ScopeGuard g(boost::bind(&Session::callOnInitiateFailure, this));
@@ -142,15 +142,15 @@ public:
142
142
  theFd = FileDescriptor(connection.fd, false);
143
143
  g.clear();
144
144
  }
145
-
145
+
146
146
  bool initiated() const {
147
147
  return connection.fd != -1;
148
148
  }
149
-
149
+
150
150
  const FileDescriptor &fd() const {
151
151
  return theFd;
152
152
  }
153
-
153
+
154
154
  /**
155
155
  * This Session object becomes fully unsable after closing.
156
156
  */
@@ -68,7 +68,7 @@ private:
68
68
  const vector<string> preloaderCommand;
69
69
  map<string, string> preloaderAnnotations;
70
70
  Options options;
71
-
71
+
72
72
  // Protects m_lastUsed and pid.
73
73
  mutable boost::mutex simpleFieldSyncher;
74
74
  // Protects everything else.
@@ -82,11 +82,11 @@ private:
82
82
  // Upon starting the preloader, its preparation info is stored here
83
83
  // for future reference.
84
84
  SpawnPreparationInfo preparation;
85
-
85
+
86
86
  string getPreloaderCommandString() const {
87
87
  string result;
88
88
  unsigned int i;
89
-
89
+
90
90
  for (i = 0; i < preloaderCommand.size(); i++) {
91
91
  if (i != 0) {
92
92
  result.append(1, '\0');
@@ -95,13 +95,13 @@ private:
95
95
  }
96
96
  return result;
97
97
  }
98
-
98
+
99
99
  vector<string> createRealPreloaderCommand(const Options &options,
100
100
  shared_array<const char *> &args)
101
101
  {
102
102
  string agentsDir = config->resourceLocator.getAgentsDir();
103
103
  vector<string> command;
104
-
104
+
105
105
  if (shouldLoadShellEnvvars(options, preparation)) {
106
106
  command.push_back(preparation.shell);
107
107
  command.push_back(preparation.shell);
@@ -121,11 +121,11 @@ private:
121
121
  for (unsigned int i = 1; i < preloaderCommand.size(); i++) {
122
122
  command.push_back(preloaderCommand[i]);
123
123
  }
124
-
124
+
125
125
  createCommandArgs(command, args);
126
126
  return command;
127
127
  }
128
-
128
+
129
129
  void throwPreloaderSpawnException(const string &msg,
130
130
  SpawnException::ErrorKind errorKind,
131
131
  StartupDetails &details)
@@ -147,7 +147,7 @@ private:
147
147
  if (stderrCapturer != NULL) {
148
148
  stderrOutput = stderrCapturer->stop();
149
149
  }
150
-
150
+
151
151
  // If the exception wasn't due to a timeout, try to capture the
152
152
  // remaining stderr output for at most 2 seconds.
153
153
  if (errorKind != SpawnException::PRELOADER_STARTUP_TIMEOUT
@@ -159,7 +159,7 @@ private:
159
159
  while (!done) {
160
160
  char buf[1024 * 32];
161
161
  unsigned int ret;
162
-
162
+
163
163
  try {
164
164
  ret = readExact(stderrCapturer->getFd(), buf,
165
165
  sizeof(buf), &timeout);
@@ -177,7 +177,7 @@ private:
177
177
  }
178
178
  }
179
179
  stderrCapturer.reset();
180
-
180
+
181
181
  // Now throw SpawnException with the captured stderr output
182
182
  // as error response.
183
183
  SpawnException e(msg,
@@ -206,7 +206,7 @@ private:
206
206
  assert(!preloaderStarted());
207
207
  P_DEBUG("Spawning new preloader: appRoot=" << options.appRoot);
208
208
  checkChrootDirectories(options);
209
-
209
+
210
210
  shared_array<const char *> args;
211
211
  preparation = prepareSpawn(options);
212
212
  vector<string> command = createRealPreloaderCommand(options, args);
@@ -214,7 +214,7 @@ private:
214
214
  Pipe errorPipe = createPipe();
215
215
  DebugDirPtr debugDir = boost::make_shared<DebugDir>(preparation.uid, preparation.gid);
216
216
  pid_t pid;
217
-
217
+
218
218
  pid = syscalls::fork();
219
219
  if (pid == 0) {
220
220
  setenv("PASSENGER_DEBUG_DIR", debugDir->getPath().c_str(), 1);
@@ -232,7 +232,7 @@ private:
232
232
  switchUser(preparation);
233
233
  setWorkingDirectory(preparation);
234
234
  execvp(command[0].c_str(), (char * const *) args.get());
235
-
235
+
236
236
  int e = errno;
237
237
  printf("!> Error\n");
238
238
  printf("!> \n");
@@ -243,17 +243,17 @@ private:
243
243
  fflush(stdout);
244
244
  fflush(stderr);
245
245
  _exit(1);
246
-
246
+
247
247
  } else if (pid == -1) {
248
248
  int e = errno;
249
249
  throw SystemException("Cannot fork a new process", e);
250
-
250
+
251
251
  } else {
252
252
  ScopeGuard guard(boost::bind(nonInterruptableKillAndWaitpid, pid));
253
253
  P_DEBUG("Preloader process forked for appRoot=" << options.appRoot << ": PID " << pid);
254
254
  adminSocket.first.close();
255
255
  errorPipe.second.close();
256
-
256
+
257
257
  StartupDetails details;
258
258
  details.pid = pid;
259
259
  details.adminSocket = adminSocket.second;
@@ -268,7 +268,7 @@ private:
268
268
  details.debugDir = debugDir;
269
269
  details.options = &options;
270
270
  details.timeout = options.startTimeout * 1000;
271
-
271
+
272
272
  {
273
273
  this_thread::restore_interruption ri(di);
274
274
  this_thread::restore_syscall_interruption rsi(dsi);
@@ -279,7 +279,7 @@ private:
279
279
  boost::lock_guard<boost::mutex> l(simpleFieldSyncher);
280
280
  this->pid = pid;
281
281
  }
282
-
282
+
283
283
  PipeWatcherPtr watcher;
284
284
 
285
285
  watcher = boost::make_shared<PipeWatcher>(adminSocket.second,
@@ -291,7 +291,7 @@ private:
291
291
  "stderr", pid);
292
292
  watcher->initialize();
293
293
  watcher->start();
294
-
294
+
295
295
  preloaderAnnotations = debugDir->readAll();
296
296
  P_INFO("Preloader for " << options.appRoot <<
297
297
  " started on PID " << pid <<
@@ -299,12 +299,12 @@ private:
299
299
  guard.clear();
300
300
  }
301
301
  }
302
-
302
+
303
303
  void stopPreloader() {
304
304
  TRACE_POINT();
305
305
  this_thread::disable_interruption di;
306
306
  this_thread::disable_syscall_interruption dsi;
307
-
307
+
308
308
  if (!preloaderStarted()) {
309
309
  return;
310
310
  }
@@ -327,7 +327,7 @@ private:
327
327
  socketAddress.clear();
328
328
  preparation = SpawnPreparationInfo();
329
329
  }
330
-
330
+
331
331
  void sendStartupRequest(StartupDetails &details) {
332
332
  TRACE_POINT();
333
333
  try {
@@ -375,14 +375,14 @@ private:
375
375
  details);
376
376
  }
377
377
  }
378
-
378
+
379
379
  string handleStartupResponse(StartupDetails &details) {
380
380
  TRACE_POINT();
381
381
  string socketAddress;
382
-
382
+
383
383
  while (true) {
384
384
  string line;
385
-
385
+
386
386
  try {
387
387
  line = readMessageLine(details);
388
388
  } catch (const SystemException &e) {
@@ -397,7 +397,7 @@ private:
397
397
  SpawnException::PRELOADER_STARTUP_TIMEOUT,
398
398
  details);
399
399
  }
400
-
400
+
401
401
  if (line.empty()) {
402
402
  throwPreloaderSpawnException("An error occurred while starting up "
403
403
  "the preloader. It unexpected closed the connection while "
@@ -413,7 +413,7 @@ private:
413
413
  } else if (line == "\n") {
414
414
  break;
415
415
  }
416
-
416
+
417
417
  string::size_type pos = line.find(": ");
418
418
  if (pos == string::npos) {
419
419
  throwPreloaderSpawnException("An error occurred while starting up "
@@ -422,7 +422,7 @@ private:
422
422
  SpawnException::PRELOADER_STARTUP_PROTOCOL_ERROR,
423
423
  details);
424
424
  }
425
-
425
+
426
426
  string key = line.substr(0, pos);
427
427
  string value = line.substr(pos + 2, line.size() - pos - 3);
428
428
  if (key == "socket") {
@@ -436,7 +436,7 @@ private:
436
436
  details);
437
437
  }
438
438
  }
439
-
439
+
440
440
  if (socketAddress.empty()) {
441
441
  throwPreloaderSpawnException("An error occurred while starting up "
442
442
  "the preloader. It did not report a socket address in its "
@@ -444,17 +444,17 @@ private:
444
444
  SpawnException::PRELOADER_STARTUP_PROTOCOL_ERROR,
445
445
  details);
446
446
  }
447
-
447
+
448
448
  return socketAddress;
449
449
  }
450
-
450
+
451
451
  void handleErrorResponse(StartupDetails &details) {
452
452
  TRACE_POINT();
453
453
  map<string, string> attributes;
454
-
454
+
455
455
  while (true) {
456
456
  string line;
457
-
457
+
458
458
  try {
459
459
  line = readMessageLine(details);
460
460
  } catch (const SystemException &e) {
@@ -469,7 +469,7 @@ private:
469
469
  SpawnException::PRELOADER_STARTUP_TIMEOUT,
470
470
  details);
471
471
  }
472
-
472
+
473
473
  if (line.empty()) {
474
474
  throwPreloaderSpawnException("An error occurred while starting up "
475
475
  "the preloader. It unexpected closed the connection while "
@@ -485,7 +485,7 @@ private:
485
485
  } else if (line == "\n") {
486
486
  break;
487
487
  }
488
-
488
+
489
489
  string::size_type pos = line.find(": ");
490
490
  if (pos == string::npos) {
491
491
  throwPreloaderSpawnException("An error occurred while starting up "
@@ -494,12 +494,12 @@ private:
494
494
  SpawnException::PRELOADER_STARTUP_PROTOCOL_ERROR,
495
495
  details);
496
496
  }
497
-
497
+
498
498
  string key = line.substr(0, pos);
499
499
  string value = line.substr(pos + 2, line.size() - pos - 3);
500
500
  attributes[key] = value;
501
501
  }
502
-
502
+
503
503
  try {
504
504
  string message = details.io.readAll(&details.timeout);
505
505
  SpawnException e("An error occured while starting up the preloader.",
@@ -524,7 +524,7 @@ private:
524
524
  details);
525
525
  }
526
526
  }
527
-
527
+
528
528
  void handleInvalidResponseType(StartupDetails &details, const string &line) {
529
529
  if (line.empty()) {
530
530
  throwPreloaderSpawnException("An error occurred while starting up "
@@ -540,7 +540,7 @@ private:
540
540
  details);
541
541
  }
542
542
  }
543
-
543
+
544
544
  string negotiatePreloaderStartup(StartupDetails &details) {
545
545
  TRACE_POINT();
546
546
  string result;
@@ -558,7 +558,7 @@ private:
558
558
  SpawnException::PRELOADER_STARTUP_TIMEOUT,
559
559
  details);
560
560
  }
561
-
561
+
562
562
  if (result == "I have control 1.0\n") {
563
563
  UPDATE_TRACE_POINT();
564
564
  sendStartupRequest(details);
@@ -591,12 +591,12 @@ private:
591
591
  handleInvalidResponseType(details, result);
592
592
  }
593
593
  }
594
-
594
+
595
595
  // Never reached, shut up compiler warning.
596
596
  abort();
597
597
  return "";
598
598
  }
599
-
599
+
600
600
  SpawnResult sendSpawnCommand(const Options &options) {
601
601
  TRACE_POINT();
602
602
  FileDescriptor fd;
@@ -612,14 +612,14 @@ private:
612
612
  options,
613
613
  DebugDirPtr());
614
614
  }
615
-
615
+
616
616
  UPDATE_TRACE_POINT();
617
617
  BufferedIO io(fd);
618
618
  unsigned long long timeout = options.startTimeout * 1000;
619
619
  string result;
620
620
  vector<string> args;
621
621
  vector<string>::const_iterator it;
622
-
622
+
623
623
  writeExact(fd, "spawn\n", &timeout);
624
624
  options.toVector(args, config->resourceLocator, Options::SPAWN_OPTIONS);
625
625
  for (it = args.begin(); it != args.end(); it++) {
@@ -629,12 +629,12 @@ private:
629
629
  writeExact(fd, key + ": " + value + "\n", &timeout);
630
630
  }
631
631
  writeExact(fd, "\n", &timeout);
632
-
632
+
633
633
  result = io.readLine(1024, &timeout);
634
634
  if (result == "OK\n") {
635
635
  UPDATE_TRACE_POINT();
636
636
  pid_t spawnedPid;
637
-
637
+
638
638
  spawnedPid = atoi(io.readLine(1024, &timeout).c_str());
639
639
  if (spawnedPid <= 0) {
640
640
  BackgroundIOCapturerPtr stderrCapturer;
@@ -660,29 +660,29 @@ private:
660
660
  options,
661
661
  DebugDirPtr());
662
662
  }
663
-
663
+
664
664
  SpawnResult result;
665
665
  result.pid = spawnedPid;
666
666
  result.adminSocket = fd;
667
667
  result.io = io;
668
668
  return result;
669
-
669
+
670
670
  } else if (result == "Error\n") {
671
671
  UPDATE_TRACE_POINT();
672
672
  NegotiationDetails details;
673
673
  details.io = io;
674
674
  details.timeout = timeout;
675
675
  handleSpawnErrorResponse(details);
676
-
676
+
677
677
  } else {
678
678
  UPDATE_TRACE_POINT();
679
679
  NegotiationDetails details;
680
680
  handleInvalidSpawnResponseType(result, details);
681
681
  }
682
-
682
+
683
683
  return SpawnResult(); // Never reached.
684
684
  }
685
-
685
+
686
686
  template<typename Exception>
687
687
  SpawnResult sendSpawnCommandAgain(const Exception &e, const Options &options) {
688
688
  TRACE_POINT();
@@ -695,7 +695,7 @@ private:
695
695
  guard.clear();
696
696
  return result;
697
697
  }
698
-
698
+
699
699
  protected:
700
700
  virtual void annotateAppSpawnException(SpawnException &e, NegotiationDetails &details) {
701
701
  Spawner::annotateAppSpawnException(e, details);
@@ -713,23 +713,23 @@ public:
713
713
  if (preloaderCommand.size() < 2) {
714
714
  throw ArgumentException("preloaderCommand must have at least 2 elements");
715
715
  }
716
-
716
+
717
717
  generation = _generation;
718
718
  options = _options.copyAndPersist().detachFromUnionStationTransaction();
719
719
  pid = -1;
720
720
  m_lastUsed = SystemTime::getUsec();
721
721
  }
722
-
722
+
723
723
  virtual ~SmartSpawner() {
724
724
  boost::lock_guard<boost::mutex> l(syncher);
725
725
  stopPreloader();
726
726
  }
727
-
727
+
728
728
  virtual ProcessPtr spawn(const Options &options) {
729
729
  TRACE_POINT();
730
730
  assert(options.appType == this->options.appType);
731
731
  assert(options.appRoot == this->options.appRoot);
732
-
732
+
733
733
  P_DEBUG("Spawning new process: appRoot=" << options.appRoot);
734
734
  possiblyRaiseInternalError(options);
735
735
 
@@ -743,7 +743,7 @@ public:
743
743
  UPDATE_TRACE_POINT();
744
744
  startPreloader();
745
745
  }
746
-
746
+
747
747
  UPDATE_TRACE_POINT();
748
748
  SpawnResult result;
749
749
  try {
@@ -755,7 +755,7 @@ public:
755
755
  } catch (const SpawnException &e) {
756
756
  result = sendSpawnCommandAgain(e, options);
757
757
  }
758
-
758
+
759
759
  UPDATE_TRACE_POINT();
760
760
  NegotiationDetails details;
761
761
  details.preparation = &preparation;
@@ -772,7 +772,7 @@ public:
772
772
  virtual bool cleanable() const {
773
773
  return true;
774
774
  }
775
-
775
+
776
776
  virtual void cleanup() {
777
777
  TRACE_POINT();
778
778
  {
@@ -787,7 +787,7 @@ public:
787
787
  boost::lock_guard<boost::mutex> lock(simpleFieldSyncher);
788
788
  return m_lastUsed;
789
789
  }
790
-
790
+
791
791
  pid_t getPreloaderPid() const {
792
792
  boost::lock_guard<boost::mutex> lock(simpleFieldSyncher);
793
793
  return pid;