passenger 3.0.8 → 3.0.9

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 (42) hide show
  1. data/NEWS +9 -0
  2. data/bin/passenger-install-nginx-module +1 -1
  3. data/build/basics.rb +0 -1
  4. data/build/cxx_tests.rb +5 -0
  5. data/build/rpm.rb +1 -1
  6. data/doc/Users guide Apache.html +1 -1
  7. data/doc/Users guide Nginx.html +1 -1
  8. data/ext/apache2/Configuration.cpp +12 -0
  9. data/ext/apache2/Configuration.hpp +12 -1
  10. data/ext/apache2/Hooks.cpp +2 -0
  11. data/ext/common/AgentsStarter.cpp +4 -0
  12. data/ext/common/AgentsStarter.h +2 -0
  13. data/ext/common/AgentsStarter.hpp +4 -0
  14. data/ext/common/Constants.h +1 -1
  15. data/ext/common/Logging.h +481 -261
  16. data/ext/common/LoggingAgent/LoggingServer.h +10 -4
  17. data/ext/common/LoggingAgent/Main.cpp +7 -2
  18. data/ext/common/LoggingAgent/RemoteSender.h +25 -3
  19. data/ext/common/MessageChannel.h +18 -227
  20. data/ext/common/MessageClient.h +95 -92
  21. data/ext/common/Utils/IOUtils.cpp +114 -1
  22. data/ext/common/Utils/IOUtils.h +57 -1
  23. data/ext/common/Utils/MessageIO.h +576 -0
  24. data/ext/nginx/Configuration.c +35 -0
  25. data/ext/nginx/Configuration.h +2 -0
  26. data/ext/nginx/ContentHandler.c +17 -6
  27. data/ext/nginx/ngx_http_passenger_module.c +8 -0
  28. data/lib/phusion_passenger.rb +2 -2
  29. data/lib/phusion_passenger/analytics_logger.rb +174 -117
  30. data/lib/phusion_passenger/app_process.rb +14 -2
  31. data/test/cxx/CxxTestMain.cpp +14 -19
  32. data/test/cxx/IOUtilsTest.cpp +68 -18
  33. data/test/cxx/LoggingTest.cpp +20 -24
  34. data/test/cxx/MessageChannelTest.cpp +1 -1
  35. data/test/cxx/MessageIOTest.cpp +310 -0
  36. data/test/cxx/TestSupport.cpp +47 -0
  37. data/test/cxx/TestSupport.h +8 -0
  38. data/test/ruby/analytics_logger_spec.rb +20 -28
  39. data/test/tut/tut.h +2 -0
  40. metadata +11 -11
  41. data/build/rdoctask.rb +0 -209
  42. data/test/cxx/HttpStatusExtractorTest.cpp +0 -198
@@ -185,7 +185,8 @@ private:
185
185
  virtual void dump(ostream &stream) const {
186
186
  stream << " Log file: file=" << filename << ", "
187
187
  "opened=" << opened << ", "
188
- "age=" << long(ev_now(server->getLoop()) - lastUsed) << "\n";
188
+ "lastUsed=" << long(ev_now(server->getLoop()) - lastUsed) << "s ago, "
189
+ "lastFlushed=" << long(ev_now(server->getLoop()) - lastFlushed) << "s ago\n";
189
190
  }
190
191
  };
191
192
 
@@ -268,7 +269,8 @@ private:
268
269
  "node=" << nodeName << ", "
269
270
  "category=" << category << ", "
270
271
  "opened=" << opened << ", "
271
- "age=" << long(ev_now(server->getLoop()) - lastUsed) << ", "
272
+ "lastUsed=" << long(ev_now(server->getLoop()) - lastUsed) << "s ago, "
273
+ "lastFlushed=" << long(ev_now(server->getLoop()) - lastFlushed) << "s ago, "
272
274
  "bufferSize=" << bufferSize <<
273
275
  "\n";
274
276
  }
@@ -1206,11 +1208,15 @@ public:
1206
1208
  gid_t gid = GROUP_NOT_GIVEN,
1207
1209
  const string &unionStationGatewayAddress = DEFAULT_UNION_STATION_GATEWAY_ADDRESS,
1208
1210
  unsigned short unionStationGatewayPort = DEFAULT_UNION_STATION_GATEWAY_PORT,
1209
- const string &unionStationGatewayCert = "")
1211
+ const string &unionStationGatewayCert = "",
1212
+ const string &unionStationProxyAddress = "",
1213
+ const string &unionStationProxyPort = "")
1210
1214
  : EventedMessageServer(loop, fd, accountsDatabase),
1211
1215
  remoteSender(unionStationGatewayAddress,
1212
1216
  unionStationGatewayPort,
1213
- unionStationGatewayCert),
1217
+ unionStationGatewayCert,
1218
+ unionStationProxyAddress,
1219
+ unionStationProxyPort),
1214
1220
  garbageCollectionTimer(loop),
1215
1221
  sinkFlushingTimer(loop),
1216
1222
  exitTimer(loop)
@@ -162,7 +162,9 @@ main(int argc, char *argv[]) {
162
162
  false, DEFAULT_UNION_STATION_GATEWAY_ADDRESS);
163
163
  int unionStationGatewayPort = options.getInt("union_station_gateway_port",
164
164
  false, DEFAULT_UNION_STATION_GATEWAY_PORT);
165
- string unionStationGatewayCert = options.get("union_station_gateway_cert", false);
165
+ string unionStationGatewayCert = options.get("union_station_gateway_cert", false);
166
+ string unionStationProxyAddress = options.get("union_station_proxy_address", false);
167
+ string unionStationProxyType = options.get("union_station_proxy_type", false);
166
168
 
167
169
  curl_global_init(CURL_GLOBAL_ALL);
168
170
 
@@ -251,7 +253,9 @@ main(int argc, char *argv[]) {
251
253
  "u=rwx,g=rx,o=rx", GROUP_NOT_GIVEN,
252
254
  unionStationGatewayAddress,
253
255
  unionStationGatewayPort,
254
- unionStationGatewayCert);
256
+ unionStationGatewayCert,
257
+ unionStationProxyAddress,
258
+ unionStationProxyType);
255
259
  loggingServer = &server;
256
260
 
257
261
 
@@ -276,6 +280,7 @@ main(int argc, char *argv[]) {
276
280
 
277
281
  /********** Initialized! Enter main loop... **********/
278
282
 
283
+ P_DEBUG("Logging agent online, listening at " << socketAddress);
279
284
  ev_loop(eventLoop, 0);
280
285
  return exitCode;
281
286
  } catch (const tracable_exception &e) {
@@ -72,6 +72,8 @@ private:
72
72
  string ip;
73
73
  unsigned short port;
74
74
  string certificate;
75
+ string proxyAddress;
76
+ string proxyType;
75
77
 
76
78
  CURL *curl;
77
79
  struct curl_slist *headers;
@@ -103,6 +105,16 @@ private:
103
105
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
104
106
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlDataReceived);
105
107
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
108
+ if (!proxyAddress.empty()) {
109
+ curl_easy_setopt(curl, CURLOPT_PROXY, proxyAddress.c_str());
110
+ if (proxyType.empty() || proxyType == "http") {
111
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
112
+ } else if (proxyType == "socks5") {
113
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
114
+ } else {
115
+ throw RuntimeException("Only 'http' and 'socks5' proxies are supported.");
116
+ }
117
+ }
106
118
  if (certificate.empty()) {
107
119
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
108
120
  } else {
@@ -129,10 +141,14 @@ private:
129
141
  }
130
142
 
131
143
  public:
132
- Server(const string &ip, const string &hostName, unsigned short port, const string &cert) {
144
+ Server(const string &ip, const string &hostName, unsigned short port, const string &cert,
145
+ const string &proxyAddress, const string &proxyType)
146
+ {
133
147
  this->ip = ip;
134
148
  this->port = port;
135
149
  certificate = cert;
150
+ this->proxyAddress = proxyAddress;
151
+ this->proxyType = proxyType;
136
152
 
137
153
  hostHeader = "Host: " + hostName;
138
154
  headers = NULL;
@@ -245,6 +261,8 @@ private:
245
261
  string gatewayAddress;
246
262
  unsigned short gatewayPort;
247
263
  string certificate;
264
+ string proxyAddress;
265
+ string proxyType;
248
266
  BlockingQueue<Item> queue;
249
267
  oxt::thread *thr;
250
268
 
@@ -298,7 +316,8 @@ private:
298
316
 
299
317
  servers.clear();
300
318
  for (it = ips.begin(); it != ips.end(); it++) {
301
- ServerPtr server(new Server(*it, gatewayAddress, gatewayPort, certificate));
319
+ ServerPtr server = make_shared<Server>(*it, gatewayAddress, gatewayPort,
320
+ certificate, proxyAddress, proxyType);
302
321
  if (server->ping()) {
303
322
  servers.push_back(server);
304
323
  } else {
@@ -418,12 +437,15 @@ private:
418
437
  }
419
438
 
420
439
  public:
421
- RemoteSender(const string &gatewayAddress, unsigned short gatewayPort, const string &certificate)
440
+ RemoteSender(const string &gatewayAddress, unsigned short gatewayPort, const string &certificate,
441
+ const string &proxyAddress, const string &proxyType)
422
442
  : queue(1024)
423
443
  {
424
444
  this->gatewayAddress = gatewayAddress;
425
445
  this->gatewayPort = gatewayPort;
426
446
  this->certificate = certificate;
447
+ this->proxyAddress = proxyAddress;
448
+ this->proxyType = proxyType;
427
449
  thr = new oxt::thread(
428
450
  boost::bind(&RemoteSender::threadMain, this),
429
451
  "RemoteSender thread",
@@ -53,6 +53,7 @@
53
53
  #include "Utils/Timer.h"
54
54
  #include "Utils/MemZeroGuard.h"
55
55
  #include "Utils/IOUtils.h"
56
+ #include "Utils/MessageIO.h"
56
57
 
57
58
  namespace Passenger {
58
59
 
@@ -194,52 +195,9 @@ public:
194
195
  * @pre None of the message elements may contain a NUL character (<tt>'\\0'</tt>).
195
196
  * @see read(), write(const char *, ...)
196
197
  */
197
- template<typename StringArrayType, typename StringArrayConstIteratorType>
198
+ template<typename StringArrayType>
198
199
  void write(const StringArrayType &args) {
199
- StringArrayConstIteratorType it;
200
- string data;
201
- uint16_t dataSize = 0;
202
-
203
- for (it = args.begin(); it != args.end(); it++) {
204
- dataSize += it->size() + 1;
205
- }
206
- data.reserve(dataSize + sizeof(dataSize));
207
- dataSize = htons(dataSize);
208
- data.append((const char *) &dataSize, sizeof(dataSize));
209
- for (it = args.begin(); it != args.end(); it++) {
210
- data.append(*it);
211
- data.append(1, DELIMITER);
212
- }
213
-
214
- writeExact(fd, data);
215
- }
216
-
217
- /**
218
- * Send an array message, which consists of the given elements, over the underlying
219
- * file descriptor.
220
- *
221
- * @param args The message elements.
222
- * @throws SystemException An error occured while writing the data to the file descriptor.
223
- * @throws boost::thread_interrupted
224
- * @pre None of the message elements may contain a NUL character (<tt>'\\0'</tt>).
225
- * @see read(), write(const char *, ...)
226
- */
227
- void write(const list<string> &args) {
228
- write<list<string>, list<string>::const_iterator>(args);
229
- }
230
-
231
- /**
232
- * Send an array message, which consists of the given elements, over the underlying
233
- * file descriptor.
234
- *
235
- * @param args The message elements.
236
- * @throws SystemException An error occured while writing the data to the file descriptor.
237
- * @throws boost::thread_interrupted
238
- * @pre None of the message elements may contain a NUL character (<tt>'\\0'</tt>).
239
- * @see read(), write(const char *, ...)
240
- */
241
- void write(const vector<string> &args) {
242
- write<vector<string>, vector<string>::const_iterator>(args);
200
+ writeArrayMessage(fd, args);
243
201
  }
244
202
 
245
203
  /**
@@ -252,18 +210,7 @@ public:
252
210
  * @pre None of the message elements may contain a NUL character (<tt>'\\0'</tt>).
253
211
  */
254
212
  void write(const char *name, va_list &ap) {
255
- list<string> args;
256
- args.push_back(name);
257
-
258
- while (true) {
259
- const char *arg = va_arg(ap, const char *);
260
- if (arg == NULL) {
261
- break;
262
- } else {
263
- args.push_back(arg);
264
- }
265
- }
266
- write(args);
213
+ writeArrayMessage(fd, name, ap);
267
214
  }
268
215
 
269
216
  /**
@@ -297,8 +244,7 @@ public:
297
244
  * @throws boost::thread_interrupted
298
245
  */
299
246
  void writeUint32(unsigned int value) {
300
- uint32_t l = htonl(value);
301
- writeExact(fd, &l, sizeof(uint32_t));
247
+ Passenger::writeUint32(fd, value);
302
248
  }
303
249
 
304
250
  /**
@@ -314,7 +260,7 @@ public:
314
260
  * @see readScalar(), writeScalar(const char *, unsigned int)
315
261
  */
316
262
  void writeScalar(const string &str) {
317
- writeScalar(str.c_str(), str.size());
263
+ writeScalarMessage(fd, str);
318
264
  }
319
265
 
320
266
  /**
@@ -332,8 +278,7 @@ public:
332
278
  * @see readScalar(), writeScalar(const string &)
333
279
  */
334
280
  void writeScalar(const char *data, unsigned int size) {
335
- writeUint32(size);
336
- writeExact(fd, data, size);
281
+ writeScalarMessage(fd, data, size);
337
282
  }
338
283
 
339
284
  /**
@@ -348,69 +293,10 @@ public:
348
293
  * @see readFileDescriptor()
349
294
  */
350
295
  void writeFileDescriptor(int fileDescriptor, bool negotiate = true) {
351
- // See message_channel.rb for more info about negotiation.
352
- if (negotiate) {
353
- vector<string> args;
354
-
355
- if (!read(args)) {
356
- throw IOException("Unexpected end of stream encountered while pre-negotiating a file descriptor");
357
- } else if (args.size() != 1 || args[0] != "pass IO") {
358
- throw IOException("FD passing pre-negotiation message expected.");
359
- }
360
- }
361
-
362
- struct msghdr msg;
363
- struct iovec vec;
364
- char dummy[1];
365
- #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
366
- struct {
367
- struct cmsghdr header;
368
- int fd;
369
- } control_data;
370
- #else
371
- char control_data[CMSG_SPACE(sizeof(int))];
372
- #endif
373
- struct cmsghdr *control_header;
374
- int ret;
375
-
376
- msg.msg_name = NULL;
377
- msg.msg_namelen = 0;
378
-
379
- /* Linux and Solaris require msg_iov to be non-NULL. */
380
- dummy[0] = '\0';
381
- vec.iov_base = dummy;
382
- vec.iov_len = sizeof(dummy);
383
- msg.msg_iov = &vec;
384
- msg.msg_iovlen = 1;
385
-
386
- msg.msg_control = (caddr_t) &control_data;
387
- msg.msg_controllen = sizeof(control_data);
388
- msg.msg_flags = 0;
389
-
390
- control_header = CMSG_FIRSTHDR(&msg);
391
- control_header->cmsg_level = SOL_SOCKET;
392
- control_header->cmsg_type = SCM_RIGHTS;
393
- #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
394
- control_header->cmsg_len = sizeof(control_data);
395
- control_data.fd = fileDescriptor;
396
- #else
397
- control_header->cmsg_len = CMSG_LEN(sizeof(int));
398
- memcpy(CMSG_DATA(control_header), &fileDescriptor, sizeof(int));
399
- #endif
400
-
401
- ret = syscalls::sendmsg(fd, &msg, 0);
402
- if (ret == -1) {
403
- throw SystemException("Cannot send file descriptor with sendmsg()", errno);
404
- }
405
-
406
296
  if (negotiate) {
407
- vector<string> args;
408
-
409
- if (!read(args)) {
410
- throw IOException("Unexpected end of stream encountered while post-negotiating a file descriptor");
411
- } else if (args.size() != 1 || args[0] != "got IO") {
412
- throw IOException("FD passing post-negotiation message expected.");
413
- }
297
+ Passenger::writeFileDescriptorWithNegotiation(fd, fileDescriptor);
298
+ } else {
299
+ Passenger::writeFileDescriptor(fd, fileDescriptor);
414
300
  }
415
301
  }
416
302
 
@@ -425,44 +311,12 @@ public:
425
311
  * @see write()
426
312
  */
427
313
  bool read(vector<string> &args) {
428
- uint16_t size;
429
- int ret;
430
- unsigned int alreadyRead = 0;
431
-
432
- do {
433
- ret = syscalls::read(fd, (char *) &size + alreadyRead, sizeof(size) - alreadyRead);
434
- if (ret == -1) {
435
- throw SystemException("read() failed", errno);
436
- } else if (ret == 0) {
437
- return false;
438
- }
439
- alreadyRead += ret;
440
- } while (alreadyRead < sizeof(size));
441
- size = ntohs(size);
442
-
443
- string buffer;
444
- args.clear();
445
- buffer.reserve(size);
446
- while (buffer.size() < size) {
447
- char tmp[1024 * 8];
448
- ret = syscalls::read(fd, tmp, min(size - buffer.size(), sizeof(tmp)));
449
- if (ret == -1) {
450
- throw SystemException("read() failed", errno);
451
- } else if (ret == 0) {
452
- return false;
453
- }
454
- buffer.append(tmp, ret);
455
- }
456
-
457
- if (!buffer.empty()) {
458
- string::size_type start = 0, pos;
459
- const string &const_buffer(buffer);
460
- while ((pos = const_buffer.find('\0', start)) != string::npos) {
461
- args.push_back(const_buffer.substr(start, pos - start));
462
- start = pos + 1;
463
- }
314
+ try {
315
+ args = readArrayMessage(fd);
316
+ return true;
317
+ } catch (const EOFException &) {
318
+ return false;
464
319
  }
465
- return true;
466
320
  }
467
321
 
468
322
  /**
@@ -610,74 +464,11 @@ public:
610
464
  * @throws boost::thread_interrupted
611
465
  */
612
466
  int readFileDescriptor(bool negotiate = true) {
613
- // See message_channel.rb for more info about negotiation.
614
- if (negotiate) {
615
- write("pass IO", NULL);
616
- }
617
-
618
- struct msghdr msg;
619
- struct iovec vec;
620
- char dummy[1];
621
- #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
622
- // File descriptor passing macros (CMSG_*) seem to be broken
623
- // on 64-bit MacOS X. This structure works around the problem.
624
- struct {
625
- struct cmsghdr header;
626
- int fd;
627
- } control_data;
628
- #define EXPECTED_CMSG_LEN sizeof(control_data)
629
- #else
630
- char control_data[CMSG_SPACE(sizeof(int))];
631
- #define EXPECTED_CMSG_LEN CMSG_LEN(sizeof(int))
632
- #endif
633
- struct cmsghdr *control_header;
634
- int ret;
635
-
636
- msg.msg_name = NULL;
637
- msg.msg_namelen = 0;
638
-
639
- dummy[0] = '\0';
640
- vec.iov_base = dummy;
641
- vec.iov_len = sizeof(dummy);
642
- msg.msg_iov = &vec;
643
- msg.msg_iovlen = 1;
644
-
645
- msg.msg_control = (caddr_t) &control_data;
646
- msg.msg_controllen = sizeof(control_data);
647
- msg.msg_flags = 0;
648
-
649
- ret = syscalls::recvmsg(fd, &msg, 0);
650
- if (ret == -1) {
651
- throw SystemException("Cannot read file descriptor with recvmsg()", errno);
652
- }
653
-
654
- control_header = CMSG_FIRSTHDR(&msg);
655
- if (control_header == NULL) {
656
- throw IOException("No valid file descriptor received.");
657
- }
658
- if (control_header->cmsg_len != EXPECTED_CMSG_LEN
659
- || control_header->cmsg_level != SOL_SOCKET
660
- || control_header->cmsg_type != SCM_RIGHTS) {
661
- throw IOException("No valid file descriptor received.");
662
- }
663
-
664
- #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
665
- int fd = control_data.fd;
666
- #else
667
- int fd = *((int *) CMSG_DATA(control_header));
668
- #endif
669
-
670
467
  if (negotiate) {
671
- try {
672
- write("got IO", NULL);
673
- } catch (...) {
674
- this_thread::disable_syscall_interruption dsi;
675
- syscalls::close(fd);
676
- throw;
677
- }
468
+ Passenger::readFileDescriptorWithNegotiation(fd);
469
+ } else {
470
+ Passenger::readFileDescriptor(fd);
678
471
  }
679
-
680
- return fd;
681
472
  }
682
473
 
683
474
  /**