passenger-jmazzi 2.2.9 → 2.2.10

Sign up to get free protection for your applications and to get access to all the features.
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