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 +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
|