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
@@ -49,13 +49,13 @@ struct Connection {
49
49
  int fd;
50
50
  bool persistent: 1;
51
51
  bool fail: 1;
52
-
52
+
53
53
  Connection() {
54
54
  fd = -1;
55
55
  persistent = false;
56
56
  fail = false;
57
57
  }
58
-
58
+
59
59
  void close() {
60
60
  if (fd != -1) {
61
61
  int fd2 = fd;
@@ -75,37 +75,37 @@ private:
75
75
  boost::mutex connectionPoolLock;
76
76
  int totalConnections;
77
77
  vector<Connection> idleConnections;
78
-
78
+
79
79
  int connectionPoolLimit() const {
80
80
  return concurrency;
81
81
  }
82
-
82
+
83
83
  Connection connect() const {
84
84
  Connection connection;
85
85
  P_TRACE(3, "Connecting to " << address);
86
86
  connection.fd = connectToServer(address);
87
87
  return connection;
88
88
  }
89
-
89
+
90
90
  public:
91
91
  // Read-only.
92
92
  string name;
93
93
  string address;
94
94
  string protocol;
95
95
  int concurrency;
96
-
96
+
97
97
  /** The handle inside the associated Process's 'sessionSockets' priority queue.
98
98
  * Guaranteed to be valid as long as the Process is alive.
99
99
  */
100
100
  PriorityQueue<Socket>::Handle pqHandle;
101
-
101
+
102
102
  /** Invariant: sessions >= 0 */
103
103
  int sessions;
104
-
104
+
105
105
  Socket()
106
106
  : concurrency(0)
107
107
  { }
108
-
108
+
109
109
  Socket(const string &_name, const string &_address, const string &_protocol, int _concurrency)
110
110
  : totalConnections(0),
111
111
  name(_name),
@@ -114,7 +114,7 @@ public:
114
114
  concurrency(_concurrency),
115
115
  sessions(0)
116
116
  { }
117
-
117
+
118
118
  Socket(const Socket &other)
119
119
  : totalConnections(other.totalConnections),
120
120
  idleConnections(other.idleConnections),
@@ -125,7 +125,7 @@ public:
125
125
  pqHandle(other.pqHandle),
126
126
  sessions(other.sessions)
127
127
  { }
128
-
128
+
129
129
  Socket &operator=(const Socket &other) {
130
130
  totalConnections = other.totalConnections;
131
131
  idleConnections = other.idleConnections;
@@ -137,7 +137,7 @@ public:
137
137
  sessions = other.sessions;
138
138
  return *this;
139
139
  }
140
-
140
+
141
141
  /**
142
142
  * Connect to this socket or reuse an existing connection.
143
143
  *
@@ -146,7 +146,7 @@ public:
146
146
  */
147
147
  Connection checkoutConnection() {
148
148
  boost::lock_guard<boost::mutex> l(connectionPoolLock);
149
-
149
+
150
150
  if (!idleConnections.empty()) {
151
151
  Connection connection = idleConnections.back();
152
152
  idleConnections.pop_back();
@@ -160,10 +160,10 @@ public:
160
160
  return connect();
161
161
  }
162
162
  }
163
-
163
+
164
164
  void checkinConnection(Connection connection) {
165
165
  boost::unique_lock<boost::mutex> l(connectionPoolLock);
166
-
166
+
167
167
  if (connection.persistent) {
168
168
  if (connection.fail) {
169
169
  totalConnections--;
@@ -177,12 +177,12 @@ public:
177
177
  connection.close();
178
178
  }
179
179
  }
180
-
181
-
180
+
181
+
182
182
  bool isIdle() const {
183
183
  return sessions == 0;
184
184
  }
185
-
185
+
186
186
  int busyness() const {
187
187
  /* Different sockets within a Process may have different
188
188
  * 'concurrency' values. We want:
@@ -204,7 +204,7 @@ public:
204
204
  return (int) (((long long) sessions * INT_MAX) / (double) concurrency);
205
205
  }
206
206
  }
207
-
207
+
208
208
  bool isTotallyBusy() const {
209
209
  return concurrency != 0 && sessions >= concurrency;
210
210
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2013 Phusion
3
+ * Copyright (c) 2011-2014 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -57,6 +57,7 @@
57
57
  #include <map>
58
58
  #include <vector>
59
59
  #include <utility>
60
+ #include <algorithm>
60
61
  #include <boost/make_shared.hpp>
61
62
  #include <boost/shared_array.hpp>
62
63
  #include <boost/bind.hpp>
@@ -107,7 +108,7 @@ class Spawner {
107
108
  protected:
108
109
  friend struct tut::ApplicationPool2_DirectSpawnerTest;
109
110
  friend struct tut::ApplicationPool2_SmartSpawnerTest;
110
-
111
+
111
112
  /**
112
113
  * Given a file descriptor, captures its output in a background thread
113
114
  * and also forwards it immediately to a target file descriptor.
@@ -122,13 +123,13 @@ protected:
122
123
  boost::mutex dataSyncher;
123
124
  string data;
124
125
  oxt::thread *thr;
125
-
126
+
126
127
  void capture() {
127
128
  TRACE_POINT();
128
129
  while (!this_thread::interruption_requested()) {
129
130
  char buf[1024 * 8];
130
131
  ssize_t ret;
131
-
132
+
132
133
  UPDATE_TRACE_POINT();
133
134
  ret = syscalls::read(fd, buf, sizeof(buf));
134
135
  int e = errno;
@@ -162,7 +163,7 @@ protected:
162
163
  }
163
164
  }
164
165
  }
165
-
166
+
166
167
  public:
167
168
  BackgroundIOCapturer(const FileDescriptor &_fd, pid_t _pid, const char *_channelName)
168
169
  : fd(_fd),
@@ -170,7 +171,7 @@ protected:
170
171
  channelName(_channelName),
171
172
  thr(NULL)
172
173
  { }
173
-
174
+
174
175
  ~BackgroundIOCapturer() {
175
176
  TRACE_POINT();
176
177
  if (thr != NULL) {
@@ -181,17 +182,17 @@ protected:
181
182
  thr = NULL;
182
183
  }
183
184
  }
184
-
185
+
185
186
  const FileDescriptor &getFd() const {
186
187
  return fd;
187
188
  }
188
-
189
+
189
190
  void start() {
190
191
  assert(thr == NULL);
191
192
  thr = new oxt::thread(boost::bind(&BackgroundIOCapturer::capture, this),
192
193
  "Background I/O capturer", 64 * 1024);
193
194
  }
194
-
195
+
195
196
  string stop() {
196
197
  TRACE_POINT();
197
198
  assert(thr != NULL);
@@ -210,9 +211,9 @@ protected:
210
211
  data.append(dataToAdd.data(), dataToAdd.size());
211
212
  }
212
213
  };
213
-
214
+
214
215
  typedef boost::shared_ptr<BackgroundIOCapturer> BackgroundIOCapturerPtr;
215
-
216
+
216
217
  /**
217
218
  * A temporary directory for spawned child processes to write
218
219
  * debugging information to. It is removed after spawning has
@@ -345,14 +346,14 @@ protected:
345
346
  FileDescriptor errorPipe;
346
347
  const Options *options;
347
348
  DebugDirPtr debugDir;
348
-
349
+
349
350
  /****** Working state ******/
350
351
  BufferedIO io;
351
352
  string gupid;
352
353
  string connectPassword;
353
354
  unsigned long long spawnStartTime;
354
355
  unsigned long long timeout;
355
-
356
+
356
357
  NegotiationDetails() {
357
358
  preparation = NULL;
358
359
  pid = 0;
@@ -361,8 +362,8 @@ protected:
361
362
  timeout = 0;
362
363
  }
363
364
  };
364
-
365
-
365
+
366
+
366
367
  private:
367
368
  /**
368
369
  * Appends key + "\0" + value + "\0" to 'output'.
@@ -425,7 +426,7 @@ private:
425
426
  SocketListPtr sockets = boost::make_shared<SocketList>();
426
427
  while (true) {
427
428
  string line;
428
-
429
+
429
430
  try {
430
431
  line = readMessageLine(details);
431
432
  } catch (const SystemException &e) {
@@ -440,7 +441,7 @@ private:
440
441
  SpawnException::APP_STARTUP_TIMEOUT,
441
442
  details);
442
443
  }
443
-
444
+
444
445
  if (line.empty()) {
445
446
  throwAppSpawnException("An error occurred while starting the "
446
447
  "web application. It unexpected closed the connection while "
@@ -456,7 +457,7 @@ private:
456
457
  } else if (line == "\n") {
457
458
  break;
458
459
  }
459
-
460
+
460
461
  string::size_type pos = line.find(": ");
461
462
  if (pos == string::npos) {
462
463
  throwAppSpawnException("An error occurred while starting the "
@@ -465,7 +466,7 @@ private:
465
466
  SpawnException::APP_STARTUP_PROTOCOL_ERROR,
466
467
  details);
467
468
  }
468
-
469
+
469
470
  string key = line.substr(0, pos);
470
471
  string value = line.substr(pos + 2, line.size() - pos - 3);
471
472
  if (key == "socket") {
@@ -525,7 +526,7 @@ private:
525
526
  SpawnException::APP_STARTUP_PROTOCOL_ERROR,
526
527
  details);
527
528
  }
528
-
529
+
529
530
  ProcessPtr process = boost::make_shared<Process>(
530
531
  details.pid,
531
532
  details.gupid, details.connectPassword,
@@ -534,17 +535,17 @@ private:
534
535
  process->codeRevision = details.preparation->codeRevision;
535
536
  return process;
536
537
  }
537
-
538
+
538
539
  protected:
539
540
  ServerInstanceDir::GenerationPtr generation;
540
541
  SpawnerConfigPtr config;
541
-
542
+
542
543
  static void nonInterruptableKillAndWaitpid(pid_t pid) {
543
544
  this_thread::disable_syscall_interruption dsi;
544
545
  syscalls::kill(pid, SIGKILL);
545
546
  syscalls::waitpid(pid, NULL, 0);
546
547
  }
547
-
548
+
548
549
  /**
549
550
  * Behaves like <tt>waitpid(pid, status, WNOHANG)</tt>, but waits at most
550
551
  * <em>timeout</em> miliseconds for the process to exit.
@@ -552,7 +553,7 @@ protected:
552
553
  static int timedWaitpid(pid_t pid, int *status, unsigned long long timeout) {
553
554
  Timer timer;
554
555
  int ret;
555
-
556
+
556
557
  do {
557
558
  ret = syscalls::waitpid(pid, status, WNOHANG);
558
559
  if (ret > 0 || ret == -1) {
@@ -563,7 +564,7 @@ protected:
563
564
  } while (timer.elapsed() < timeout);
564
565
  return 0; // timed out
565
566
  }
566
-
567
+
567
568
  static string fixupSocketAddress(const Options &options, const string &address) {
568
569
  TRACE_POINT();
569
570
  if (!options.preexecChroot.empty() && !options.postexecChroot.empty()) {
@@ -662,7 +663,7 @@ protected:
662
663
  // and whether postexecChroot is a child directory of appRoot.
663
664
  }
664
665
  }
665
-
666
+
666
667
  static void createCommandArgs(const vector<string> &command,
667
668
  shared_array<const char *> &args)
668
669
  {
@@ -678,7 +679,7 @@ protected:
678
679
  throw RuntimeException("An internal error!");
679
680
  }
680
681
  }
681
-
682
+
682
683
  void throwAppSpawnException(const string &msg,
683
684
  SpawnException::ErrorKind errorKind,
684
685
  NegotiationDetails &details)
@@ -690,7 +691,7 @@ protected:
690
691
  if (details.stderrCapturer != NULL) {
691
692
  stderrOutput = details.stderrCapturer->stop();
692
693
  }
693
-
694
+
694
695
  // If the exception wasn't due to a timeout, try to capture the
695
696
  // remaining stderr output for at most 2 seconds.
696
697
  if (errorKind != SpawnException::PRELOADER_STARTUP_TIMEOUT
@@ -702,7 +703,7 @@ protected:
702
703
  while (!done) {
703
704
  char buf[1024 * 32];
704
705
  unsigned int ret;
705
-
706
+
706
707
  try {
707
708
  ret = readExact(details.stderrCapturer->getFd(), buf,
708
709
  sizeof(buf), &timeout);
@@ -720,7 +721,7 @@ protected:
720
721
  }
721
722
  }
722
723
  details.stderrCapturer.reset();
723
-
724
+
724
725
  // Now throw SpawnException with the captured stderr output
725
726
  // as error response.
726
727
  SpawnException e(msg,
@@ -782,7 +783,7 @@ protected:
782
783
  if (!line.empty() && line[line.size() - 1] == '\n') {
783
784
  line.erase(line.size() - 1, 1);
784
785
  }
785
-
786
+
786
787
  if (result.empty()) {
787
788
  // EOF
788
789
  return result;
@@ -840,11 +841,9 @@ protected:
840
841
  long bufSize;
841
842
  shared_array<char> strings;
842
843
 
843
- bufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
844
- if (bufSize == -1) {
845
- // Let's hope this is enough.
846
- bufSize = 1024 * 64;
847
- }
844
+ // _SC_GETPW_R_SIZE_MAX is not a maximum:
845
+ // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
846
+ bufSize = std::max<long>(1024 * 128, sysconf(_SC_GETPW_R_SIZE_MAX));
848
847
  strings.reset(new char[bufSize]);
849
848
 
850
849
  userInfo = (struct passwd *) NULL;
@@ -855,7 +854,7 @@ protected:
855
854
  getProcessUsername() + "; it looks like your system's " +
856
855
  "user database is broken, please fix it.");
857
856
  }
858
-
857
+
859
858
  info.switchUser = false;
860
859
  info.username = userInfo->pw_name;
861
860
  info.groupname = getGroupName(userInfo->pw_gid);
@@ -866,7 +865,7 @@ protected:
866
865
  info.ngroups = 0;
867
866
  return;
868
867
  }
869
-
868
+
870
869
  UPDATE_TRACE_POINT();
871
870
  string defaultGroup;
872
871
  string startupFile = absolutizePath(options.getStartupFile(), info.appRoot);
@@ -876,19 +875,12 @@ protected:
876
875
  long pwdBufSize, grpBufSize;
877
876
  shared_array<char> pwdBuf, grpBuf;
878
877
  int ret;
879
-
880
- pwdBufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
881
- if (pwdBufSize == -1) {
882
- // Let's hope this is enough.
883
- pwdBufSize = 1024 * 64;
884
- }
885
- pwdBuf.reset(new char[pwdBufSize]);
886
878
 
887
- grpBufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
888
- if (grpBufSize == -1) {
889
- // Let's hope this is enough.
890
- grpBufSize = 1024 * 64;
891
- }
879
+ // _SC_GETPW_R_SIZE_MAX/_SC_GETGR_R_SIZE_MAX are not maximums:
880
+ // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
881
+ pwdBufSize = std::max<long>(1024 * 128, sysconf(_SC_GETPW_R_SIZE_MAX));
882
+ pwdBuf.reset(new char[pwdBufSize]);
883
+ grpBufSize = std::max<long>(1024 * 128, sysconf(_SC_GETGR_R_SIZE_MAX));
892
884
  grpBuf.reset(new char[grpBufSize]);
893
885
 
894
886
  if (options.defaultGroup.empty()) {
@@ -920,7 +912,7 @@ protected:
920
912
  } else {
921
913
  defaultGroup = options.defaultGroup;
922
914
  }
923
-
915
+
924
916
  UPDATE_TRACE_POINT();
925
917
  userInfo = (struct passwd *) NULL;
926
918
  if (!options.user.empty()) {
@@ -950,7 +942,7 @@ protected:
950
942
  userInfo = (struct passwd *) NULL;
951
943
  }
952
944
  }
953
-
945
+
954
946
  UPDATE_TRACE_POINT();
955
947
  if (!options.group.empty()) {
956
948
  struct group *groupInfo = (struct group *) NULL;
@@ -1000,7 +992,7 @@ protected:
1000
992
  if (groupId == (gid_t) -1) {
1001
993
  throw RuntimeException("Cannot determine a group to lower privilege to");
1002
994
  }
1003
-
995
+
1004
996
  UPDATE_TRACE_POINT();
1005
997
  #ifdef __APPLE__
1006
998
  int groups[1024];
@@ -1110,11 +1102,11 @@ protected:
1110
1102
  return false;
1111
1103
  }
1112
1104
  }
1113
-
1105
+
1114
1106
  string serializeEnvvarsFromPoolOptions(const Options &options) const {
1115
1107
  vector< pair<StaticString, StaticString> >::const_iterator it, end;
1116
1108
  string result;
1117
-
1109
+
1118
1110
  appendNullTerminatedKeyValue(result, "IN_PASSENGER", "1");
1119
1111
  appendNullTerminatedKeyValue(result, "PYTHONUNBUFFERED", "1");
1120
1112
  appendNullTerminatedKeyValue(result, "NODE_PATH", config->resourceLocator.getNodeLibDir());
@@ -1134,14 +1126,14 @@ protected:
1134
1126
  "PASSENGER_BASE_URI",
1135
1127
  options.baseURI);
1136
1128
  }
1137
-
1129
+
1138
1130
  it = options.environmentVariables.begin();
1139
1131
  end = options.environmentVariables.end();
1140
1132
  while (it != end) {
1141
1133
  appendNullTerminatedKeyValue(result, it->first, it->second);
1142
1134
  it++;
1143
1135
  }
1144
-
1136
+
1145
1137
  return Base64::encode(result);
1146
1138
  }
1147
1139
 
@@ -1189,7 +1181,7 @@ protected:
1189
1181
  fflush(stdout);
1190
1182
  _exit(1);
1191
1183
  }
1192
-
1184
+
1193
1185
  // We set these environment variables here instead of
1194
1186
  // in the SpawnPreparer because SpawnPreparer might
1195
1187
  // be executed by bash, but these environment variables
@@ -1200,7 +1192,7 @@ protected:
1200
1192
  setenv("HOME", info.home.c_str(), 1);
1201
1193
  }
1202
1194
  }
1203
-
1195
+
1204
1196
  void setChroot(const SpawnPreparationInfo &info) {
1205
1197
  if (info.chrootDir != "/") {
1206
1198
  int ret = chroot(info.chrootDir.c_str());
@@ -1215,7 +1207,7 @@ protected:
1215
1207
  }
1216
1208
  }
1217
1209
  }
1218
-
1210
+
1219
1211
  void setWorkingDirectory(const SpawnPreparationInfo &info) {
1220
1212
  vector<string>::const_iterator it, end = info.appRootPathsInsideChroot.end();
1221
1213
  int ret;
@@ -1279,7 +1271,7 @@ protected:
1279
1271
  _exit(1);
1280
1272
  }
1281
1273
  }
1282
-
1274
+
1283
1275
  /**
1284
1276
  * Execute the process spawning negotiation protocol.
1285
1277
  */
@@ -1290,7 +1282,7 @@ protected:
1290
1282
  config->randomGenerator->generateAsciiString(11);
1291
1283
  details.connectPassword = config->randomGenerator->generateAsciiString(43);
1292
1284
  details.timeout = details.options->startTimeout * 1000;
1293
-
1285
+
1294
1286
  string result;
1295
1287
  try {
1296
1288
  result = readMessageLine(details);
@@ -1306,7 +1298,7 @@ protected:
1306
1298
  SpawnException::APP_STARTUP_TIMEOUT,
1307
1299
  details);
1308
1300
  }
1309
-
1301
+
1310
1302
  protocol_begin:
1311
1303
  if (result == "I have control 1.0\n") {
1312
1304
  UPDATE_TRACE_POINT();
@@ -1344,11 +1336,11 @@ protected:
1344
1336
  }
1345
1337
  return ProcessPtr(); // Never reached.
1346
1338
  }
1347
-
1339
+
1348
1340
  void handleSpawnErrorResponse(NegotiationDetails &details) {
1349
1341
  TRACE_POINT();
1350
1342
  map<string, string> attributes;
1351
-
1343
+
1352
1344
  while (true) {
1353
1345
  string line = readMessageLine(details);
1354
1346
  if (line.empty()) {
@@ -1366,7 +1358,7 @@ protected:
1366
1358
  } else if (line == "\n") {
1367
1359
  break;
1368
1360
  }
1369
-
1361
+
1370
1362
  string::size_type pos = line.find(": ");
1371
1363
  if (pos == string::npos) {
1372
1364
  throwAppSpawnException("An error occurred while starting the "
@@ -1375,12 +1367,12 @@ protected:
1375
1367
  SpawnException::APP_STARTUP_PROTOCOL_ERROR,
1376
1368
  details);
1377
1369
  }
1378
-
1370
+
1379
1371
  string key = line.substr(0, pos);
1380
1372
  string value = line.substr(pos + 2, line.size() - pos - 3);
1381
1373
  attributes[key] = value;
1382
1374
  }
1383
-
1375
+
1384
1376
  try {
1385
1377
  string message = details.io.readAll(&details.timeout);
1386
1378
  SpawnException e("An error occured while starting the web application.",
@@ -1404,7 +1396,7 @@ protected:
1404
1396
  details);
1405
1397
  }
1406
1398
  }
1407
-
1399
+
1408
1400
  void handleInvalidSpawnResponseType(const string &line, NegotiationDetails &details) {
1409
1401
  if (line.empty()) {
1410
1402
  throwAppSpawnException("An error occurred while starting "
@@ -1420,7 +1412,7 @@ protected:
1420
1412
  details);
1421
1413
  }
1422
1414
  }
1423
-
1415
+
1424
1416
  public:
1425
1417
  /**
1426
1418
  * Timestamp at which this Spawner was created. Microseconds resolution.
@@ -1431,10 +1423,10 @@ public:
1431
1423
  : config(_config),
1432
1424
  creationTime(SystemTime::getUsec())
1433
1425
  { }
1434
-
1426
+
1435
1427
  virtual ~Spawner() { }
1436
1428
  virtual ProcessPtr spawn(const Options &options) = 0;
1437
-
1429
+
1438
1430
  /** Does not depend on the event loop. */
1439
1431
  virtual bool cleanable() const {
1440
1432
  return false;