passenger 4.0.21 → 4.0.23
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.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/NEWS +15 -0
- data/Rakefile +4 -2
- data/bin/passenger-install-apache2-module +10 -0
- data/build/debian.rb +9 -3
- data/build/test_basics.rb +2 -1
- data/debian.template/rules.template +7 -0
- data/doc/Users guide Apache.idmap.txt +65 -59
- data/doc/Users guide Apache.txt +169 -164
- data/doc/Users guide Standalone.idmap.txt +20 -14
- data/doc/Users guide Standalone.txt +38 -17
- data/doc/Users guide.txt +6 -6
- data/doc/users_guide_snippets/deployment_basics.txt +37 -0
- data/doc/users_guide_snippets/installation.txt +45 -26
- data/doc/users_guide_snippets/tips.txt +2 -2
- data/ext/boost/atomic/atomic.hpp +1 -1
- data/ext/common/ApplicationPool2/AppTypes.h +1 -1
- data/ext/common/ApplicationPool2/Spawner.h +17 -0
- data/ext/common/Constants.h +1 -1
- data/ext/common/Utils/Dechunker.h +12 -2
- data/ext/common/Utils/ProcessMetricsCollector.h +4 -2
- data/ext/common/Utils/VariantMap.h +21 -2
- data/ext/common/agents/HelperAgent/RequestHandler.cpp +8 -0
- data/ext/common/agents/HelperAgent/RequestHandler.h +13 -2
- data/ext/common/agents/Watchdog/Main.cpp +91 -2
- data/ext/ruby/extconf.rb +9 -0
- data/helper-scripts/meteor-loader.rb +10 -1
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/console_text_template.rb +4 -2
- data/lib/phusion_passenger/platform_info.rb +1 -1
- data/lib/phusion_passenger/platform_info/apache_detector.rb +17 -22
- data/test/cxx/DechunkerTest.cpp +34 -0
- data/test/cxx/ProcessMetricsCollectorTest.cpp +5 -3
- data/test/cxx/RequestHandlerTest.cpp +27 -0
- data/test/stub/wsgi/passenger_wsgi.py +16 -0
- metadata +3 -2
- metadata.gz.asc +7 -7
@@ -93,6 +93,7 @@ struct ProcessMetrics {
|
|
93
93
|
/** OS X Snow Leopard does not report the VM size correctly, so don't use this. */
|
94
94
|
size_t vmsize;
|
95
95
|
pid_t processGroupId;
|
96
|
+
uid_t uid;
|
96
97
|
string command;
|
97
98
|
|
98
99
|
ProcessMetrics() {
|
@@ -381,6 +382,7 @@ private:
|
|
381
382
|
metrics.rss = (size_t) readNextWordAsLongLong(&start);
|
382
383
|
metrics.vmsize = (size_t) readNextWordAsLongLong(&start);
|
383
384
|
metrics.processGroupId = (pid_t) readNextWordAsLongLong(&start);
|
385
|
+
metrics.uid = (uid_t) readNextWordAsLongLong(&start);
|
384
386
|
metrics.command = readRestOfLine(start);
|
385
387
|
|
386
388
|
bool pidAllowed;
|
@@ -452,9 +454,9 @@ public:
|
|
452
454
|
const char *command[] = {
|
453
455
|
"ps", "-o",
|
454
456
|
#if defined(sun) || defined(__sun)
|
455
|
-
"pid,ppid,pcpu,rss,vsz,pgid,args",
|
457
|
+
"pid,ppid,pcpu,rss,vsz,pgid,uid,args",
|
456
458
|
#else
|
457
|
-
"pid,ppid,%cpu,rss,vsize,pgid,command",
|
459
|
+
"pid,ppid,%cpu,rss,vsize,pgid,uid,command",
|
458
460
|
#endif
|
459
461
|
#ifdef PS_SUPPORTS_MULTIPLE_PIDS
|
460
462
|
pidsArg.c_str(),
|
@@ -110,7 +110,10 @@ public:
|
|
110
110
|
return key;
|
111
111
|
}
|
112
112
|
};
|
113
|
-
|
113
|
+
|
114
|
+
typedef map<string, string>::iterator Iterator;
|
115
|
+
typedef map<string, string>::const_iterator ConstIterator;
|
116
|
+
|
114
117
|
/**
|
115
118
|
* Populates a VariantMap from the data in <em>argv</em>, which
|
116
119
|
* consists of <em>argc</em> elements.
|
@@ -413,7 +416,23 @@ public:
|
|
413
416
|
}
|
414
417
|
writeArrayMessage(fd, args);
|
415
418
|
}
|
416
|
-
|
419
|
+
|
420
|
+
Iterator begin() {
|
421
|
+
return store.begin();
|
422
|
+
}
|
423
|
+
|
424
|
+
ConstIterator begin() const {
|
425
|
+
return store.begin();
|
426
|
+
}
|
427
|
+
|
428
|
+
Iterator end() {
|
429
|
+
return store.end();
|
430
|
+
}
|
431
|
+
|
432
|
+
ConstIterator end() const {
|
433
|
+
return store.end();
|
434
|
+
}
|
435
|
+
|
417
436
|
string inspect() const {
|
418
437
|
map<string, string>::const_iterator it;
|
419
438
|
map<string, string>::const_iterator end = store.end();
|
@@ -161,6 +161,14 @@ Client::onAppInputChunk(const char *data, size_t size, void *userData) {
|
|
161
161
|
client->requestHandler->onAppInputChunk(client->shared_from_this(), StaticString(data, size));
|
162
162
|
}
|
163
163
|
|
164
|
+
void
|
165
|
+
Client::onAppInputChunkEnd(void *userData) {
|
166
|
+
Client *client = (Client *) userData;
|
167
|
+
assert(client != NULL);
|
168
|
+
assert(client->requestHandler != NULL);
|
169
|
+
client->requestHandler->onAppInputChunkEnd(client->shared_from_this());
|
170
|
+
}
|
171
|
+
|
164
172
|
void
|
165
173
|
Client::onAppInputError(const EventedBufferedInputPtr &source, const char *message, int errnoCode) {
|
166
174
|
Client *client = (Client *) source->userData;
|
@@ -161,6 +161,7 @@ private:
|
|
161
161
|
|
162
162
|
static size_t onAppInputData(const EventedBufferedInputPtr &source, const StaticString &data);
|
163
163
|
static void onAppInputChunk(const char *data, size_t size, void *userData);
|
164
|
+
static void onAppInputChunkEnd(void *userData);
|
164
165
|
static void onAppInputError(const EventedBufferedInputPtr &source, const char *message, int errnoCode);
|
165
166
|
|
166
167
|
void onAppOutputWritable(ev::io &io, int revents);
|
@@ -326,6 +327,7 @@ public:
|
|
326
327
|
|
327
328
|
|
328
329
|
responseDechunker.onData = onAppInputChunk;
|
330
|
+
responseDechunker.onEnd = onAppInputChunkEnd;
|
329
331
|
responseDechunker.userData = this;
|
330
332
|
|
331
333
|
|
@@ -466,6 +468,8 @@ public:
|
|
466
468
|
}
|
467
469
|
|
468
470
|
bool shouldHalfCloseWrite() const {
|
471
|
+
// Many broken HTTP servers consider a half close to be a full close, so don't
|
472
|
+
// half close HTTP sessions.
|
469
473
|
return session->getProtocol() == "session";
|
470
474
|
}
|
471
475
|
|
@@ -1130,9 +1134,16 @@ private:
|
|
1130
1134
|
writeToClientOutputPipe(client, data);
|
1131
1135
|
}
|
1132
1136
|
|
1137
|
+
void onAppInputChunkEnd(const ClientPtr &client) {
|
1138
|
+
RH_LOG_EVENT(client, "onAppInputChunkEnd");
|
1139
|
+
onAppInputEof(client);
|
1140
|
+
}
|
1141
|
+
|
1133
1142
|
void onAppInputEof(const ClientPtr &client) {
|
1134
1143
|
RH_LOG_EVENT(client, "onAppInputEof");
|
1135
|
-
|
1144
|
+
// Check for session == NULL in order to avoid executing the code twice on
|
1145
|
+
// responses with chunked encoding.
|
1146
|
+
if (!client->connected() || client->session == NULL) {
|
1136
1147
|
return;
|
1137
1148
|
}
|
1138
1149
|
|
@@ -2200,7 +2211,7 @@ private:
|
|
2200
2211
|
|
2201
2212
|
/******* State: FORWARDING_BODY_TO_APP *******/
|
2202
2213
|
|
2203
|
-
void state_forwardingBodyToApp_verifyInvariants(const ClientPtr &client) {
|
2214
|
+
void state_forwardingBodyToApp_verifyInvariants(const ClientPtr &client) const {
|
2204
2215
|
assert(client->state == Client::FORWARDING_BODY_TO_APP);
|
2205
2216
|
}
|
2206
2217
|
|
@@ -30,6 +30,8 @@
|
|
30
30
|
#include <boost/foreach.hpp>
|
31
31
|
#include <boost/enable_shared_from_this.hpp>
|
32
32
|
#include <string>
|
33
|
+
#include <utility>
|
34
|
+
#include <vector>
|
33
35
|
|
34
36
|
#include <sys/select.h>
|
35
37
|
#include <sys/types.h>
|
@@ -425,6 +427,85 @@ inferDefaultGroup(const string &defaultUser) {
|
|
425
427
|
return getGroupName(userEntry->pw_gid);
|
426
428
|
}
|
427
429
|
|
430
|
+
static vector< pair<string, string> >
|
431
|
+
agentsOptionsToEnvVars(const VariantMap &agentsOptions) {
|
432
|
+
vector< pair<string, string> > result;
|
433
|
+
VariantMap::ConstIterator it, end = agentsOptions.end();
|
434
|
+
|
435
|
+
result.reserve(agentsOptions.size());
|
436
|
+
for (it = agentsOptions.begin(); it != end; it++) {
|
437
|
+
result.push_back(make_pair("passenger_" + it->first, it->second));
|
438
|
+
}
|
439
|
+
|
440
|
+
return result;
|
441
|
+
}
|
442
|
+
|
443
|
+
static void
|
444
|
+
setEnvVarsFromVector(const vector< pair<string, string> > &envvars) {
|
445
|
+
vector< pair<string, string> >::const_iterator it;
|
446
|
+
|
447
|
+
for (it = envvars.begin(); it != envvars.end(); it++) {
|
448
|
+
setenv(it->first.c_str(), it->second.c_str(), 1);
|
449
|
+
}
|
450
|
+
}
|
451
|
+
|
452
|
+
static bool
|
453
|
+
runHookScript(const char *name) {
|
454
|
+
TRACE_POINT();
|
455
|
+
string value = agentsOptions.get(string("hook_") + name, false);
|
456
|
+
if (value.empty()) {
|
457
|
+
return true;
|
458
|
+
}
|
459
|
+
|
460
|
+
vector< pair<string, string> > envvars = agentsOptionsToEnvVars(agentsOptions);
|
461
|
+
pid_t pid;
|
462
|
+
int e, status;
|
463
|
+
|
464
|
+
P_INFO("Running " << name << " hook script: " << value);
|
465
|
+
|
466
|
+
pid = fork();
|
467
|
+
if (pid == 0) {
|
468
|
+
resetSignalHandlersAndMask();
|
469
|
+
disableMallocDebugging();
|
470
|
+
closeAllFileDescriptors(2);
|
471
|
+
setEnvVarsFromVector(envvars);
|
472
|
+
|
473
|
+
execlp(value.c_str(), value.c_str(), (const char * const) 0);
|
474
|
+
e = errno;
|
475
|
+
fprintf(stderr, "*** ERROR: Cannot execute %s hook script %s: %s (errno=%d)\n",
|
476
|
+
name, value.c_str(), strerror(e), e);
|
477
|
+
fflush(stderr);
|
478
|
+
_exit(1);
|
479
|
+
return true; // Never reached.
|
480
|
+
|
481
|
+
} else if (pid == -1) {
|
482
|
+
e = errno;
|
483
|
+
P_ERROR("Cannot fork a process for hook script " << value <<
|
484
|
+
": " << strerror(e) << " (errno=" << e << ")");
|
485
|
+
return false;
|
486
|
+
|
487
|
+
} else if (waitpid(pid, &status, 0) == -1) {
|
488
|
+
e = errno;
|
489
|
+
P_ERROR("Unable to wait for hook script " << value <<
|
490
|
+
" (PID " << pid << "): " << strerror(e) << " (errno=" <<
|
491
|
+
e << ")");
|
492
|
+
return false;
|
493
|
+
|
494
|
+
} else {
|
495
|
+
P_INFO("Hook script " << value << " (PID " << pid <<
|
496
|
+
") exited with status " << WEXITSTATUS(status));
|
497
|
+
return WEXITSTATUS(status) == 0;
|
498
|
+
}
|
499
|
+
}
|
500
|
+
|
501
|
+
static void
|
502
|
+
runHookScriptAndThrowOnError(const char *name) {
|
503
|
+
TRACE_POINT();
|
504
|
+
if (!runHookScript(name)) {
|
505
|
+
throw RuntimeException(string("Hook script ") + name + " failed");
|
506
|
+
}
|
507
|
+
}
|
508
|
+
|
428
509
|
static void
|
429
510
|
initializeBareEssentials(int argc, char *argv[]) {
|
430
511
|
/*
|
@@ -555,6 +636,7 @@ initializeWorkingObjects(WorkingObjectsPtr &wo, ServerInstanceDirToucherPtr &ser
|
|
555
636
|
defaultGroup, webServerWorkerUid, webServerWorkerGid);
|
556
637
|
agentsOptions.set("server_instance_dir", wo->serverInstanceDir->getPath());
|
557
638
|
agentsOptions.setInt("generation_number", wo->generation->getNumber());
|
639
|
+
agentsOptions.set("generation_path", wo->generation->getPath());
|
558
640
|
|
559
641
|
UPDATE_TRACE_POINT();
|
560
642
|
serverInstanceDirToucher = boost::make_shared<ServerInstanceDirToucher>(wo);
|
@@ -660,6 +742,8 @@ main(int argc, char *argv[]) {
|
|
660
742
|
maybeSetsid();
|
661
743
|
initializeWorkingObjects(wo, serverInstanceDirToucher);
|
662
744
|
initializeAgentWatchers(wo, watchers);
|
745
|
+
UPDATE_TRACE_POINT();
|
746
|
+
runHookScriptAndThrowOnError("before_watchdog_initialization");
|
663
747
|
} catch (const std::exception &e) {
|
664
748
|
writeArrayMessage(FEEDBACK_FD,
|
665
749
|
"Watchdog startup error",
|
@@ -675,6 +759,8 @@ main(int argc, char *argv[]) {
|
|
675
759
|
beginWatchingAgents(wo, watchers);
|
676
760
|
reportAgentsInformation(wo, watchers);
|
677
761
|
P_INFO("All Phusion Passenger agents started!");
|
762
|
+
UPDATE_TRACE_POINT();
|
763
|
+
runHookScriptAndThrowOnError("after_watchdog_initialization");
|
678
764
|
|
679
765
|
UPDATE_TRACE_POINT();
|
680
766
|
this_thread::disable_interruption di;
|
@@ -690,16 +776,19 @@ main(int argc, char *argv[]) {
|
|
690
776
|
P_DEBUG("Web server did not exit gracefully, forcing shutdown of all agents...");
|
691
777
|
}
|
692
778
|
UPDATE_TRACE_POINT();
|
779
|
+
runHookScriptAndThrowOnError("after_watchdog_shutdown");
|
780
|
+
UPDATE_TRACE_POINT();
|
693
781
|
AgentWatcher::stopWatching(watchers);
|
694
782
|
if (exitGracefully) {
|
695
783
|
UPDATE_TRACE_POINT();
|
696
784
|
cleanupAgentsInBackground(wo, watchers, argv);
|
697
|
-
return 0;
|
698
785
|
} else {
|
699
786
|
UPDATE_TRACE_POINT();
|
700
787
|
forceAllAgentsShutdown(watchers);
|
701
|
-
return 1;
|
702
788
|
}
|
789
|
+
UPDATE_TRACE_POINT();
|
790
|
+
runHookScriptAndThrowOnError("after_watchdog_shutdown");
|
791
|
+
return exitGracefully ? 0 : 1;
|
703
792
|
} catch (const tracable_exception &e) {
|
704
793
|
P_ERROR(e.what() << "\n" << e.backtrace());
|
705
794
|
return 1;
|
data/ext/ruby/extconf.rb
CHANGED
@@ -40,4 +40,13 @@ have_func('rb_thread_io_blocking_region')
|
|
40
40
|
|
41
41
|
with_cflags($CFLAGS) do
|
42
42
|
create_makefile('passenger_native_support')
|
43
|
+
if RUBY_PLATFORM =~ /solaris/
|
44
|
+
# Fix syntax error in Solaris /usr/ccs/bin/make.
|
45
|
+
# https://code.google.com/p/phusion-passenger/issues/detail?id=999
|
46
|
+
makefile = File.read("Makefile")
|
47
|
+
makefile.sub!(/^ECHO = .*/, "ECHO = echo")
|
48
|
+
File.open("Makefile", "w") do |f|
|
49
|
+
f.write(makefile)
|
50
|
+
end
|
51
|
+
end
|
43
52
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# encoding: binary
|
3
3
|
# Phusion Passenger - https://www.phusionpassenger.com/
|
4
|
-
# Copyright (c) 2013 Phusion
|
4
|
+
# Copyright (c) 2010-2013 Phusion
|
5
5
|
#
|
6
6
|
# "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
7
7
|
#
|
@@ -93,6 +93,13 @@ module App
|
|
93
93
|
|
94
94
|
production = options["environment"] == "production" ? "production" : ""
|
95
95
|
pid = fork do
|
96
|
+
# Meteor is quite !@#$% here: if we kill its start script
|
97
|
+
# with *any* signal, it'll leave a ton of garbage processes
|
98
|
+
# around. Apparently it expects the user to press Ctrl-C in a
|
99
|
+
# terminal which happens to send a signal to all processes
|
100
|
+
# in the session. We emulate that behavior here by giving
|
101
|
+
# Meteor its own process group, and sending signals to the
|
102
|
+
# entire process group.
|
96
103
|
Process.setpgrp
|
97
104
|
exec("meteor run -p #{port} #{production}")
|
98
105
|
end
|
@@ -113,6 +120,7 @@ module App
|
|
113
120
|
end
|
114
121
|
puts "!> Ready"
|
115
122
|
puts "!> socket: main;tcp://127.0.0.1:#{port};http_session;0"
|
123
|
+
puts "!> pid: #{pid}"
|
116
124
|
puts "!> "
|
117
125
|
begin
|
118
126
|
STDIN.readline
|
@@ -121,6 +129,7 @@ module App
|
|
121
129
|
ensure
|
122
130
|
Process.kill('INT', -pid) rescue nil
|
123
131
|
Process.waitpid(pid) rescue nil
|
132
|
+
Process.kill('INT', -pid) rescue nil
|
124
133
|
end
|
125
134
|
|
126
135
|
end # module App
|
data/lib/phusion_passenger.rb
CHANGED
@@ -30,7 +30,7 @@ module PhusionPassenger
|
|
30
30
|
|
31
31
|
PACKAGE_NAME = 'passenger'
|
32
32
|
# Run 'rake ext/common/Constants.h' after changing this number.
|
33
|
-
VERSION_STRING = '4.0.
|
33
|
+
VERSION_STRING = '4.0.23'
|
34
34
|
|
35
35
|
PREFERRED_NGINX_VERSION = '1.4.3'
|
36
36
|
NGINX_SHA256_CHECKSUM = 'ae123885c923a6c3f5bab0a8b7296ef21c4fdf6087834667ebbc16338177de84'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Phusion Passenger - https://www.phusionpassenger.com/
|
2
|
-
# Copyright (c) 2010 Phusion
|
2
|
+
# Copyright (c) 2010-2013 Phusion
|
3
3
|
#
|
4
4
|
# "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
5
5
|
#
|
@@ -30,12 +30,14 @@ class ConsoleTextTemplate
|
|
30
30
|
def initialize(input, options = {})
|
31
31
|
@buffer = ''
|
32
32
|
if input[:file]
|
33
|
-
|
33
|
+
filename = "#{PhusionPassenger.resources_dir}/templates/#{input[:file]}.txt.erb"
|
34
|
+
data = File.read(filename)
|
34
35
|
else
|
35
36
|
data = input[:text]
|
36
37
|
end
|
37
38
|
@template = ERB.new(Utils::AnsiColors.ansi_colorize(data),
|
38
39
|
nil, '-', '@buffer')
|
40
|
+
@template.filename = filename if filename
|
39
41
|
options.each_pair do |name, value|
|
40
42
|
self[name] = value
|
41
43
|
end
|
@@ -360,7 +360,7 @@ public
|
|
360
360
|
def self.find_all_commands(name)
|
361
361
|
search_dirs = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
|
362
362
|
search_dirs.concat(%w(/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin))
|
363
|
-
["/opt/*/bin", "/usr/local/*/bin"].each do |glob|
|
363
|
+
["/opt/*/bin", "/opt/*/sbin", "/usr/local/*/bin", "/usr/local/*/sbin"].each do |glob|
|
364
364
|
search_dirs.concat(Dir[glob])
|
365
365
|
end
|
366
366
|
search_dirs.delete("")
|
@@ -22,10 +22,12 @@
|
|
22
22
|
# THE SOFTWARE.
|
23
23
|
|
24
24
|
require 'phusion_passenger'
|
25
|
+
require 'phusion_passenger/constants'
|
25
26
|
require 'phusion_passenger/platform_info'
|
26
27
|
require 'phusion_passenger/platform_info/ruby'
|
27
28
|
require 'phusion_passenger/platform_info/apache'
|
28
|
-
require 'phusion_passenger/utils/ansi_colors'
|
29
|
+
require 'phusion_passenger/utils/ansi_colors'
|
30
|
+
require 'pathname'
|
29
31
|
|
30
32
|
module PhusionPassenger
|
31
33
|
module PlatformInfo
|
@@ -194,6 +196,8 @@ class ApacheDetector
|
|
194
196
|
end
|
195
197
|
|
196
198
|
def result_for(apxs2)
|
199
|
+
# All the results use realpaths, so the input must too.
|
200
|
+
apxs2 = Pathname.new(apxs2).realpath
|
197
201
|
return @results.find { |r| r.apxs2 == apxs2 }
|
198
202
|
end
|
199
203
|
|
@@ -206,30 +210,21 @@ private
|
|
206
210
|
end
|
207
211
|
end
|
208
212
|
|
209
|
-
# On Ubuntu, /usr/bin/apxs2 is a symlink to /usr/bin/apxs.
|
210
|
-
#
|
213
|
+
# On Ubuntu, /usr/bin/apxs2 is a symlink to /usr/bin/apxs.
|
214
|
+
# On recent Arch Linux releases, /bin, /sbin etc are symlinks to
|
215
|
+
# /usr/bin and /usr/sbin.
|
216
|
+
# We're only supposed to detect one Apache in that case so we need to
|
217
|
+
# resolve symlinks.
|
211
218
|
def remove_symlink_duplications(filenames)
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
filenames.each do |filename|
|
216
|
-
if File.symlink?(filename)
|
217
|
-
symlink_files << filename
|
218
|
-
else
|
219
|
-
result << filename
|
220
|
-
end
|
219
|
+
old_size = filenames.size
|
220
|
+
filenames = filenames.map do |filename|
|
221
|
+
Pathname.new(filename).realpath
|
221
222
|
end
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
if result.include?(full_filename)
|
226
|
-
log "#{filename} is a symlink to #{full_filename}. Ignoring it."
|
227
|
-
else
|
228
|
-
result << full_filename
|
229
|
-
end
|
223
|
+
filenames.uniq!
|
224
|
+
if old_size != filenames.size
|
225
|
+
log "#{old_size - filenames.size} symlink duplicate(s) detected; ignoring them."
|
230
226
|
end
|
231
|
-
|
232
|
-
return result
|
227
|
+
return filenames
|
233
228
|
end
|
234
229
|
|
235
230
|
def add_result
|
data/test/cxx/DechunkerTest.cpp
CHANGED
@@ -12,10 +12,13 @@ namespace tut {
|
|
12
12
|
Dechunker dechunker;
|
13
13
|
string input;
|
14
14
|
vector<string> chunks;
|
15
|
+
bool ended;
|
15
16
|
|
16
17
|
DechunkerTest() {
|
17
18
|
dechunker.onData = onData;
|
19
|
+
dechunker.onEnd = onEnd;
|
18
20
|
dechunker.userData = this;
|
21
|
+
ended = false;
|
19
22
|
}
|
20
23
|
|
21
24
|
void addChunk(const string &data) {
|
@@ -29,6 +32,11 @@ namespace tut {
|
|
29
32
|
DechunkerTest *self = (DechunkerTest *) userData;
|
30
33
|
self->chunks.push_back(string(data, len));
|
31
34
|
}
|
35
|
+
|
36
|
+
static void onEnd(void *userData) {
|
37
|
+
DechunkerTest *self = (DechunkerTest *) userData;
|
38
|
+
self->ended = true;
|
39
|
+
}
|
32
40
|
};
|
33
41
|
|
34
42
|
DEFINE_TEST_GROUP(DechunkerTest);
|
@@ -37,6 +45,7 @@ namespace tut {
|
|
37
45
|
// Test initial state.
|
38
46
|
ensure(dechunker.acceptingInput());
|
39
47
|
ensure(!dechunker.hasError());
|
48
|
+
ensure(!ended);
|
40
49
|
ensure_equals(dechunker.getErrorMessage(), (const char *) NULL);
|
41
50
|
}
|
42
51
|
|
@@ -51,6 +60,7 @@ namespace tut {
|
|
51
60
|
ensure_equals(chunks.size(), 2u);
|
52
61
|
ensure_equals(chunks[0], "hello");
|
53
62
|
ensure_equals(chunks[1], "world");
|
63
|
+
ensure(ended);
|
54
64
|
}
|
55
65
|
|
56
66
|
TEST_METHOD(3) {
|
@@ -76,6 +86,7 @@ namespace tut {
|
|
76
86
|
ensure_equals(chunks[2], "l");
|
77
87
|
ensure_equals(chunks[3], "l");
|
78
88
|
ensure_equals(chunks[4], "o");
|
89
|
+
ensure(ended);
|
79
90
|
}
|
80
91
|
|
81
92
|
TEST_METHOD(4) {
|
@@ -103,6 +114,7 @@ namespace tut {
|
|
103
114
|
ensure_equals(chunks[3], "w");
|
104
115
|
ensure_equals(chunks[4], "or");
|
105
116
|
ensure_equals(chunks[5], "ld");
|
117
|
+
ensure(ended);
|
106
118
|
}
|
107
119
|
|
108
120
|
TEST_METHOD(5) {
|
@@ -128,6 +140,7 @@ namespace tut {
|
|
128
140
|
ensure_equals(chunks[1], "lo");
|
129
141
|
ensure_equals(chunks[2], "wo");
|
130
142
|
ensure_equals(chunks[3], "rld");
|
143
|
+
ensure(ended);
|
131
144
|
}
|
132
145
|
|
133
146
|
TEST_METHOD(6) {
|
@@ -141,6 +154,7 @@ namespace tut {
|
|
141
154
|
ensure(!dechunker.hasError());
|
142
155
|
ensure_equals(chunks.size(), 1u);
|
143
156
|
ensure_equals(chunks[0], "xy");
|
157
|
+
ensure(ended);
|
144
158
|
}
|
145
159
|
|
146
160
|
TEST_METHOD(20) {
|
@@ -158,6 +172,7 @@ namespace tut {
|
|
158
172
|
ensure_equals(chunks.size(), 2u);
|
159
173
|
ensure_equals(chunks[0], "hello");
|
160
174
|
ensure_equals(chunks[1], "hello");
|
175
|
+
ensure(ended);
|
161
176
|
}
|
162
177
|
|
163
178
|
TEST_METHOD(21) {
|
@@ -166,6 +181,7 @@ namespace tut {
|
|
166
181
|
ensure_equals(dechunker.feed(input.data(), input.size()), 2u);
|
167
182
|
ensure(!dechunker.acceptingInput());
|
168
183
|
ensure(dechunker.hasError());
|
184
|
+
ensure(!ended);
|
169
185
|
}
|
170
186
|
|
171
187
|
TEST_METHOD(22) {
|
@@ -174,6 +190,7 @@ namespace tut {
|
|
174
190
|
ensure_equals(dechunker.feed(input.data(), input.size()), 3u);
|
175
191
|
ensure(!dechunker.acceptingInput());
|
176
192
|
ensure(dechunker.hasError());
|
193
|
+
ensure(!ended);
|
177
194
|
}
|
178
195
|
|
179
196
|
TEST_METHOD(23) {
|
@@ -182,6 +199,7 @@ namespace tut {
|
|
182
199
|
ensure_equals(dechunker.feed(input.data(), input.size()), 7u);
|
183
200
|
ensure(!dechunker.acceptingInput());
|
184
201
|
ensure(dechunker.hasError());
|
202
|
+
ensure(!ended);
|
185
203
|
}
|
186
204
|
|
187
205
|
TEST_METHOD(24) {
|
@@ -191,6 +209,7 @@ namespace tut {
|
|
191
209
|
ensure_equals(dechunker.feed(input.data(), input.size()), 5u);
|
192
210
|
ensure(!dechunker.acceptingInput());
|
193
211
|
ensure(dechunker.hasError());
|
212
|
+
ensure(!ended);
|
194
213
|
}
|
195
214
|
|
196
215
|
TEST_METHOD(25) {
|
@@ -202,6 +221,7 @@ namespace tut {
|
|
202
221
|
ensure_equals(dechunker.feed(input.data(), input.size()), 11u);
|
203
222
|
ensure(!dechunker.acceptingInput());
|
204
223
|
ensure(dechunker.hasError());
|
224
|
+
ensure(!ended);
|
205
225
|
}
|
206
226
|
|
207
227
|
TEST_METHOD(26) {
|
@@ -212,5 +232,19 @@ namespace tut {
|
|
212
232
|
dechunker.feed(input.data(), input.size());
|
213
233
|
ensure(!dechunker.acceptingInput());
|
214
234
|
ensure(dechunker.hasError());
|
235
|
+
ensure(!ended);
|
236
|
+
}
|
237
|
+
|
238
|
+
TEST_METHOD(27) {
|
239
|
+
// Test feeding a partial stream.
|
240
|
+
addChunk("hello");
|
241
|
+
addChunk("world");
|
242
|
+
ensure_equals(dechunker.feed(input.data(), input.size()), input.size());
|
243
|
+
ensure(dechunker.acceptingInput());
|
244
|
+
ensure(!dechunker.hasError());
|
245
|
+
ensure_equals(chunks.size(), 2u);
|
246
|
+
ensure_equals(chunks[0], "hello");
|
247
|
+
ensure_equals(chunks[1], "world");
|
248
|
+
ensure(!ended);
|
215
249
|
}
|
216
250
|
}
|