passenger-jmazzi 2.2.9 → 2.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/NEWS CHANGED
@@ -1,3 +1,13 @@
1
+ Release 2.2.10
2
+ --------------
3
+
4
+ * Fixed some Bundler compatibility problems.
5
+ * Fixed some file descriptor passing problems, which previously
6
+ could lead to mysterious crashes.
7
+ * Fixed some compilation problems on newer GCC versions. Issue #430.
8
+ * Support #size method in rack.input.
9
+
10
+
1
11
  Release 2.2.9
2
12
  -------------
3
13
 
@@ -319,12 +319,24 @@ public:
319
319
  * descriptor is a Unix socket.
320
320
  *
321
321
  * @param fileDescriptor The file descriptor to pass.
322
+ * @param negotiate See Ruby's MessageChannel#send_io method's comments.
322
323
  * @throws SystemException Something went wrong during file descriptor passing.
323
324
  * @throws boost::thread_interrupted
324
325
  * @pre <tt>fileDescriptor >= 0</tt>
325
326
  * @see readFileDescriptor()
326
327
  */
327
- void writeFileDescriptor(int fileDescriptor) {
328
+ void writeFileDescriptor(int fileDescriptor, bool negotiate = true) {
329
+ // See message_channel.rb for more info about negotiation.
330
+ if (negotiate) {
331
+ vector<string> args;
332
+
333
+ if (!read(args)) {
334
+ throw IOException("Unexpected end of stream encountered while pre-negotiating a file descriptor");
335
+ } else if (args.size() != 1 || args[0] != "pass IO") {
336
+ throw IOException("FD passing pre-negotiation message expected.");
337
+ }
338
+ }
339
+
328
340
  struct msghdr msg;
329
341
  struct iovec vec;
330
342
  char dummy[1];
@@ -368,6 +380,16 @@ public:
368
380
  if (ret == -1) {
369
381
  throw SystemException("Cannot send file descriptor with sendmsg()", errno);
370
382
  }
383
+
384
+ if (negotiate) {
385
+ vector<string> args;
386
+
387
+ if (!read(args)) {
388
+ throw IOException("Unexpected end of stream encountered while post-negotiating a file descriptor");
389
+ } else if (args.size() != 1 || args[0] != "got IO") {
390
+ throw IOException("FD passing post-negotiation message expected.");
391
+ }
392
+ }
371
393
  }
372
394
 
373
395
  /**
@@ -492,6 +514,7 @@ public:
492
514
  * Receive a file descriptor, which had been passed over the underlying
493
515
  * file descriptor.
494
516
  *
517
+ * @param negotiate See Ruby's MessageChannel#send_io method's comments.
495
518
  * @return The passed file descriptor.
496
519
  * @throws SystemException If something went wrong during the
497
520
  * receiving of a file descriptor. Perhaps the underlying
@@ -500,7 +523,12 @@ public:
500
523
  * file descriptor.
501
524
  * @throws boost::thread_interrupted
502
525
  */
503
- int readFileDescriptor() {
526
+ int readFileDescriptor(bool negotiate = true) {
527
+ // See message_channel.rb for more info about negotiation.
528
+ if (negotiate) {
529
+ write("pass IO", NULL);
530
+ }
531
+
504
532
  struct msghdr msg;
505
533
  struct iovec vec;
506
534
  char dummy[1];
@@ -538,16 +566,32 @@ public:
538
566
  }
539
567
 
540
568
  control_header = CMSG_FIRSTHDR(&msg);
569
+ if (control_header == NULL) {
570
+ throw IOException("No valid file descriptor received.");
571
+ }
541
572
  if (control_header->cmsg_len != EXPECTED_CMSG_LEN
542
573
  || control_header->cmsg_level != SOL_SOCKET
543
574
  || control_header->cmsg_type != SCM_RIGHTS) {
544
575
  throw IOException("No valid file descriptor received.");
545
576
  }
577
+
546
578
  #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
547
- return control_data.fd;
579
+ int fd = control_data.fd;
548
580
  #else
549
- return *((int *) CMSG_DATA(control_header));
581
+ int fd = *((int *) CMSG_DATA(control_header));
550
582
  #endif
583
+
584
+ if (negotiate) {
585
+ try {
586
+ write("got IO", NULL);
587
+ } catch (...) {
588
+ this_thread::disable_syscall_interruption dsi;
589
+ syscalls::close(fd);
590
+ throw;
591
+ }
592
+ }
593
+
594
+ return fd;
551
595
  }
552
596
 
553
597
  /**
@@ -26,6 +26,6 @@
26
26
  #define _PASSENGER_VERSION_H_
27
27
 
28
28
  /* Don't forget to update lib/phusion_passenger/constants.rb too. */
29
- #define PASSENGER_VERSION "2.2.9"
29
+ #define PASSENGER_VERSION "2.2.10"
30
30
 
31
31
  #endif /* _PASSENGER_VERSION_H */
@@ -26,6 +26,7 @@
26
26
  #include <string>
27
27
  #include <cstdio>
28
28
  #include <cstdlib>
29
+ #include <cstring>
29
30
 
30
31
  namespace Passenger {
31
32
 
@@ -25,6 +25,7 @@
25
25
 
26
26
  #include <string>
27
27
  #include <map>
28
+ #include <cstdlib>
28
29
 
29
30
  #include "StaticString.h"
30
31
 
@@ -158,10 +158,14 @@ recv_fd(VALUE self, VALUE socket_fd) {
158
158
  }
159
159
 
160
160
  control_header = CMSG_FIRSTHDR(&msg);
161
+ if (control_header == NULL) {
162
+ rb_raise(rb_eIOError, "No valid file descriptor received.");
163
+ return Qnil;
164
+ }
161
165
  if (control_header->cmsg_len != EXPECTED_CMSG_LEN
162
166
  || control_header->cmsg_level != SOL_SOCKET
163
167
  || control_header->cmsg_type != SCM_RIGHTS) {
164
- rb_sys_fail("No valid file descriptor received.");
168
+ rb_raise(rb_eIOError, "No valid file descriptor received.");
165
169
  return Qnil;
166
170
  }
167
171
  #if defined(__APPLE__) || defined(__SOLARIS__) || defined(__arm__)
@@ -24,7 +24,7 @@
24
24
  module PhusionPassenger
25
25
  # Phusion Passenger version number.
26
26
  # Don't forget to edit ext/common/Version.h too.
27
- VERSION_STRING = '2.2.9'
27
+ VERSION_STRING = '2.2.10'
28
28
 
29
29
  DEFAULT_FRAMEWORK_SPAWNER_MAX_IDLE_TIME = 30 * 60
30
30
  DEFAULT_APP_SPAWNER_MAX_IDLE_TIME = 10 * 60
@@ -193,8 +193,11 @@ class MessageChannel
193
193
  #
194
194
  # Might raise SystemCallError, IOError or SocketError when something
195
195
  # goes wrong.
196
- def recv_io
197
- return @io.recv_io
196
+ def recv_io(klass = IO, negotiate = true)
197
+ write("pass IO") if negotiate
198
+ io = @io.recv_io(klass)
199
+ write("got IO") if negotiate
200
+ return io
198
201
  end
199
202
 
200
203
  # Send an IO object (a file descriptor) over the channel. The other
@@ -204,7 +207,46 @@ class MessageChannel
204
207
  # Might raise SystemCallError, IOError or SocketError when something
205
208
  # goes wrong.
206
209
  def send_io(io)
207
- @io.send_io(io)
210
+ # We read a message before actually calling #send_io
211
+ # in order to prevent the other side from accidentally
212
+ # read()ing past the normal data and reading our file
213
+ # descriptor too.
214
+ #
215
+ # For example suppose that side A looks like this:
216
+ #
217
+ # read(fd, buf, 1024)
218
+ # read_io(fd)
219
+ #
220
+ # and side B:
221
+ #
222
+ # write(fd, buf, 100)
223
+ # send_io(fd_to_pass)
224
+ #
225
+ # If B completes both write() and send_io(), then A's read() call
226
+ # reads past the 100 bytes that B sent. On some platforms, like
227
+ # Linux, this will cause read_io() to fail. And it just so happens
228
+ # that Ruby's IO#read method slurps more than just the given amount
229
+ # of bytes.
230
+ result = read
231
+ if !result
232
+ raise EOFError, "End of stream"
233
+ elsif result != ["pass IO"]
234
+ raise IOError, "IO passing pre-negotiation header expected"
235
+ else
236
+ @io.send_io(io)
237
+ # Once you've sent the IO you expect to be able to close it on the
238
+ # sender's side, even if the other side hasn't read the IO yet.
239
+ # Not so: on some operating systems (I'm looking at you OS X) this
240
+ # can cause the receiving side to receive a bad file descriptor.
241
+ # The post negotiation protocol ensures that we block until the
242
+ # other side has really received the IO.
243
+ result = read
244
+ if !result
245
+ raise EOFError, "End of stream"
246
+ elsif result != ["got IO"]
247
+ raise IOError, "IO passing post-negotiation header expected"
248
+ end
249
+ end
208
250
  end
209
251
 
210
252
  # Return the file descriptor of the underlying IO object.
@@ -97,6 +97,10 @@ private
97
97
  if options["lower_privilege"]
98
98
  lower_privilege('config.ru', options["lowest_user"])
99
99
  end
100
+ # Make sure RubyGems uses any new environment variable values
101
+ # that have been set now (e.g. $HOME, $GEM_HOME, etc) and that
102
+ # it is able to detect newly installed gems.
103
+ Gem.clear_paths
100
104
  app = load_rack_app
101
105
  end
102
106
 
@@ -169,6 +169,10 @@ class ApplicationSpawner < AbstractServer
169
169
  if @lower_privilege
170
170
  lower_privilege('config/environment.rb', @lowest_user)
171
171
  end
172
+ # Make sure RubyGems uses any new environment variable values
173
+ # that have been set now (e.g. $HOME, $GEM_HOME, etc) and that
174
+ # it is able to detect newly installed gems.
175
+ Gem.clear_paths
172
176
 
173
177
  require File.expand_path('config/environment')
174
178
  require 'dispatcher'
@@ -346,9 +350,12 @@ private
346
350
  end
347
351
 
348
352
  def handle_spawn_application
353
+ a, b = UNIXSocket.pair
349
354
  safe_fork('application', true) do
350
355
  begin
351
- start_request_handler(client, true)
356
+ a.close
357
+ client.close
358
+ start_request_handler(MessageChannel.new(b), true)
352
359
  rescue SignalException => e
353
360
  if e.message != AbstractRequestHandler::HARD_TERMINATION_SIGNAL &&
354
361
  e.message != AbstractRequestHandler::SOFT_TERMINATION_SIGNAL
@@ -356,6 +363,17 @@ private
356
363
  end
357
364
  end
358
365
  end
366
+
367
+ b.close
368
+ worker_channel = MessageChannel.new(a)
369
+ info = worker_channel.read
370
+ owner_pipe = worker_channel.recv_io
371
+ client.write(*info)
372
+ client.send_io(owner_pipe)
373
+ ensure
374
+ a.close if a
375
+ b.close if b && !b.closed?
376
+ owner_pipe.close if owner_pipe
359
377
  end
360
378
 
361
379
  # Initialize the request handler and enter its main loop.
@@ -538,8 +538,8 @@ class IO
538
538
  # This only works if this IO channel is a Unix socket.
539
539
  #
540
540
  # Raises SystemCallError if something went wrong.
541
- def recv_io
542
- return IO.new(PhusionPassenger::NativeSupport.recv_fd(self.fileno))
541
+ def recv_io(klass = IO)
542
+ return klass.for_fd(PhusionPassenger::NativeSupport.recv_fd(self.fileno))
543
543
  end
544
544
  end
545
545
 
@@ -590,7 +590,7 @@ end
590
590
  if RUBY_PLATFORM =~ /freebsd/ || RUBY_PLATFORM =~ /openbsd/ || (RUBY_PLATFORM =~ /darwin/ && RUBY_PLATFORM !~ /universal/)
591
591
  require 'socket'
592
592
  UNIXSocket.class_eval do
593
- def recv_io
593
+ def recv_io(klass = IO)
594
594
  super
595
595
  end
596
596
 
@@ -41,6 +41,11 @@ module Utils
41
41
  @rewindable_io.rewind
42
42
  end
43
43
 
44
+ def size
45
+ make_rewindable unless @rewindable_io
46
+ @rewindable_io.size
47
+ end
48
+
44
49
  # Closes this RewindableInput object without closing the originally
45
50
  # wrapped IO oject. Cleans up any temporary resources that this RewindableInput
46
51
  # has created.
@@ -1,6 +1,8 @@
1
1
  #include "tut.h"
2
2
  #include "MessageChannel.h"
3
3
 
4
+ #include <boost/bind.hpp>
5
+ #include <boost/thread.hpp>
4
6
  #include <cstring>
5
7
  #include <cstdio>
6
8
 
@@ -144,8 +146,14 @@ namespace tut {
144
146
  MessageChannel channel2(s[1]);
145
147
 
146
148
  pipe(my_pipe);
147
- channel1.writeFileDescriptor(my_pipe[1]);
149
+ boost::thread thr(boost::bind(
150
+ &MessageChannel::writeFileDescriptor,
151
+ &channel1,
152
+ my_pipe[1],
153
+ true
154
+ ));
148
155
  fd = channel2.readFileDescriptor();
156
+ thr.join();
149
157
 
150
158
  char buf[5];
151
159
  write(fd, "hello", 5);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- $LOAD_PATH << "#{File.dirname(__FILE__)}/../../lib"
2
+ $LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../../lib")
3
3
  require 'phusion_passenger/message_channel'
4
4
 
5
5
  include PhusionPassenger
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- $LOAD_PATH << "#{File.dirname(__FILE__)}/../../lib"
2
+ $LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../../lib")
3
3
  require 'phusion_passenger/message_channel'
4
4
 
5
5
  include PhusionPassenger
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- $LOAD_PATH << "#{File.dirname(__FILE__)}/../../lib"
3
- $LOAD_PATH << "#{File.dirname(__FILE__)}/../../ext"
2
+ $LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../../lib")
3
+ $LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../../ext")
4
4
  require 'phusion_passenger/message_channel'
5
5
  require 'phusion_passenger/utils'
6
6
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: passenger-jmazzi
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.9
4
+ version: 2.2.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phusion - http://www.phusion.nl/
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-01-11 00:00:00 -05:00
13
+ date: 2010-03-01 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency