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 +10 -0
- data/ext/common/MessageChannel.h +48 -4
- data/ext/common/Version.h +1 -1
- data/ext/nginx/HttpStatusExtractor.h +1 -0
- data/ext/nginx/ScgiRequestParser.h +1 -0
- data/ext/phusion_passenger/native_support.c +5 -1
- data/lib/phusion_passenger/constants.rb +1 -1
- data/lib/phusion_passenger/message_channel.rb +45 -3
- data/lib/phusion_passenger/rack/application_spawner.rb +4 -0
- data/lib/phusion_passenger/railz/application_spawner.rb +19 -1
- data/lib/phusion_passenger/utils.rb +3 -3
- data/lib/phusion_passenger/utils/rewindable_input.rb +5 -0
- data/test/MessageChannelTest.cpp +9 -1
- data/test/stub/message_channel.rb +1 -1
- data/test/stub/message_channel_2.rb +1 -1
- data/test/stub/message_channel_3.rb +2 -2
- metadata +2 -2
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
|
|
data/ext/common/MessageChannel.h
CHANGED
@@ -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
|
-
|
579
|
+
int fd = control_data.fd;
|
548
580
|
#else
|
549
|
-
|
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
|
/**
|
data/ext/common/Version.h
CHANGED
@@ -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
|
-
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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.
|
data/test/MessageChannelTest.cpp
CHANGED
@@ -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
|
-
|
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,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
$LOAD_PATH
|
3
|
-
$LOAD_PATH
|
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.
|
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
|
13
|
+
date: 2010-03-01 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|