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.
- data/NEWS +32 -0
- data/Rakefile +1 -1
- data/build/common_library.rb +6 -1
- data/build/config.rb +3 -1
- data/doc/Users guide Apache.html +120 -39
- data/doc/Users guide Apache.txt +64 -0
- data/doc/Users guide Nginx.html +50 -2
- data/doc/Users guide Nginx.txt +29 -0
- data/ext/apache2/Bucket.cpp +7 -5
- data/ext/apache2/Bucket.h +2 -1
- data/ext/apache2/Configuration.cpp +8 -0
- data/ext/apache2/Configuration.hpp +9 -5
- data/ext/apache2/HelperAgent.cpp +4 -5
- data/ext/apache2/Hooks.cpp +1 -6
- data/ext/boost/thread/exceptions.hpp +7 -1
- data/ext/boost/thread/locks.hpp +11 -11
- data/ext/common/AgentBase.cpp +21 -1
- data/ext/common/AgentsStarter.hpp +22 -21
- data/ext/common/ApplicationPool/Client.h +0 -8
- data/ext/common/ApplicationPool/Server.h +22 -21
- data/ext/common/Constants.h +1 -1
- data/ext/common/EventedMessageServer.h +6 -2
- data/ext/common/IniFile.h +4 -4
- data/ext/common/Logging.h +1 -1
- data/ext/common/LoggingAgent/LoggingServer.h +2 -2
- data/ext/common/LoggingAgent/Main.cpp +2 -2
- data/ext/common/MessageChannel.h +20 -62
- data/ext/common/MessageReadersWriters.h +4 -4
- data/ext/common/MessageServer.h +18 -18
- data/ext/common/Process.h +4 -5
- data/ext/common/Session.h +6 -40
- data/ext/common/SpawnManager.h +20 -25
- data/ext/common/Utils.cpp +1 -1
- data/ext/common/Utils/Dechunker.h +1 -1
- data/ext/common/Utils/MessageIO.h +109 -14
- data/ext/common/Utils/StreamBoyerMooreHorspool.h +20 -14
- data/ext/common/Utils/VariantMap.h +9 -27
- data/ext/common/Watchdog.cpp +53 -42
- data/ext/libev/config.h +122 -0
- data/ext/nginx/Configuration.c +62 -0
- data/ext/nginx/Configuration.h +5 -0
- data/ext/nginx/ContentHandler.c +46 -19
- data/ext/nginx/HelperAgent.cpp +6 -5
- data/ext/nginx/config +12 -12
- data/ext/oxt/system_calls.cpp +10 -1
- data/ext/ruby/extconf.rb +0 -1
- data/ext/ruby/passenger_native_support.c +2 -2
- data/helper-scripts/prespawn +1 -1
- data/lib/phusion_passenger.rb +4 -4
- data/lib/phusion_passenger/classic_rails/application_spawner.rb +2 -2
- data/lib/phusion_passenger/dependencies.rb +6 -1
- data/lib/phusion_passenger/platform_info.rb +9 -0
- data/lib/phusion_passenger/platform_info/compiler.rb +5 -0
- data/lib/phusion_passenger/platform_info/operating_system.rb +1 -1
- data/lib/phusion_passenger/platform_info/ruby.rb +5 -5
- data/lib/phusion_passenger/rack/application_spawner.rb +6 -3
- data/lib/phusion_passenger/utils.rb +2 -2
- data/lib/phusion_passenger/wsgi/application_spawner.rb +1 -1
- data/resources/mime.types +2 -0
- data/test/cxx/LoggingTest.cpp +10 -12
- data/test/cxx/MessageIOTest.cpp +53 -3
- data/test/cxx/MessageReadersWritersTest.cpp +5 -2
- data/test/cxx/MessageServerTest.cpp +3 -1
- data/test/integration_tests/nginx_tests.rb +14 -1
- data/test/stub/rack/config.ru +2 -0
- data/test/tut/tut.h +9 -3
- metadata +5 -4
@@ -36,19 +36,19 @@
|
|
36
36
|
#include <unistd.h>
|
37
37
|
#include <signal.h>
|
38
38
|
|
39
|
-
#include
|
40
|
-
#include
|
41
|
-
#include
|
42
|
-
#include
|
43
|
-
#include
|
44
|
-
#include
|
45
|
-
#include
|
46
|
-
#include
|
47
|
-
#include
|
48
|
-
#include
|
49
|
-
#include
|
50
|
-
#include
|
51
|
-
#include
|
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
|
-
|
129
|
-
|
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
|
-
|
470
|
-
|
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.
|
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 =
|
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 =
|
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
|
-
|
168
|
+
int fd;
|
168
169
|
PoolOptions &options;
|
169
170
|
mutable StringListPtr result;
|
170
171
|
public:
|
171
|
-
EnvironmentVariablesFetcher(
|
172
|
-
:
|
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
|
-
|
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 (!
|
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.
|
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.
|
294
|
-
commonContext.
|
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.
|
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.
|
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.
|
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.
|
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.
|
348
|
+
writeArrayMessage(commonContext.fd, "true", NULL);
|
348
349
|
} else {
|
349
|
-
commonContext.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
414
|
+
writeScalarMessage(commonContext.fd, pool->toXml(includeSensitiveInfo));
|
414
415
|
}
|
415
416
|
|
416
417
|
public:
|
data/ext/common/Constants.h
CHANGED
@@ -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
|
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
|
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
@@ -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 =
|
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
|
-
|
271
|
+
writeArrayMessage(FEEDBACK_FD, "initialized", NULL);
|
272
272
|
}
|
273
273
|
sigintWatcher.set<&caughtExitSignal>();
|
274
274
|
sigintWatcher.start(SIGINT);
|
data/ext/common/MessageChannel.h
CHANGED
@@ -62,68 +62,10 @@ using namespace oxt;
|
|
62
62
|
|
63
63
|
|
64
64
|
/**
|
65
|
-
* Convenience class for
|
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
|
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
|
|