passenger 4.0.2 → 4.0.3

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 (79) hide show
  1. data.tar.gz.asc +7 -7
  2. data/NEWS +27 -0
  3. data/bin/passenger-config +6 -3
  4. data/bin/passenger-install-apache2-module +2 -2
  5. data/bin/passenger-install-nginx-module +16 -2
  6. data/build/agents.rb +4 -0
  7. data/build/apache2.rb +1 -1
  8. data/build/cplusplus_support.rb +1 -1
  9. data/build/cxx_tests.rb +3 -0
  10. data/build/packaging.rb +51 -8
  11. data/build/ruby_extension.rb +1 -1
  12. data/doc/Packaging.txt.md +20 -7
  13. data/doc/Users guide Apache.html +1 -1
  14. data/doc/Users guide Apache.txt +1 -1
  15. data/doc/Users guide Nginx.html +5 -4
  16. data/doc/Users guide Nginx.txt +1 -1
  17. data/doc/users_guide_snippets/installation.txt +5 -3
  18. data/ext/apache2/Configuration.cpp +12 -0
  19. data/ext/apache2/Configuration.hpp +7 -4
  20. data/ext/apache2/Hooks.cpp +29 -19
  21. data/ext/common/AgentsStarter.cpp +85 -57
  22. data/ext/common/AgentsStarter.h +570 -42
  23. data/ext/common/ApplicationPool2/DirectSpawner.h +5 -2
  24. data/ext/common/ApplicationPool2/Implementation.cpp +7 -1
  25. data/ext/common/ApplicationPool2/Pool.h +6 -3
  26. data/ext/common/ApplicationPool2/Process.h +12 -3
  27. data/ext/common/ApplicationPool2/SmartSpawner.h +2 -1
  28. data/ext/common/Constants.h +4 -1
  29. data/ext/common/EventedBufferedInput.h +139 -16
  30. data/ext/common/MultiLibeio.cpp +4 -2
  31. data/ext/common/SafeLibev.h +15 -62
  32. data/ext/common/ServerInstanceDir.h +10 -26
  33. data/ext/common/Utils.cpp +1 -3
  34. data/ext/common/Utils.h +1 -1
  35. data/ext/common/Utils/StrIntUtils.cpp +9 -0
  36. data/ext/common/Utils/StrIntUtils.h +5 -0
  37. data/ext/common/Utils/VariantMap.h +63 -14
  38. data/ext/common/agents/Base.cpp +50 -15
  39. data/ext/common/agents/HelperAgent/AgentOptions.h +20 -12
  40. data/ext/common/agents/HelperAgent/FileBackedPipe.h +1 -1
  41. data/ext/common/agents/HelperAgent/Main.cpp +5 -4
  42. data/ext/common/agents/HelperAgent/RequestHandler.h +1 -1
  43. data/ext/common/agents/LoggingAgent/Main.cpp +0 -1
  44. data/ext/common/agents/LoggingAgent/RemoteSender.h +2 -2
  45. data/ext/common/agents/SpawnPreparer.cpp +23 -5
  46. data/ext/common/agents/Watchdog/AgentWatcher.cpp +508 -0
  47. data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +93 -0
  48. data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +68 -0
  49. data/ext/common/agents/Watchdog/Main.cpp +180 -802
  50. data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +111 -0
  51. data/ext/nginx/Configuration.c +107 -92
  52. data/ext/nginx/Configuration.h +1 -0
  53. data/ext/nginx/ContentHandler.c +6 -6
  54. data/ext/nginx/ContentHandler.h +1 -1
  55. data/ext/nginx/config +8 -2
  56. data/ext/nginx/ngx_http_passenger_module.c +54 -60
  57. data/ext/nginx/ngx_http_passenger_module.h +6 -6
  58. data/lib/phusion_passenger.rb +17 -10
  59. data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
  60. data/lib/phusion_passenger/common_library.rb +0 -1
  61. data/lib/phusion_passenger/platform_info.rb +10 -1
  62. data/lib/phusion_passenger/platform_info/depcheck.rb +4 -4
  63. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +2 -2
  64. data/lib/phusion_passenger/platform_info/ruby.rb +7 -0
  65. data/lib/phusion_passenger/request_handler.rb +119 -42
  66. data/lib/phusion_passenger/request_handler/thread_handler.rb +25 -22
  67. data/lib/phusion_passenger/standalone/command.rb +2 -0
  68. data/lib/phusion_passenger/standalone/runtime_installer.rb +4 -3
  69. data/lib/phusion_passenger/standalone/start_command.rb +49 -37
  70. data/resources/templates/nginx/pcre_checksum_could_not_be_verified.txt.erb +11 -0
  71. data/test/cxx/CxxTestMain.cpp +2 -0
  72. data/test/cxx/EventedBufferedInputTest.cpp +758 -0
  73. data/test/cxx/ServerInstanceDirTest.cpp +16 -31
  74. data/test/cxx/TestSupport.cpp +2 -1
  75. data/test/cxx/VariantMapTest.cpp +23 -11
  76. metadata +8 -4
  77. metadata.gz.asc +7 -7
  78. data/ext/common/AgentsStarter.hpp +0 -655
  79. data/lib/phusion_passenger/utils/robust_interruption.rb +0 -173
@@ -54,7 +54,9 @@ struct Data {
54
54
  Data(const SafeLibevPtr &_libev, const MultiLibeio::Callback &_callback)
55
55
  : libev(_libev),
56
56
  callback(_callback)
57
- { }
57
+ {
58
+ assert(_libev != NULL);
59
+ }
58
60
  };
59
61
 
60
62
  struct CustomData: public Data {
@@ -96,7 +98,7 @@ static int
96
98
  dispatch(eio_req *req) {
97
99
  auto_ptr<Data> data((Data *) req->data);
98
100
  assert(data->libev != NULL); // Check for strange bug.
99
- data->libev->runLaterTS(boost::bind(data->callback, *req));
101
+ data->libev->runLater(boost::bind(data->callback, *req));
100
102
  return 0;
101
103
  }
102
104
 
@@ -58,23 +58,9 @@ private:
58
58
  { }
59
59
  };
60
60
 
61
- struct Timer {
62
- ev_timer realTimer;
63
- SafeLibev *self;
64
- Callback callback;
65
- list<Timer *>::iterator it;
66
-
67
- Timer(SafeLibev *_self, const Callback &_callback)
68
- : self(_self),
69
- callback(_callback)
70
- { }
71
- };
72
-
73
61
  struct ev_loop *loop;
74
62
  pthread_t loopThread;
75
63
  ev_async async;
76
- ev_idle idle;
77
- list<Timer *> timers;
78
64
 
79
65
  boost::mutex syncher;
80
66
  condition_variable cond;
@@ -86,17 +72,9 @@ private:
86
72
  self->runCommands();
87
73
  }
88
74
 
89
- static void idleHandler(EV_P_ ev_idle *idle, int revents) {
90
- SafeLibev *self = (SafeLibev *) idle->data;
91
- self->runCommands();
92
- }
93
-
94
- static void timeoutHandler(EV_P_ ev_timer *t, int revents) {
95
- auto_ptr<Timer> timer((Timer *) ((const char *) t));
96
- SafeLibev *self = timer->self;
97
- self->timers.erase(timer->it);
98
- ev_timer_stop(self->loop, &timer->realTimer);
99
- timer->callback();
75
+ static void timeoutHandler(int revents, void *arg) {
76
+ auto_ptr<Callback> callback((Callback *) arg);
77
+ (*callback)();
100
78
  }
101
79
 
102
80
  void runCommands() {
@@ -151,12 +129,9 @@ public:
151
129
  nextCommandId = 0;
152
130
 
153
131
  ev_async_init(&async, asyncHandler);
132
+ ev_set_priority(&async, EV_MAXPRI);
154
133
  async.data = this;
155
134
  ev_async_start(loop, &async);
156
-
157
- ev_idle_init(&idle, idleHandler);
158
- ev_set_priority(&idle, EV_MAXPRI);
159
- idle.data = this;
160
135
  }
161
136
 
162
137
  ~SafeLibev() {
@@ -166,15 +141,6 @@ public:
166
141
 
167
142
  void destroy() {
168
143
  ev_async_stop(loop, &async);
169
- ev_idle_stop(loop, &idle);
170
-
171
- list<Timer *>::iterator it, end = timers.end();
172
- for (it = timers.begin(); it != end; it++) {
173
- Timer *timer = *it;
174
- ev_timer_stop(loop, &timer->realTimer);
175
- delete timer;
176
- }
177
- timers.clear();
178
144
  }
179
145
 
180
146
  struct ev_loop *getLoop() const {
@@ -249,36 +215,23 @@ public:
249
215
  }
250
216
  }
251
217
 
252
- void runAsync(const Callback &callback) {
253
- runLaterTS(callback);
254
- }
255
-
256
- // TODO: make it possible to call this from a thread
218
+ /** Run a callback after a certain timeout. */
257
219
  void runAfter(unsigned int timeout, const Callback &callback) {
258
220
  assert(callback != NULL);
259
- Timer *timer = new Timer(this, callback);
260
- ev_timer_init(&timer->realTimer, timeoutHandler, timeout / 1000.0, 0);
261
- timers.push_front(timer);
262
- timer->it = timers.begin();
263
- ev_timer_start(loop, &timer->realTimer);
221
+ ev_once(loop, -1, 0, timeout / 1000.0, timeoutHandler, new Callback(callback));
264
222
  }
265
223
 
266
- unsigned int runLater(const Callback &callback) {
224
+ /** Thread-safe version of runAfter(). */
225
+ void runAfterTS(unsigned int timeout, const Callback &callback) {
267
226
  assert(callback != NULL);
268
- unsigned int result;
269
- {
270
- unique_lock<boost::mutex> l(syncher);
271
- commands.push_back(Command(nextCommandId, callback));
272
- result = nextCommandId;
273
- incNextCommandId();
274
- }
275
- if (!ev_is_active(&idle)) {
276
- ev_idle_start(loop, &idle);
227
+ if (pthread_equal(pthread_self(), loopThread)) {
228
+ runAfter(timeout, callback);
229
+ } else {
230
+ runLater(boost::bind(&SafeLibev::runAfter, this, timeout, callback));
277
231
  }
278
- return result;
279
232
  }
280
-
281
- unsigned int runLaterTS(const Callback &callback) {
233
+
234
+ unsigned int runLater(const Callback &callback) {
282
235
  assert(callback != NULL);
283
236
  unsigned int result;
284
237
  {
@@ -292,7 +245,7 @@ public:
292
245
  }
293
246
 
294
247
  /**
295
- * Cancels a callback that was scheduled to be run by runLater() and runLaterTS().
248
+ * Cancels a callback that was scheduled to be run by runLater().
296
249
  * Returns whether the command has been successfully cancelled or not.
297
250
  * That is, a return value of true guarantees that the callback will not be called
298
251
  * in the future, while a return value of false means that the callback has already
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010 Phusion
3
+ * Copyright (c) 2010-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -52,7 +52,7 @@ public:
52
52
  // Don't forget to update lib/phusion_passenger/admin_tools/server_instance.rb too.
53
53
  static const int DIR_STRUCTURE_MAJOR_VERSION = 1;
54
54
  static const int DIR_STRUCTURE_MINOR_VERSION = 0;
55
- static const int GENERATION_STRUCTURE_MAJOR_VERSION = 1;
55
+ static const int GENERATION_STRUCTURE_MAJOR_VERSION = 2;
56
56
  static const int GENERATION_STRUCTURE_MINOR_VERSION = 0;
57
57
 
58
58
  class Generation: public noncopyable {
@@ -179,7 +179,9 @@ public:
179
179
  return number;
180
180
  }
181
181
 
182
- string getPath() const {
182
+ // The 'const strng &' here is on purpose. The AgentsStarter C
183
+ // functions return the string pointer directly.
184
+ const string &getPath() const {
183
185
  return path;
184
186
  }
185
187
 
@@ -236,28 +238,6 @@ private:
236
238
  }
237
239
 
238
240
  public:
239
- ServerInstanceDir(pid_t webServerPid, const string &parentDir = "", bool owner = true) {
240
- string theParentDir;
241
-
242
- if (parentDir.empty()) {
243
- theParentDir = getSystemTempDir();
244
- } else {
245
- theParentDir = parentDir;
246
- }
247
-
248
- /* We embed the super structure version in the server instance directory name
249
- * because it's possible to upgrade Phusion Passenger without changing the
250
- * web server's PID. This way each incompatible upgrade will use its own
251
- * server instance directory.
252
- */
253
- initialize(theParentDir + "/passenger." +
254
- toString(DIR_STRUCTURE_MAJOR_VERSION) + "." +
255
- toString(DIR_STRUCTURE_MINOR_VERSION) + "." +
256
- toString<unsigned long long>(webServerPid),
257
- owner);
258
-
259
- }
260
-
261
241
  ServerInstanceDir(const string &path, bool owner = true) {
262
242
  initialize(path, owner);
263
243
  }
@@ -280,7 +260,9 @@ public:
280
260
  }
281
261
  }
282
262
 
283
- string getPath() const {
263
+ // The 'const strng &' here is on purpose. The AgentsStarter C
264
+ // functions return the string pointer directly.
265
+ const string &getPath() const {
284
266
  return path;
285
267
  }
286
268
 
@@ -307,6 +289,8 @@ public:
307
289
  }
308
290
 
309
291
  GenerationPtr getGeneration(unsigned int number) const {
292
+ // Must not used make_shared() here because Watchdog.cpp
293
+ // deletes the raw pointer in cleanupAgentsInBackground().
310
294
  return ptr(new Generation(path, number));
311
295
  }
312
296
 
@@ -712,7 +712,7 @@ verifyWSGIDir(const string &dir, CachedFileStat *cstat, unsigned int throttleRat
712
712
 
713
713
  void
714
714
  prestartWebApps(const ResourceLocator &locator, const string &ruby,
715
- const string &serializedprestartURLs)
715
+ const vector<string> &prestartURLs)
716
716
  {
717
717
  /* Apache calls the initialization routines twice during startup, and
718
718
  * as a result it starts two helper servers, where the first one exits
@@ -724,11 +724,9 @@ prestartWebApps(const ResourceLocator &locator, const string &ruby,
724
724
 
725
725
  this_thread::disable_interruption di;
726
726
  this_thread::disable_syscall_interruption dsi;
727
- vector<string> prestartURLs;
728
727
  vector<string>::const_iterator it;
729
728
  string prespawnScript = locator.getHelperScriptsDir() + "/prespawn";
730
729
 
731
- split(Base64::decode(serializedprestartURLs), '\0', prestartURLs);
732
730
  it = prestartURLs.begin();
733
731
  while (it != prestartURLs.end() && !this_thread::interruption_requested()) {
734
732
  if (it->empty()) {
@@ -366,7 +366,7 @@ bool verifyWSGIDir(const string &dir, CachedFileStat *cstat = 0,
366
366
  unsigned int throttleRate = 0);
367
367
 
368
368
  void prestartWebApps(const ResourceLocator &locator, const string &ruby,
369
- const string &serializedprestartURLs);
369
+ const vector<string> &prestartURLs);
370
370
 
371
371
  /**
372
372
  * Runs the given function and catches any tracable_exceptions. Upon catching such an exception,
@@ -121,6 +121,15 @@ replaceString(const string &str, const string &toFind, const string &replaceWith
121
121
  }
122
122
  }
123
123
 
124
+ string
125
+ replaceAll(const string &str, const string &toFind, const string &replaceWith) {
126
+ string result = str;
127
+ while (result.find(toFind) != string::npos) {
128
+ result = replaceString(result, toFind, replaceWith);
129
+ }
130
+ return result;
131
+ }
132
+
124
133
  string
125
134
  strip(const StaticString &str) {
126
135
  const char *data = str.data();
@@ -103,6 +103,11 @@ void splitIncludeSep(const StaticString & restrict_ref str,
103
103
  */
104
104
  string replaceString(const string &str, const string &toFind, const string &replaceWith);
105
105
 
106
+ /**
107
+ * Like replaceString(), but replace all occurrences of `toFind`.
108
+ */
109
+ string replaceAll(const string &str, const string &toFind, const string &replaceWith);
110
+
106
111
  /**
107
112
  * Strips leading and trailing whitespaces.
108
113
  */
@@ -29,9 +29,12 @@
29
29
  #include <oxt/macros.hpp>
30
30
  #include <sys/types.h>
31
31
  #include <map>
32
+ #include <set>
33
+ #include <vector>
32
34
  #include <string>
33
35
  #include <Exceptions.h>
34
36
  #include <Utils/StrIntUtils.h>
37
+ #include <Utils/Base64.h>
35
38
  #include <Utils/MessageIO.h>
36
39
 
37
40
  namespace Passenger {
@@ -124,19 +127,25 @@ public:
124
127
  }
125
128
  unsigned int i = 0;
126
129
  while (i < argc) {
127
- store[argv[i]] = argv[i + 1];
130
+ string name = argv[i];
131
+ if (startsWith(name, "--")) {
132
+ name.erase(0, 2);
133
+ }
134
+ name = replaceAll(name, "-", "_");
135
+
136
+ store[name] = replaceAll(argv[i + 1], "-", "_");
128
137
  i += 2;
129
138
  }
130
139
  }
131
140
 
132
141
  /**
133
- * Populates a VariantMap from the data in <em>fd</em>. MessageIO
142
+ * Populates a VariantMap from the data in `fd`. MessageIO
134
143
  * is used to read from the file descriptor.
135
144
  *
136
145
  * @throws SystemException
137
146
  * @throws IOException
138
147
  */
139
- void readFrom(int fd) {
148
+ void readFrom(int fd, const StaticString &messageName = "VariantMap") {
140
149
  TRACE_POINT();
141
150
  vector<string> args;
142
151
 
@@ -146,7 +155,7 @@ public:
146
155
  if (args.size() == 0) {
147
156
  throw IOException("Unexpected empty message received from channel");
148
157
  }
149
- if (args[0] != "VariantMap") {
158
+ if (args[0] != messageName) {
150
159
  throw IOException("Unexpected message '" + args[0] + "' received from channel");
151
160
  }
152
161
  if (args.size() % 2 != 1) {
@@ -165,19 +174,26 @@ public:
165
174
  }
166
175
 
167
176
  VariantMap &set(const string &name, const string &value) {
168
- store[name] = value;
177
+ if (value.empty()) {
178
+ map<string, string>::iterator it = store.find(name);
179
+ if (it != store.end()) {
180
+ store.erase(it);
181
+ }
182
+ } else {
183
+ store[name] = value;
184
+ }
169
185
  return *this;
170
186
  }
171
187
 
172
188
  VariantMap &setDefault(const string &name, const string &value) {
173
189
  if (store.find(name) == store.end()) {
174
- store[name] = value;
190
+ set(name, value);
175
191
  }
176
192
  return *this;
177
193
  }
178
194
 
179
195
  VariantMap &setInt(const string &name, int value) {
180
- store[name] = toString(value);
196
+ set(name, toString(value));
181
197
  return *this;
182
198
  }
183
199
 
@@ -189,7 +205,7 @@ public:
189
205
  }
190
206
 
191
207
  VariantMap &setULL(const string &name, unsigned long long value) {
192
- store[name] = toString(value);
208
+ set(name, toString(value));
193
209
  return *this;
194
210
  }
195
211
 
@@ -201,7 +217,7 @@ public:
201
217
  }
202
218
 
203
219
  VariantMap &setPid(const string &name, pid_t value) {
204
- store[name] = toString((unsigned long long) value);
220
+ set(name, toString((unsigned long long) value));
205
221
  return *this;
206
222
  }
207
223
 
@@ -213,7 +229,7 @@ public:
213
229
  }
214
230
 
215
231
  VariantMap &setUid(const string &name, uid_t value) {
216
- store[name] = toString((long long) value);
232
+ set(name, toString((long long) value));
217
233
  return *this;
218
234
  }
219
235
 
@@ -225,7 +241,7 @@ public:
225
241
  }
226
242
 
227
243
  VariantMap &setGid(const string &name, gid_t value) {
228
- store[name] = toString((long long) value);
244
+ set(name, toString((long long) value));
229
245
  return *this;
230
246
  }
231
247
 
@@ -237,7 +253,7 @@ public:
237
253
  }
238
254
 
239
255
  VariantMap &setBool(const string &name, bool value) {
240
- store[name] = value ? "true" : "false";
256
+ set(name, value ? "true" : "false");
241
257
  return *this;
242
258
  }
243
259
 
@@ -248,6 +264,18 @@ public:
248
264
  return *this;
249
265
  }
250
266
 
267
+ VariantMap &setStrSet(const string &name, const std::set<string> &value) {
268
+ std::set<string>::const_iterator it;
269
+ string result;
270
+
271
+ for (it = value.begin(); it != value.end(); it++) {
272
+ result.append(*it);
273
+ result.append(1, '\0');
274
+ }
275
+ set(name, Base64::encode(result));
276
+ return *this;
277
+ }
278
+
251
279
  const string &get(const string &name, bool required = true) const {
252
280
  map<string, string>::const_iterator it = store.find(name);
253
281
  if (it == store.end()) {
@@ -329,6 +357,18 @@ public:
329
357
  }
330
358
  return result;
331
359
  }
360
+
361
+ vector<string> getStrSet(const string &name, bool required = true,
362
+ const vector<string> &defaultValue = vector<string>()) const
363
+ {
364
+ vector<string> result = defaultValue;
365
+ const string *str;
366
+ if (lookup(name, required, &str)) {
367
+ result.clear();
368
+ split(Base64::decode(*str), '\0', result);
369
+ }
370
+ return result;
371
+ }
332
372
 
333
373
  bool erase(const string &name) {
334
374
  return store.erase(name) != 0;
@@ -343,6 +383,15 @@ public:
343
383
  unsigned int size() const {
344
384
  return store.size();
345
385
  }
386
+
387
+ void addTo(VariantMap &other) const {
388
+ map<string, string>::const_iterator it;
389
+ map<string, string>::const_iterator end = store.end();
390
+
391
+ for (it = store.begin(); it != end; it++) {
392
+ other.set(it->first, it->second);
393
+ }
394
+ }
346
395
 
347
396
  /**
348
397
  * Writes a representation of the contents in this VariantMap to
@@ -351,13 +400,13 @@ public:
351
400
  *
352
401
  * @throws SystemException
353
402
  */
354
- void writeToFd(int fd) const {
403
+ void writeToFd(int fd, const StaticString &messageName = "VariantMap") const {
355
404
  map<string, string>::const_iterator it;
356
405
  map<string, string>::const_iterator end = store.end();
357
406
  vector<string> args;
358
407
 
359
408
  args.reserve(1 + 2 * store.size());
360
- args.push_back("VariantMap");
409
+ args.push_back(messageName);
361
410
  for (it = store.begin(); it != end; it++) {
362
411
  args.push_back(it->first);
363
412
  args.push_back(it->second);