passenger 3.0.9 → 3.0.10

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 (67) hide show
  1. data/NEWS +32 -0
  2. data/Rakefile +1 -1
  3. data/build/common_library.rb +6 -1
  4. data/build/config.rb +3 -1
  5. data/doc/Users guide Apache.html +120 -39
  6. data/doc/Users guide Apache.txt +64 -0
  7. data/doc/Users guide Nginx.html +50 -2
  8. data/doc/Users guide Nginx.txt +29 -0
  9. data/ext/apache2/Bucket.cpp +7 -5
  10. data/ext/apache2/Bucket.h +2 -1
  11. data/ext/apache2/Configuration.cpp +8 -0
  12. data/ext/apache2/Configuration.hpp +9 -5
  13. data/ext/apache2/HelperAgent.cpp +4 -5
  14. data/ext/apache2/Hooks.cpp +1 -6
  15. data/ext/boost/thread/exceptions.hpp +7 -1
  16. data/ext/boost/thread/locks.hpp +11 -11
  17. data/ext/common/AgentBase.cpp +21 -1
  18. data/ext/common/AgentsStarter.hpp +22 -21
  19. data/ext/common/ApplicationPool/Client.h +0 -8
  20. data/ext/common/ApplicationPool/Server.h +22 -21
  21. data/ext/common/Constants.h +1 -1
  22. data/ext/common/EventedMessageServer.h +6 -2
  23. data/ext/common/IniFile.h +4 -4
  24. data/ext/common/Logging.h +1 -1
  25. data/ext/common/LoggingAgent/LoggingServer.h +2 -2
  26. data/ext/common/LoggingAgent/Main.cpp +2 -2
  27. data/ext/common/MessageChannel.h +20 -62
  28. data/ext/common/MessageReadersWriters.h +4 -4
  29. data/ext/common/MessageServer.h +18 -18
  30. data/ext/common/Process.h +4 -5
  31. data/ext/common/Session.h +6 -40
  32. data/ext/common/SpawnManager.h +20 -25
  33. data/ext/common/Utils.cpp +1 -1
  34. data/ext/common/Utils/Dechunker.h +1 -1
  35. data/ext/common/Utils/MessageIO.h +109 -14
  36. data/ext/common/Utils/StreamBoyerMooreHorspool.h +20 -14
  37. data/ext/common/Utils/VariantMap.h +9 -27
  38. data/ext/common/Watchdog.cpp +53 -42
  39. data/ext/libev/config.h +122 -0
  40. data/ext/nginx/Configuration.c +62 -0
  41. data/ext/nginx/Configuration.h +5 -0
  42. data/ext/nginx/ContentHandler.c +46 -19
  43. data/ext/nginx/HelperAgent.cpp +6 -5
  44. data/ext/nginx/config +12 -12
  45. data/ext/oxt/system_calls.cpp +10 -1
  46. data/ext/ruby/extconf.rb +0 -1
  47. data/ext/ruby/passenger_native_support.c +2 -2
  48. data/helper-scripts/prespawn +1 -1
  49. data/lib/phusion_passenger.rb +4 -4
  50. data/lib/phusion_passenger/classic_rails/application_spawner.rb +2 -2
  51. data/lib/phusion_passenger/dependencies.rb +6 -1
  52. data/lib/phusion_passenger/platform_info.rb +9 -0
  53. data/lib/phusion_passenger/platform_info/compiler.rb +5 -0
  54. data/lib/phusion_passenger/platform_info/operating_system.rb +1 -1
  55. data/lib/phusion_passenger/platform_info/ruby.rb +5 -5
  56. data/lib/phusion_passenger/rack/application_spawner.rb +6 -3
  57. data/lib/phusion_passenger/utils.rb +2 -2
  58. data/lib/phusion_passenger/wsgi/application_spawner.rb +1 -1
  59. data/resources/mime.types +2 -0
  60. data/test/cxx/LoggingTest.cpp +10 -12
  61. data/test/cxx/MessageIOTest.cpp +53 -3
  62. data/test/cxx/MessageReadersWritersTest.cpp +5 -2
  63. data/test/cxx/MessageServerTest.cpp +3 -1
  64. data/test/integration_tests/nginx_tests.rb +14 -1
  65. data/test/stub/rack/config.ru +2 -0
  66. data/test/tut/tut.h +9 -3
  67. metadata +5 -4
@@ -36,19 +36,19 @@
36
36
  #include <unistd.h>
37
37
  #include <signal.h>
38
38
 
39
- #include "Constants.h"
40
- #include "FileDescriptor.h"
41
- #include "MessageChannel.h"
42
- #include "MessageClient.h"
43
- #include "ServerInstanceDir.h"
44
- #include "Exceptions.h"
45
- #include "ResourceLocator.h"
46
- #include "Utils.h"
47
- #include "Utils/IOUtils.h"
48
- #include "Utils/Base64.h"
49
- #include "Utils/Timer.h"
50
- #include "Utils/ScopeGuard.h"
51
- #include "Utils/VariantMap.h"
39
+ #include <Constants.h>
40
+ #include <FileDescriptor.h>
41
+ #include <MessageClient.h>
42
+ #include <ServerInstanceDir.h>
43
+ #include <Exceptions.h>
44
+ #include <ResourceLocator.h>
45
+ #include <Utils.h>
46
+ #include <Utils/IOUtils.h>
47
+ #include <Utils/MessageIO.h>
48
+ #include <Utils/Base64.h>
49
+ #include <Utils/Timer.h>
50
+ #include <Utils/ScopeGuard.h>
51
+ #include <Utils/VariantMap.h>
52
52
 
53
53
  namespace Passenger {
54
54
 
@@ -125,8 +125,8 @@ private:
125
125
  if (fd != FEEDBACK_FD && syscalls::dup2(fd, FEEDBACK_FD) == -1) {
126
126
  int e = errno;
127
127
  try {
128
- MessageChannel channel(fd);
129
- channel.write("system error",
128
+ writeArrayMessage(fd,
129
+ "system error",
130
130
  "dup2() failed",
131
131
  toString(e).c_str(),
132
132
  NULL);
@@ -466,8 +466,10 @@ public:
466
466
  execl(watchdogFilename.c_str(), "PassengerWatchdog", (char *) 0);
467
467
  e = errno;
468
468
  try {
469
- MessageChannel channel(FEEDBACK_FD);
470
- channel.write("exec error", toString(e).c_str(), NULL);
469
+ writeArrayMessage(FEEDBACK_FD,
470
+ "exec error",
471
+ toString(e).c_str(),
472
+ NULL);
471
473
  _exit(1);
472
474
  } catch (...) {
473
475
  fprintf(stderr, "Passenger AgentsStarter: could not execute %s: %s (%d)\n",
@@ -483,7 +485,6 @@ public:
483
485
  // Parent
484
486
  UPDATE_TRACE_POINT();
485
487
  FileDescriptor feedbackFd = fds[0];
486
- MessageChannel feedbackChannel(fds[0]);
487
488
  vector<string> args;
488
489
  bool result, allAgentsStarted;
489
490
 
@@ -501,7 +502,7 @@ public:
501
502
  * reading the arguments. We'll notice that later.
502
503
  */
503
504
  try {
504
- watchdogArgs.writeToChannel(feedbackChannel);
505
+ watchdogArgs.writeToFd(feedbackFd);
505
506
  } catch (const SystemException &e) {
506
507
  if (e.code() != EPIPE && e.code() != ECONNRESET) {
507
508
  inspectWatchdogCrashReason(pid);
@@ -516,7 +517,7 @@ public:
516
517
  UPDATE_TRACE_POINT();
517
518
 
518
519
  try {
519
- result = feedbackChannel.read(args);
520
+ result = readArrayMessage(feedbackFd, args);
520
521
  } catch (const SystemException &ex) {
521
522
  if (ex.code() == ECONNRESET) {
522
523
  inspectWatchdogCrashReason(pid);
@@ -585,7 +586,7 @@ public:
585
586
  while (!allAgentsStarted) {
586
587
  try {
587
588
  UPDATE_TRACE_POINT();
588
- result = feedbackChannel.read(args);
589
+ result = readArrayMessage(feedbackFd, args);
589
590
  } catch (const SystemException &ex) {
590
591
  killProcessGroupAndWait(&pid, 5000);
591
592
  guard.clear();
@@ -186,14 +186,6 @@ protected:
186
186
  return fd;
187
187
  }
188
188
 
189
- virtual void setReaderTimeout(unsigned int msec) {
190
- MessageChannel(fd).setReadTimeout(msec);
191
- }
192
-
193
- virtual void setWriterTimeout(unsigned int msec) {
194
- MessageChannel(fd).setWriteTimeout(msec);
195
- }
196
-
197
189
  virtual void shutdownReader() {
198
190
  if (fd != -1) {
199
191
  int ret = syscalls::shutdown(fd, SHUT_RD);
@@ -44,6 +44,7 @@
44
44
  #include "../FileDescriptor.h"
45
45
  #include "../Exceptions.h"
46
46
  #include "../Utils.h"
47
+ #include "../Utils/MessageIO.h"
47
48
 
48
49
  namespace Passenger {
49
50
  namespace ApplicationPool {
@@ -164,13 +165,12 @@ private:
164
165
  */
165
166
  class EnvironmentVariablesFetcher: public StringListCreator {
166
167
  private:
167
- MessageChannel &channel;
168
+ int fd;
168
169
  PoolOptions &options;
169
170
  mutable StringListPtr result;
170
171
  public:
171
- EnvironmentVariablesFetcher(MessageChannel &theChannel, PoolOptions &theOptions)
172
- : channel(theChannel),
173
- options(theOptions)
172
+ EnvironmentVariablesFetcher(int theFd, PoolOptions &theOptions)
173
+ : fd(theFd), options(theOptions)
174
174
  { }
175
175
 
176
176
  /**
@@ -189,14 +189,14 @@ private:
189
189
  * where the connection with the client will be broken.
190
190
  */
191
191
  try {
192
- channel.write("getEnvironmentVariables", NULL);
192
+ writeArrayMessage(fd, "getEnvironmentVariables", NULL);
193
193
  } catch (const SystemException &e) {
194
194
  throw ClientCommunicationError(
195
195
  "Unable to send a 'getEnvironmentVariables' request to the client",
196
196
  e.code());
197
197
  }
198
198
  try {
199
- if (!channel.readScalar(data)) {
199
+ if (!readScalarMessage(fd, data)) {
200
200
  throw ClientCommunicationError("Unable to read a reply from the client for the 'getEnvironmentVariables' request.");
201
201
  }
202
202
  } catch (const SystemException &e) {
@@ -278,7 +278,7 @@ private:
278
278
  try {
279
279
  PoolOptions options(args, 1, analyticsLogger);
280
280
  options.environmentVariables = ptr(new EnvironmentVariablesFetcher(
281
- commonContext.channel, options));
281
+ commonContext.fd, options));
282
282
  options.initiateSession = false;
283
283
  session = pool->get(options);
284
284
  specificContext->sessions[specificContext->lastSessionID] = session;
@@ -290,23 +290,23 @@ private:
290
290
  if (e.hasErrorPage()) {
291
291
  P_TRACE(3, "Client " << commonContext.name() << ": SpawnException "
292
292
  "occured (with error page)");
293
- commonContext.channel.write("SpawnException", e.what(), "true", NULL);
294
- commonContext.channel.writeScalar(e.getErrorPage());
293
+ writeArrayMessage(commonContext.fd, "SpawnException", e.what(), "true", NULL);
294
+ writeScalarMessage(commonContext.fd, e.getErrorPage());
295
295
  } else {
296
296
  P_TRACE(3, "Client " << commonContext.name() << ": SpawnException "
297
297
  "occured (no error page)");
298
- commonContext.channel.write("SpawnException", e.what(), "false", NULL);
298
+ writeArrayMessage(commonContext.fd, "SpawnException", e.what(), "false", NULL);
299
299
  }
300
300
  failed = true;
301
301
  } catch (const BusyException &e) {
302
302
  UPDATE_TRACE_POINT();
303
303
  this_thread::disable_syscall_interruption dsi;
304
- commonContext.channel.write("BusyException", e.what(), NULL);
304
+ writeArrayMessage(commonContext.fd, "BusyException", e.what(), NULL);
305
305
  failed = true;
306
306
  } catch (const IOException &e) {
307
307
  UPDATE_TRACE_POINT();
308
308
  this_thread::disable_syscall_interruption dsi;
309
- commonContext.channel.write("IOException", e.what(), NULL);
309
+ writeArrayMessage(commonContext.fd, "IOException", e.what(), NULL);
310
310
  failed = true;
311
311
  }
312
312
  UPDATE_TRACE_POINT();
@@ -314,7 +314,8 @@ private:
314
314
  this_thread::disable_syscall_interruption dsi;
315
315
  try {
316
316
  UPDATE_TRACE_POINT();
317
- commonContext.channel.write("ok",
317
+ writeArrayMessage(commonContext.fd,
318
+ "ok",
318
319
  toString(session->getPid()).c_str(),
319
320
  session->getSocketType().c_str(),
320
321
  session->getSocketName().c_str(),
@@ -344,9 +345,9 @@ private:
344
345
  TRACE_POINT();
345
346
  commonContext.requireRights(Account::DETACH);
346
347
  if (pool->detach(args[1])) {
347
- commonContext.channel.write("true", NULL);
348
+ writeArrayMessage(commonContext.fd, "true", NULL);
348
349
  } else {
349
- commonContext.channel.write("false", NULL);
350
+ writeArrayMessage(commonContext.fd, "false", NULL);
350
351
  }
351
352
  }
352
353
 
@@ -371,19 +372,19 @@ private:
371
372
  void processGetActive(CommonClientContext &commonContext, SpecificContext *specificContext, const vector<string> &args) {
372
373
  TRACE_POINT();
373
374
  commonContext.requireRights(Account::GET_PARAMETERS);
374
- commonContext.channel.write(toString(pool->getActive()).c_str(), NULL);
375
+ writeArrayMessage(commonContext.fd, toString(pool->getActive()).c_str(), NULL);
375
376
  }
376
377
 
377
378
  void processGetCount(CommonClientContext &commonContext, SpecificContext *specificContext, const vector<string> &args) {
378
379
  TRACE_POINT();
379
380
  commonContext.requireRights(Account::GET_PARAMETERS);
380
- commonContext.channel.write(toString(pool->getCount()).c_str(), NULL);
381
+ writeArrayMessage(commonContext.fd, toString(pool->getCount()).c_str(), NULL);
381
382
  }
382
383
 
383
384
  void processGetGlobalQueueSize(CommonClientContext &commonContext, SpecificContext *specificContext, const vector<string> &args) {
384
385
  TRACE_POINT();
385
386
  commonContext.requireRights(Account::GET_PARAMETERS);
386
- commonContext.channel.write(toString(pool->getGlobalQueueSize()).c_str(), NULL);
387
+ writeArrayMessage(commonContext.fd, toString(pool->getGlobalQueueSize()).c_str(), NULL);
387
388
  }
388
389
 
389
390
  void processSetMaxPerApp(CommonClientContext &commonContext, SpecificContext *specificContext, unsigned int maxPerApp) {
@@ -395,13 +396,13 @@ private:
395
396
  void processGetSpawnServerPid(CommonClientContext &commonContext, SpecificContext *specificContext, const vector<string> &args) {
396
397
  TRACE_POINT();
397
398
  commonContext.requireRights(Account::GET_PARAMETERS);
398
- commonContext.channel.write(toString(pool->getSpawnServerPid()).c_str(), NULL);
399
+ writeArrayMessage(commonContext.fd, toString(pool->getSpawnServerPid()).c_str(), NULL);
399
400
  }
400
401
 
401
402
  void processInspect(CommonClientContext &commonContext, SpecificContext *specificContext, const vector<string> &args) {
402
403
  TRACE_POINT();
403
404
  commonContext.requireRights(Account::INSPECT_BASIC_INFO);
404
- commonContext.channel.writeScalar(pool->inspect());
405
+ writeScalarMessage(commonContext.fd, pool->inspect());
405
406
  }
406
407
 
407
408
  void processToXml(CommonClientContext &commonContext, SpecificContext *specificContext, const vector<string> &args) {
@@ -410,7 +411,7 @@ private:
410
411
  bool includeSensitiveInfo =
411
412
  commonContext.account->hasRights(Account::INSPECT_SENSITIVE_INFO) &&
412
413
  args[1] == "true";
413
- commonContext.channel.writeScalar(pool->toXml(includeSensitiveInfo));
414
+ writeScalarMessage(commonContext.fd, pool->toXml(includeSensitiveInfo));
414
415
  }
415
416
 
416
417
  public:
@@ -26,7 +26,7 @@
26
26
  #define _PASSENGER_CONSTANTS_H_
27
27
 
28
28
  /* Don't forget to update lib/phusion_passenger.rb too. */
29
- #define PASSENGER_VERSION "3.0.9"
29
+ #define PASSENGER_VERSION "3.0.10"
30
30
 
31
31
  #define FEEDBACK_FD 3
32
32
 
@@ -28,6 +28,8 @@
28
28
  #include <boost/shared_ptr.hpp>
29
29
  #include <ev++.h>
30
30
  #include <cstdarg>
31
+ #include <cstdlib>
32
+ #include <alloca.h>
31
33
  #include "EventedServer.h"
32
34
  #include "MessageReadersWriters.h"
33
35
  #include "AccountsDatabase.h"
@@ -87,7 +89,8 @@ public:
87
89
  }
88
90
  va_end(ap);
89
91
 
90
- StaticString args[count + 1];
92
+ StaticString *args = (StaticString *)
93
+ alloca((count + 1) * sizeof(StaticString));
91
94
  unsigned int i = 1;
92
95
 
93
96
  args[0] = name;
@@ -109,7 +112,8 @@ public:
109
112
  void writeArrayMessage(StaticString args[], unsigned int count) {
110
113
  char headerBuf[sizeof(uint16_t)];
111
114
  unsigned int outSize = ArrayMessage::outputSize(count);
112
- StaticString out[outSize];
115
+ StaticString *out = (StaticString *)
116
+ alloca(outSize * sizeof(StaticString));
113
117
 
114
118
  ArrayMessage::generate(args, count, headerBuf, out, outSize);
115
119
  write(out, outSize);
data/ext/common/IniFile.h CHANGED
@@ -176,7 +176,7 @@ protected:
176
176
  }
177
177
 
178
178
  void accept() {
179
- if (upcomingChar == EOF) return;
179
+ if ((int) upcomingChar == EOF) return;
180
180
 
181
181
  lastAcceptedChar = (char)iniFileStream.get();
182
182
  upcomingChar = (char)iniFileStream.peek();
@@ -189,7 +189,7 @@ protected:
189
189
  }
190
190
 
191
191
  void ignore() {
192
- if (upcomingChar == EOF) return;
192
+ if ((int) upcomingChar == EOF) return;
193
193
 
194
194
  upcomingChar = (char)iniFileStream.peek();
195
195
  currentColumn++;
@@ -261,7 +261,7 @@ protected:
261
261
  int column = currentColumn;
262
262
  string result;
263
263
 
264
- while (upcomingChar != '\n' && upcomingChar != EOF) {
264
+ while (upcomingChar != '\n' && (int) upcomingChar != EOF) {
265
265
  result.append(1, upcomingChar);
266
266
  accept();
267
267
  }
@@ -282,7 +282,7 @@ protected:
282
282
  int column = currentColumn;
283
283
  string result;
284
284
 
285
- while (upcomingChar != EOF) {
285
+ while ((int) upcomingChar != EOF) {
286
286
  result.append(1, upcomingChar);
287
287
  accept();
288
288
  }
data/ext/common/Logging.h CHANGED
@@ -696,7 +696,7 @@ public:
696
696
  template<typename T>
697
697
  static bool instanceof(const std::exception &e) {
698
698
  try {
699
- dynamic_cast<const T &>(e);
699
+ (void) dynamic_cast<const T &>(e);
700
700
  return true;
701
701
  } catch (const bad_cast &) {
702
702
  return false;
@@ -49,11 +49,11 @@
49
49
  #include "../MessageReadersWriters.h"
50
50
  #include "../StaticString.h"
51
51
  #include "../Exceptions.h"
52
- #include "../MessageChannel.h"
53
52
  #include "../Constants.h"
54
53
  #include "../Utils.h"
55
54
  #include "../Utils/MD5.h"
56
55
  #include "../Utils/IOUtils.h"
56
+ #include "../Utils/MessageIO.h"
57
57
  #include "../Utils/StrIntUtils.h"
58
58
  #include "../Utils/StringMap.h"
59
59
 
@@ -68,7 +68,7 @@ using namespace oxt;
68
68
  class LoggingServer: public EventedMessageServer {
69
69
  private:
70
70
  static const int MAX_LOG_SINK_CACHE_SIZE = 512;
71
- static const int GARBAGE_COLLECTION_TIMEOUT = (int) (1.25 * 60 * 60); // 1 hour 15 minutes
71
+ static const int GARBAGE_COLLECTION_TIMEOUT = 4500; // 1 hour 15 minutes
72
72
 
73
73
  struct LogSink;
74
74
  typedef shared_ptr<LogSink> LogSinkPtr;
@@ -44,6 +44,7 @@
44
44
  #include "../Exceptions.h"
45
45
  #include "../Utils.h"
46
46
  #include "../Utils/IOUtils.h"
47
+ #include "../Utils/MessageIO.h"
47
48
  #include "../Utils/Base64.h"
48
49
  #include "../Utils/VariantMap.h"
49
50
 
@@ -265,10 +266,9 @@ main(int argc, char *argv[]) {
265
266
  ev::sig sigquitWatcher(eventLoop);
266
267
 
267
268
  if (feedbackFdAvailable()) {
268
- MessageChannel feedbackChannel(FEEDBACK_FD);
269
269
  feedbackFdWatcher.set<&feedbackFdBecameReadable>();
270
270
  feedbackFdWatcher.start(FEEDBACK_FD, ev::READ);
271
- feedbackChannel.write("initialized", NULL);
271
+ writeArrayMessage(FEEDBACK_FD, "initialized", NULL);
272
272
  }
273
273
  sigintWatcher.set<&caughtExitSignal>();
274
274
  sigintWatcher.start(SIGINT);
@@ -62,68 +62,10 @@ using namespace oxt;
62
62
 
63
63
 
64
64
  /**
65
- * Convenience class for I/O operations on file descriptors.
66
- *
67
- * This class provides convenience methods for:
68
- * - sending and receiving raw data over a file descriptor.
69
- * - sending and receiving messages over a file descriptor.
70
- * - file descriptor passing over a Unix socket.
71
- * - data size limit enforcement and time constraint enforcement.
72
- * All of these methods use exceptions for error reporting.
73
- *
74
- * There are two kinds of messages:
75
- * - Array messages. These are just a list of strings, and the message
76
- * itself has a specific length. The contained strings may not
77
- * contain NUL characters (<tt>'\\0'</tt>). Note that an array message
78
- * must have at least one element.
79
- * - Scalar messages. These are byte strings which may contain arbitrary
80
- * binary data. Scalar messages also have a specific length.
81
- * The protocol is designed to be low overhead, easy to implement and
82
- * easy to parse.
83
- *
84
- * MessageChannel is to be wrapped around a file descriptor. For example:
85
- * @code
86
- * int p[2];
87
- * pipe(p);
88
- * MessageChannel channel1(p[0]);
89
- * MessageChannel channel2(p[1]);
90
- *
91
- * // Send an array message.
92
- * channel2.write("hello", "world !!", NULL);
93
- * list<string> args;
94
- * channel1.read(args); // args now contains { "hello", "world !!" }
95
- *
96
- * // Send a scalar message.
97
- * channel2.writeScalar("some long string which can contain arbitrary binary data");
98
- * string str;
99
- * channel1.readScalar(str);
100
- * @endcode
101
- *
102
- * The life time of a MessageChannel is independent from that of the
103
- * wrapped file descriptor. If a MessageChannel object is destroyed,
104
- * the file descriptor is not automatically closed. Call close()
105
- * if you want to close the file descriptor.
106
- *
107
- * @note I/O operations are not buffered.
108
- * @note Be careful with mixing the sending/receiving of array messages,
109
- * scalar messages and file descriptors. If you send a collection of any
110
- * of these in a specific order, then the receiving side must receive them
111
- * in the exact some order. So suppose you first send a message, then a
112
- * file descriptor, then a scalar, then the receiving side must first
113
- * receive a message, then a file descriptor, then a scalar. If the
114
- * receiving side does things in the wrong order then bad things will
115
- * happen.
116
- * @note MessageChannel is not thread-safe, but is reentrant.
117
- * @note Some methods throw SecurityException and TimeoutException. When these
118
- * exceptions are thrown, the channel will be left in an inconsistent state
119
- * because only parts of the data have been read. You should close the channel
120
- * after having caught these exceptions.
121
- *
122
- * @ingroup Support
65
+ * Convenience wrapper class for MessageIO operations on file descriptors.
123
66
  */
124
67
  class MessageChannel {
125
68
  private:
126
- const static char DELIMITER = '\0';
127
69
  int fd;
128
70
 
129
71
  #ifdef __OpenBSD__
@@ -196,10 +138,26 @@ public:
196
138
  * @see read(), write(const char *, ...)
197
139
  */
198
140
  template<typename StringArrayType>
199
- void write(const StringArrayType &args) {
141
+ void writeEx(const StringArrayType &args) {
200
142
  writeArrayMessage(fd, args);
201
143
  }
202
144
 
145
+ void write(const vector<StaticString> &args) {
146
+ writeArrayMessageEx(fd, args);
147
+ }
148
+
149
+ void write(const vector<string> &args) {
150
+ writeArrayMessageEx(fd, args);
151
+ }
152
+
153
+ void write(const list<StaticString> &args) {
154
+ writeArrayMessageEx(fd, args);
155
+ }
156
+
157
+ void write(const list<string> &args) {
158
+ writeArrayMessageEx(fd, args);
159
+ }
160
+
203
161
  /**
204
162
  * Send an array message, which consists of the given strings, over the underlying
205
163
  * file descriptor. Like <tt>write(const char *name, ...)</tt> but takes a va_list
@@ -465,9 +423,9 @@ public:
465
423
  */
466
424
  int readFileDescriptor(bool negotiate = true) {
467
425
  if (negotiate) {
468
- Passenger::readFileDescriptorWithNegotiation(fd);
426
+ return Passenger::readFileDescriptorWithNegotiation(fd);
469
427
  } else {
470
- Passenger::readFileDescriptor(fd);
428
+ return Passenger::readFileDescriptor(fd);
471
429
  }
472
430
  }
473
431