passenger 5.0.25 → 5.0.26
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 +4 -4
- data/CHANGELOG +20 -0
- data/CONTRIBUTORS +1 -0
- data/build/cxx_dependency_map.rb +7338 -7104
- data/build/cxx_tests.rb +3 -3
- data/build/misc.rb +1 -0
- data/dev/index_cxx_dependencies.rb +3 -2
- data/resources/templates/standalone/config.erb +1 -1
- data/resources/templates/standalone/http.erb +1 -0
- data/resources/templates/standalone/server.erb +1 -0
- data/src/agent/Core/ApplicationPool/AbstractSession.h +83 -0
- data/src/agent/Core/ApplicationPool/Common.h +6 -4
- data/src/agent/Core/ApplicationPool/Options.h +4 -1
- data/src/agent/Core/ApplicationPool/Pool.h +2 -2
- data/src/agent/Core/ApplicationPool/Pool/AnalyticsCollection.cpp +3 -6
- data/src/agent/Core/ApplicationPool/Pool/GeneralUtils.cpp +3 -3
- data/src/agent/Core/ApplicationPool/Session.h +15 -27
- data/src/agent/Core/ApplicationPool/TestSession.h +188 -0
- data/src/agent/Core/Controller.h +15 -6
- data/src/agent/Core/Controller/CheckoutSession.cpp +13 -5
- data/src/agent/Core/Controller/ForwardResponse.cpp +20 -2
- data/src/agent/Core/Controller/Hooks.cpp +15 -2
- data/src/agent/Core/Controller/InitRequest.cpp +5 -1
- data/src/agent/Core/Controller/InitializationAndShutdown.cpp +1 -0
- data/src/agent/Core/Controller/Request.h +11 -4
- data/src/agent/Core/Controller/SendRequest.cpp +34 -13
- data/src/agent/Core/Controller/StateInspectionAndConfiguration.cpp +2 -2
- data/src/agent/Core/CoreMain.cpp +27 -1
- data/src/agent/Core/OptionParser.h +11 -1
- data/src/agent/Core/SpawningKit/DirectSpawner.h +1 -0
- data/src/agent/Core/SpawningKit/SmartSpawner.h +1 -0
- data/src/agent/Core/SpawningKit/Spawner.h +21 -1
- data/src/agent/SpawnPreparer/SpawnPreparerMain.cpp +1 -1
- data/src/agent/UstRouter/OptionParser.h +7 -1
- data/src/agent/UstRouter/UstRouterMain.cpp +27 -1
- data/src/cxx_supportlib/Algorithms/MovingAverage.h +223 -0
- data/src/cxx_supportlib/Constants.h +2 -2
- data/src/cxx_supportlib/DataStructures/StringKeyTable.h +96 -40
- data/src/cxx_supportlib/ResourceLocator.h +33 -14
- data/src/cxx_supportlib/ServerKit/Channel.h +198 -69
- data/src/cxx_supportlib/ServerKit/Errors.h +6 -1
- data/src/cxx_supportlib/ServerKit/HttpRequest.h +20 -1
- data/src/cxx_supportlib/ServerKit/HttpServer.h +124 -32
- data/src/cxx_supportlib/ServerKit/Server.h +65 -1
- data/src/cxx_supportlib/Utils/IOUtils.cpp +12 -22
- data/src/cxx_supportlib/Utils/JsonUtils.h +87 -1
- data/src/cxx_supportlib/Utils/StrIntUtils.cpp +16 -1
- data/src/cxx_supportlib/Utils/StrIntUtils.h +31 -1
- data/src/cxx_supportlib/Utils/VariantMap.h +6 -1
- data/src/cxx_supportlib/WatchdogLauncher.h +17 -9
- data/src/cxx_supportlib/vendor-copy/libuv/AUTHORS +43 -0
- data/src/cxx_supportlib/vendor-copy/libuv/ChangeLog +350 -1
- data/src/cxx_supportlib/vendor-copy/libuv/Makefile.am +9 -1
- data/src/cxx_supportlib/vendor-copy/libuv/README.md +48 -0
- data/src/cxx_supportlib/vendor-copy/libuv/checksparse.sh +1 -0
- data/src/cxx_supportlib/vendor-copy/libuv/common.gypi +5 -5
- data/src/cxx_supportlib/vendor-copy/libuv/configure.ac +2 -1
- data/src/cxx_supportlib/vendor-copy/libuv/gyp_uv.py +0 -3
- data/src/cxx_supportlib/vendor-copy/libuv/include/uv-version.h +5 -1
- data/src/cxx_supportlib/vendor-copy/libuv/include/uv.h +30 -3
- data/src/cxx_supportlib/vendor-copy/libuv/src/fs-poll.c +3 -3
- data/src/cxx_supportlib/vendor-copy/libuv/src/inet.c +0 -4
- data/src/cxx_supportlib/vendor-copy/libuv/src/queue.h +17 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/threadpool.c +10 -10
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/aix.c +84 -166
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/android-ifaddrs.c +11 -11
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/async.c +7 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/atomic-ops.h +17 -0
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/core.c +140 -21
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/darwin.c +15 -11
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/dl.c +4 -7
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/freebsd.c +52 -37
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fs.c +181 -60
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fsevents.c +39 -34
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/getaddrinfo.c +4 -4
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/internal.h +3 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/kqueue.c +12 -4
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-core.c +38 -15
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-inotify.c +36 -8
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.c +4 -4
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.h +2 -2
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop-watcher.c +6 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop.c +28 -8
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/netbsd.c +18 -16
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/openbsd.c +18 -16
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pipe.c +3 -3
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/process.c +18 -6
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/proctitle.c +2 -2
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pthread-fixes.c +1 -0
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/signal.c +2 -0
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/stream.c +47 -30
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/sunos.c +13 -11
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tcp.c +43 -8
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/thread.c +21 -15
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tty.c +16 -2
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/udp.c +54 -14
- data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.c +104 -21
- data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.h +14 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/version.c +1 -5
- data/src/cxx_supportlib/vendor-copy/libuv/uv.gyp +22 -1
- data/src/nginx_module/CacheLocationConfig.c +52 -0
- data/src/nginx_module/CacheLocationConfig.c.erb +13 -1
- data/src/nginx_module/Configuration.c +1 -0
- data/src/nginx_module/Configuration.h +1 -0
- data/src/nginx_module/ConfigurationCommands.c +20 -0
- data/src/nginx_module/ConfigurationFields.h +4 -0
- data/src/nginx_module/CreateLocationConfig.c +8 -0
- data/src/nginx_module/MergeLocationConfig.c +12 -0
- data/src/nginx_module/config +31 -13
- data/src/nginx_module/ngx_http_passenger_module.c +4 -0
- data/src/ruby_supportlib/phusion_passenger.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/constants.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +11 -1
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +6 -1
- data/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb +32 -31
- data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +13 -2
- data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -0
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +6 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +6 -0
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +29 -19
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/context.rb +2 -2
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter.rb +2 -3
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/simple_json.rb +2 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/spec_helper.rb +2 -0
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/time_point.rb +3 -17
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/transaction.rb +7 -10
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/utils.rb +11 -9
- metadata +5 -2
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2012-
|
3
|
+
* Copyright (c) 2012-2016 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -52,6 +52,9 @@ enum Error {
|
|
52
52
|
ERROR_SECURE_HEADER_NOT_ALLOWED = -1017,
|
53
53
|
NORMAL_HEADER_NOT_ALLOWED_AFTER_SECURITY_PASSWORD = -1018,
|
54
54
|
|
55
|
+
// HttpServer special errors
|
56
|
+
EARLY_EOF_DETECTED = -1020,
|
57
|
+
|
55
58
|
// Error codes below -2000 are http_parser errors
|
56
59
|
HTTP_PARSER_ERRNO_BEGIN = -2000,
|
57
60
|
};
|
@@ -87,6 +90,8 @@ getErrorDesc(int errcode) {
|
|
87
90
|
return "A secure header was provided, but no security password was provided";
|
88
91
|
case NORMAL_HEADER_NOT_ALLOWED_AFTER_SECURITY_PASSWORD:
|
89
92
|
return "A normal header was encountered after the security password header";
|
93
|
+
case EARLY_EOF_DETECTED:
|
94
|
+
return "The client connection is closed before the request is done processing";
|
90
95
|
default:
|
91
96
|
if (errcode <= HTTP_PARSER_ERRNO_BEGIN) {
|
92
97
|
return http_errno_description((enum http_errno)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2014-
|
3
|
+
* Copyright (c) 2014-2016 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -102,6 +102,7 @@ public:
|
|
102
102
|
http_method method: 5;
|
103
103
|
bool wantKeepAlive: 1;
|
104
104
|
bool responseBegun: 1;
|
105
|
+
bool detectingNextRequestEarlyReadError: 1;
|
105
106
|
|
106
107
|
boost::atomic<int> refcount;
|
107
108
|
|
@@ -139,6 +140,9 @@ public:
|
|
139
140
|
} aux;
|
140
141
|
boost::uint64_t bodyAlreadyRead;
|
141
142
|
|
143
|
+
ev_tstamp lastDataReceiveTime;
|
144
|
+
ev_tstamp lastDataSendTime;
|
145
|
+
|
142
146
|
/**
|
143
147
|
* The start index of the '?' character in `path`. -1 when it doesn't exist.
|
144
148
|
*/
|
@@ -149,6 +153,21 @@ public:
|
|
149
153
|
*/
|
150
154
|
int bodyError;
|
151
155
|
|
156
|
+
/**
|
157
|
+
* When a request body read error, or a client socket EOF, has been detected
|
158
|
+
* after the current request body has already fully received, the error code is
|
159
|
+
* temporarily stored here so that it may be processed at the next request. The
|
160
|
+
* error is not passed to the bodyChannel immediately because it isn't an error
|
161
|
+
* part of the current request's body. But users of HttpServer can still query
|
162
|
+
* this field to see that an error is imminent, and may choose to abort early.
|
163
|
+
*
|
164
|
+
* The value is either the body read error code, or EARLY_EOF_DETECTED. The
|
165
|
+
* latter means that a client socket EOF has been detected.
|
166
|
+
*
|
167
|
+
* A value of 0 means that everthing is ok.
|
168
|
+
*/
|
169
|
+
int nextRequestEarlyReadError;
|
170
|
+
|
152
171
|
|
153
172
|
BaseHttpRequest()
|
154
173
|
: refcount(1),
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2014-
|
3
|
+
* Copyright (c) 2014-2016 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -32,6 +32,7 @@
|
|
32
32
|
#include <oxt/macros.hpp>
|
33
33
|
#include <algorithm>
|
34
34
|
#include <cstdio>
|
35
|
+
#include <cmath>
|
35
36
|
#include <cassert>
|
36
37
|
#include <pthread.h>
|
37
38
|
#include <Logging.h>
|
@@ -41,10 +42,12 @@
|
|
41
42
|
#include <ServerKit/HttpRequestRef.h>
|
42
43
|
#include <ServerKit/HttpHeaderParser.h>
|
43
44
|
#include <ServerKit/HttpChunkedBodyParser.h>
|
45
|
+
#include <Algorithms/MovingAverage.h>
|
44
46
|
#include <Utils/SystemTime.h>
|
45
47
|
#include <Utils/StrIntUtils.h>
|
46
48
|
#include <Utils/HttpConstants.h>
|
47
49
|
#include <Utils/Hasher.h>
|
50
|
+
#include <Utils/SystemTime.h>
|
48
51
|
|
49
52
|
namespace Passenger {
|
50
53
|
namespace ServerKit {
|
@@ -65,7 +68,8 @@ public:
|
|
65
68
|
|
66
69
|
FreeRequestList freeRequests;
|
67
70
|
unsigned int freeRequestCount, requestFreelistLimit;
|
68
|
-
unsigned long totalRequestsBegun;
|
71
|
+
unsigned long totalRequestsBegun, lastTotalRequestsBegun;
|
72
|
+
double requestBeginSpeed1m, requestBeginSpeed1h;
|
69
73
|
|
70
74
|
private:
|
71
75
|
/***** Types and nested classes *****/
|
@@ -209,6 +213,7 @@ private:
|
|
209
213
|
assert(c->currentRequest != NULL);
|
210
214
|
Request *req = c->currentRequest;
|
211
215
|
bool keepAlive = canKeepAlive(req);
|
216
|
+
int nextRequestEarlyReadError = req->nextRequestEarlyReadError;
|
212
217
|
|
213
218
|
P_ASSERT_EQ(req->httpState, Request::WAITING_FOR_REFERENCES);
|
214
219
|
assert(req->pool != NULL);
|
@@ -221,6 +226,9 @@ private:
|
|
221
226
|
if (keepAlive) {
|
222
227
|
SKC_TRACE(c, 3, "Keeping alive connection, handling next request");
|
223
228
|
handleNextRequest(c);
|
229
|
+
if (nextRequestEarlyReadError != 0) {
|
230
|
+
onClientDataReceived(c, MemoryKit::mbuf(), nextRequestEarlyReadError);
|
231
|
+
}
|
224
232
|
} else {
|
225
233
|
SKC_TRACE(c, 3, "Not keeping alive connection, disconnecting client");
|
226
234
|
this->disconnect(client);
|
@@ -278,7 +286,7 @@ private:
|
|
278
286
|
|
279
287
|
switch (req->httpState) {
|
280
288
|
case Request::COMPLETE:
|
281
|
-
|
289
|
+
req->detectingNextRequestEarlyReadError = true;
|
282
290
|
onRequestBegin(client, req);
|
283
291
|
return Channel::Result(ret, false);
|
284
292
|
case Request::PARSING_BODY:
|
@@ -338,39 +346,34 @@ private:
|
|
338
346
|
|
339
347
|
boost::uint64_t maxRemaining, remaining;
|
340
348
|
|
349
|
+
assert(req->aux.bodyInfo.contentLength > 0);
|
341
350
|
maxRemaining = req->aux.bodyInfo.contentLength - req->bodyAlreadyRead;
|
351
|
+
assert(maxRemaining > 0);
|
342
352
|
remaining = std::min<boost::uint64_t>(buffer.size(), maxRemaining);
|
343
353
|
req->bodyAlreadyRead += remaining;
|
344
354
|
SKC_TRACE(client, 3, "Request body: " <<
|
345
355
|
req->bodyAlreadyRead << " of " <<
|
346
356
|
req->aux.bodyInfo.contentLength << " bytes already read");
|
347
357
|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
}
|
358
|
+
req->bodyChannel.feed(MemoryKit::mbuf(buffer, 0, remaining));
|
359
|
+
if (req->ended()) {
|
360
|
+
return Channel::Result(remaining, false);
|
361
|
+
}
|
353
362
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
}
|
360
|
-
return Channel::Result(remaining, false);
|
361
|
-
} else if (req->bodyChannel.mayAcceptInputLater()) {
|
362
|
-
client->input.stop();
|
363
|
-
req->bodyChannel.consumedCallback =
|
364
|
-
onRequestBodyChannelConsumed;
|
365
|
-
return Channel::Result(remaining, false);
|
366
|
-
} else {
|
367
|
-
return Channel::Result(remaining, true);
|
363
|
+
if (req->bodyChannel.acceptingInput()) {
|
364
|
+
if (req->bodyFullyRead()) {
|
365
|
+
SKC_TRACE(client, 2, "End of request body reached");
|
366
|
+
req->detectingNextRequestEarlyReadError = true;
|
367
|
+
req->bodyChannel.feed(MemoryKit::mbuf());
|
368
368
|
}
|
369
|
-
|
370
|
-
|
369
|
+
return Channel::Result(remaining, false);
|
370
|
+
} else if (req->bodyChannel.mayAcceptInputLater()) {
|
371
371
|
client->input.stop();
|
372
|
-
req->bodyChannel.
|
373
|
-
|
372
|
+
req->bodyChannel.consumedCallback =
|
373
|
+
onRequestBodyChannelConsumed;
|
374
|
+
return Channel::Result(remaining, false);
|
375
|
+
} else {
|
376
|
+
return Channel::Result(remaining, true);
|
374
377
|
}
|
375
378
|
} else if (errcode == 0) {
|
376
379
|
// Premature EOF. This cannot be an expected EOF because we
|
@@ -430,7 +433,7 @@ private:
|
|
430
433
|
}
|
431
434
|
case HttpChunkedEvent::END:
|
432
435
|
assert(event.end);
|
433
|
-
|
436
|
+
req->detectingNextRequestEarlyReadError = true;
|
434
437
|
req->aux.bodyInfo.endChunkReached = true;
|
435
438
|
req->bodyChannel.feed(MemoryKit::mbuf());
|
436
439
|
return Channel::Result(event.consumed, false);
|
@@ -583,6 +586,38 @@ private:
|
|
583
586
|
createChunkedBodyParser(req).initialize();
|
584
587
|
}
|
585
588
|
|
589
|
+
bool detectNextRequestEarlyReadError(Client *client, Request *req, const MemoryKit::mbuf &buffer,
|
590
|
+
int errcode)
|
591
|
+
{
|
592
|
+
if (req->detectingNextRequestEarlyReadError) {
|
593
|
+
// When we have previously fully read the expected request body,
|
594
|
+
// the above flag is set to true. This tells us to detect whether
|
595
|
+
// an EOF or an error on the socket has occurred before we are done
|
596
|
+
// processing the request.
|
597
|
+
|
598
|
+
req->detectingNextRequestEarlyReadError = false;
|
599
|
+
client->input.stop();
|
600
|
+
|
601
|
+
if (!req->ended() && buffer.empty()) {
|
602
|
+
if (errcode == 0) {
|
603
|
+
SKC_TRACE(client, 3, "Early read EOF detected");
|
604
|
+
req->nextRequestEarlyReadError = EARLY_EOF_DETECTED;
|
605
|
+
} else {
|
606
|
+
SKC_TRACE(client, 3, "Early body receive error detected: "
|
607
|
+
<< getErrorDesc(errcode) << " (errno=" << errcode << ")");
|
608
|
+
req->nextRequestEarlyReadError = errcode;
|
609
|
+
}
|
610
|
+
onNextRequestEarlyReadError(client, req, req->nextRequestEarlyReadError);
|
611
|
+
} else {
|
612
|
+
SKC_TRACE(client, 3, "No early read EOF or body receive error detected");
|
613
|
+
}
|
614
|
+
|
615
|
+
return true;
|
616
|
+
} else {
|
617
|
+
return false;
|
618
|
+
}
|
619
|
+
}
|
620
|
+
|
586
621
|
|
587
622
|
/***** Channel callbacks *****/
|
588
623
|
|
@@ -678,36 +713,44 @@ protected:
|
|
678
713
|
assert(client->currentRequest != NULL);
|
679
714
|
Request *req = client->currentRequest;
|
680
715
|
RequestRef ref(req, __FILE__, __LINE__);
|
716
|
+
bool ended = req->ended();
|
717
|
+
|
718
|
+
if (!ended) {
|
719
|
+
req->lastDataReceiveTime = ev_now(this->getLoop());
|
720
|
+
}
|
721
|
+
if (detectNextRequestEarlyReadError(client, req, buffer, errcode)) {
|
722
|
+
return Channel::Result(0, false);
|
723
|
+
}
|
681
724
|
|
682
725
|
// Moved outside switch() so that the CPU branch predictor can do its work
|
683
726
|
if (req->httpState == Request::PARSING_HEADERS) {
|
684
|
-
assert(!
|
727
|
+
assert(!ended);
|
685
728
|
return processClientDataWhenParsingHeaders(client, req, buffer, errcode);
|
686
729
|
} else {
|
687
730
|
switch (req->bodyType) {
|
688
731
|
case Request::RBT_CONTENT_LENGTH:
|
689
|
-
if (
|
732
|
+
if (ended) {
|
690
733
|
assert(!req->wantKeepAlive);
|
691
734
|
return Channel::Result(buffer.size(), true);
|
692
735
|
} else {
|
693
736
|
return processClientDataWhenParsingBody(client, req, buffer, errcode);
|
694
737
|
}
|
695
738
|
case Request::RBT_CHUNKED:
|
696
|
-
if (
|
739
|
+
if (ended) {
|
697
740
|
assert(!req->wantKeepAlive);
|
698
741
|
return Channel::Result(buffer.size(), true);
|
699
742
|
} else {
|
700
743
|
return processClientDataWhenParsingChunkedBody(client, req, buffer, errcode);
|
701
744
|
}
|
702
745
|
case Request::RBT_UPGRADE:
|
703
|
-
if (
|
746
|
+
if (ended) {
|
704
747
|
assert(!req->wantKeepAlive);
|
705
748
|
return Channel::Result(buffer.size(), true);
|
706
749
|
} else {
|
707
750
|
return processClientDataWhenUpgraded(client, req, buffer, errcode);
|
708
751
|
}
|
709
752
|
default:
|
710
|
-
P_BUG("Invalid request
|
753
|
+
P_BUG("Invalid request body type " << (int) req->bodyType);
|
711
754
|
// Never reached
|
712
755
|
return Channel::Result(0, false);
|
713
756
|
}
|
@@ -737,6 +780,29 @@ protected:
|
|
737
780
|
|| client->currentRequest->upgraded();
|
738
781
|
}
|
739
782
|
|
783
|
+
virtual void onUpdateStatistics() {
|
784
|
+
ParentClass::onUpdateStatistics();
|
785
|
+
ev_tstamp now = ev_now(this->getLoop());
|
786
|
+
ev_tstamp duration = now - this->lastStatisticsUpdateTime;
|
787
|
+
|
788
|
+
// Statistics are updated about every 5 seconds, so about 12 updates
|
789
|
+
// per minute. We want the old average to decay to 5% after 1 minute
|
790
|
+
// and 1 hour, respectively, so:
|
791
|
+
// 1 minute: 1 - exp(ln(0.05) / 12) = 0.22092219194555585
|
792
|
+
// 1 hour : 1 - exp(ln(0.05) / (60 * 12)) = 0.0041520953856636345
|
793
|
+
requestBeginSpeed1m = expMovingAverage(requestBeginSpeed1m,
|
794
|
+
(totalRequestsBegun - lastTotalRequestsBegun) / duration,
|
795
|
+
0.22092219194555585);
|
796
|
+
requestBeginSpeed1h = expMovingAverage(requestBeginSpeed1h,
|
797
|
+
(totalRequestsBegun - lastTotalRequestsBegun) / duration,
|
798
|
+
0.0041520953856636345);
|
799
|
+
}
|
800
|
+
|
801
|
+
virtual void onFinalizeStatisticsUpdate() {
|
802
|
+
ParentClass::onFinalizeStatisticsUpdate();
|
803
|
+
lastTotalRequestsBegun = totalRequestsBegun;
|
804
|
+
}
|
805
|
+
|
740
806
|
|
741
807
|
/***** New hooks *****/
|
742
808
|
|
@@ -762,6 +828,10 @@ protected:
|
|
762
828
|
return Channel::Result(buffer.size(), false);
|
763
829
|
}
|
764
830
|
|
831
|
+
virtual void onNextRequestEarlyReadError(Client *client, Request *req, int errcode) {
|
832
|
+
// Do nothing.
|
833
|
+
}
|
834
|
+
|
765
835
|
virtual bool supportsUpgrade(Client *client, Request *req) {
|
766
836
|
return false;
|
767
837
|
}
|
@@ -790,6 +860,7 @@ protected:
|
|
790
860
|
req->method = HTTP_GET;
|
791
861
|
req->wantKeepAlive = false;
|
792
862
|
req->responseBegun = false;
|
863
|
+
req->detectingNextRequestEarlyReadError = false;
|
793
864
|
req->parserState.headerParser = headerParserStatePool.construct();
|
794
865
|
createRequestHeaderParser(this->getContext(), req).initialize();
|
795
866
|
if (OXT_UNLIKELY(req->pool == NULL)) {
|
@@ -801,7 +872,11 @@ protected:
|
|
801
872
|
req->bodyChannel.reinitialize();
|
802
873
|
req->aux.bodyInfo.contentLength = 0; // Sets the entire union to 0.
|
803
874
|
req->bodyAlreadyRead = 0;
|
875
|
+
req->lastDataReceiveTime = 0;
|
876
|
+
req->lastDataSendTime = 0;
|
804
877
|
req->queryStringIndex = -1;
|
878
|
+
req->bodyError = 0;
|
879
|
+
req->nextRequestEarlyReadError = 0;
|
805
880
|
}
|
806
881
|
|
807
882
|
/**
|
@@ -860,6 +935,9 @@ public:
|
|
860
935
|
freeRequestCount(0),
|
861
936
|
requestFreelistLimit(1024),
|
862
937
|
totalRequestsBegun(0),
|
938
|
+
lastTotalRequestsBegun(0),
|
939
|
+
requestBeginSpeed1m(-1),
|
940
|
+
requestBeginSpeed1h(-1),
|
863
941
|
headerParserStatePool(16, 256)
|
864
942
|
{
|
865
943
|
STAILQ_INIT(&freeRequests);
|
@@ -928,6 +1006,7 @@ public:
|
|
928
1006
|
|
929
1007
|
void writeResponse(Client *client, const MemoryKit::mbuf &buffer) {
|
930
1008
|
client->currentRequest->responseBegun = true;
|
1009
|
+
client->currentRequest->lastDataSendTime = ev_now(this->getLoop());
|
931
1010
|
client->output.feedWithoutRefGuard(buffer);
|
932
1011
|
}
|
933
1012
|
|
@@ -1120,6 +1199,12 @@ public:
|
|
1120
1199
|
Json::Value doc = ParentClass::inspectStateAsJson();
|
1121
1200
|
doc["free_request_count"] = freeRequestCount;
|
1122
1201
|
doc["total_requests_begun"] = (Json::UInt64) totalRequestsBegun;
|
1202
|
+
doc["request_begin_speed"]["1m"] = averageSpeedToJson(
|
1203
|
+
capFloatPrecision(requestBeginSpeed1m * 60),
|
1204
|
+
"minute", "1 minute", -1);
|
1205
|
+
doc["request_begin_speed"]["1h"] = averageSpeedToJson(
|
1206
|
+
capFloatPrecision(requestBeginSpeed1h * 60),
|
1207
|
+
"minute", "1 hour", -1);
|
1123
1208
|
return doc;
|
1124
1209
|
}
|
1125
1210
|
|
@@ -1149,6 +1234,8 @@ public:
|
|
1149
1234
|
doc["request_body_fully_read"] = req->bodyFullyRead();
|
1150
1235
|
doc["request_body_already_read"] = (Json::Value::UInt64) req->bodyAlreadyRead;
|
1151
1236
|
doc["response_begun"] = req->responseBegun;
|
1237
|
+
doc["last_data_receive_time"] = timeToJson(req->lastDataReceiveTime * 1000000);
|
1238
|
+
doc["last_data_send_time"] = timeToJson(req->lastDataSendTime * 1000000);
|
1152
1239
|
doc["method"] = http_method_str(req->method);
|
1153
1240
|
if (req->httpState != Request::ERROR) {
|
1154
1241
|
if (req->bodyType == Request::RBT_CONTENT_LENGTH) {
|
@@ -1162,6 +1249,11 @@ public:
|
|
1162
1249
|
doc["parse_error"] = getErrorDesc(req->aux.parseError);
|
1163
1250
|
}
|
1164
1251
|
|
1252
|
+
if (req->nextRequestEarlyReadError != 0) {
|
1253
|
+
doc["next_request_early_read_error"] = getErrorDesc(req->nextRequestEarlyReadError)
|
1254
|
+
+ string(" (errno=") + toString(req->nextRequestEarlyReadError) + ")";
|
1255
|
+
}
|
1256
|
+
|
1165
1257
|
string str;
|
1166
1258
|
str.reserve(req->path.size);
|
1167
1259
|
part = req->path.start;
|
@@ -56,10 +56,12 @@
|
|
56
56
|
#include <ServerKit/Hooks.h>
|
57
57
|
#include <ServerKit/Client.h>
|
58
58
|
#include <ServerKit/ClientRef.h>
|
59
|
+
#include <Algorithms/MovingAverage.h>
|
59
60
|
#include <Utils.h>
|
60
61
|
#include <Utils/ScopeGuard.h>
|
61
62
|
#include <Utils/StrIntUtils.h>
|
62
63
|
#include <Utils/IOUtils.h>
|
64
|
+
#include <Utils/SystemTime.h>
|
63
65
|
|
64
66
|
namespace Passenger {
|
65
67
|
namespace ServerKit {
|
@@ -212,8 +214,11 @@ public:
|
|
212
214
|
FreeClientList freeClients;
|
213
215
|
ClientList activeClients, disconnectedClients;
|
214
216
|
unsigned int freeClientCount, activeClientCount, disconnectedClientCount;
|
215
|
-
unsigned
|
217
|
+
unsigned int peakActiveClientCount;
|
218
|
+
unsigned long totalClientsAccepted, lastTotalClientsAccepted;
|
216
219
|
unsigned long long totalBytesConsumed;
|
220
|
+
ev_tstamp lastStatisticsUpdateTime;
|
221
|
+
double clientAcceptSpeed1m, clientAcceptSpeed1h;
|
217
222
|
|
218
223
|
private:
|
219
224
|
Context *ctx;
|
@@ -221,6 +226,7 @@ private:
|
|
221
226
|
uint8_t nEndpoints: 3;
|
222
227
|
bool accept4Available: 1;
|
223
228
|
ev::timer acceptResumptionWatcher;
|
229
|
+
ev::timer statisticsUpdateWatcher;
|
224
230
|
ev::io endpoints[SERVER_KIT_MAX_SERVER_ENDPOINTS];
|
225
231
|
|
226
232
|
|
@@ -335,6 +341,16 @@ private:
|
|
335
341
|
}
|
336
342
|
}
|
337
343
|
|
344
|
+
void onStatisticsUpdateTimeout(ev::timer &timer, int revents) {
|
345
|
+
TRACE_POINT();
|
346
|
+
|
347
|
+
this->onUpdateStatistics();
|
348
|
+
this->onFinalizeStatisticsUpdate();
|
349
|
+
|
350
|
+
timer.repeat = timeToNextMultipleD(5, ev_now(this->getLoop()));
|
351
|
+
timer.again();
|
352
|
+
}
|
353
|
+
|
338
354
|
unsigned int getNextClientNumber() {
|
339
355
|
return nextClientNumber++;
|
340
356
|
}
|
@@ -442,6 +458,9 @@ private:
|
|
442
458
|
TRACE_POINT();
|
443
459
|
compact(LVL_INFO);
|
444
460
|
|
461
|
+
acceptResumptionWatcher.stop();
|
462
|
+
statisticsUpdateWatcher.stop();
|
463
|
+
|
445
464
|
SKS_NOTICE("Shutdown finished");
|
446
465
|
serverState = FINISHED_SHUTDOWN;
|
447
466
|
if (shutdownFinishCallback != NULL) {
|
@@ -513,6 +532,8 @@ protected:
|
|
513
532
|
virtual void onClientsAccepted(Client **clients, unsigned int size) {
|
514
533
|
unsigned int i;
|
515
534
|
|
535
|
+
peakActiveClientCount = std::max(peakActiveClientCount, activeClientCount);
|
536
|
+
|
516
537
|
for (i = 0; i < size; i++) {
|
517
538
|
Client *client = clients[i];
|
518
539
|
|
@@ -572,6 +593,29 @@ protected:
|
|
572
593
|
return LVL_WARN;
|
573
594
|
}
|
574
595
|
|
596
|
+
virtual void onUpdateStatistics() {
|
597
|
+
SKS_DEBUG("Updating statistics");
|
598
|
+
ev_tstamp now = ev_now(this->getLoop());
|
599
|
+
ev_tstamp duration = now - lastStatisticsUpdateTime;
|
600
|
+
|
601
|
+
// Statistics are updated about every 5 seconds, so about 12 updates
|
602
|
+
// per minute. We want the old average to decay to 5% after 1 minute
|
603
|
+
// and 1 hour, respectively, so:
|
604
|
+
// 1 minute: 1 - exp(ln(0.05) / 12) = 0.22092219194555585
|
605
|
+
// 1 hour : 1 - exp(ln(0.05) / (60 * 12)) = 0.0041520953856636345
|
606
|
+
clientAcceptSpeed1m = expMovingAverage(clientAcceptSpeed1m,
|
607
|
+
(totalClientsAccepted - lastTotalClientsAccepted) / duration,
|
608
|
+
0.22092219194555585);
|
609
|
+
clientAcceptSpeed1h = expMovingAverage(clientAcceptSpeed1h,
|
610
|
+
(totalClientsAccepted - lastTotalClientsAccepted) / duration,
|
611
|
+
0.0041520953856636345);
|
612
|
+
}
|
613
|
+
|
614
|
+
virtual void onFinalizeStatisticsUpdate() {
|
615
|
+
lastTotalClientsAccepted = totalClientsAccepted;
|
616
|
+
lastStatisticsUpdateTime = ev_now(this->getLoop());
|
617
|
+
}
|
618
|
+
|
575
619
|
virtual void reinitializeClient(Client *client, int fd) {
|
576
620
|
client->setConnState(Client::ACTIVE);
|
577
621
|
SKC_TRACE(client, 2, "Client associated with file descriptor: " << fd);
|
@@ -601,8 +645,13 @@ public:
|
|
601
645
|
freeClientCount(0),
|
602
646
|
activeClientCount(0),
|
603
647
|
disconnectedClientCount(0),
|
648
|
+
peakActiveClientCount(0),
|
604
649
|
totalClientsAccepted(0),
|
650
|
+
lastTotalClientsAccepted(0),
|
605
651
|
totalBytesConsumed(0),
|
652
|
+
lastStatisticsUpdateTime(ev_time()),
|
653
|
+
clientAcceptSpeed1m(-1),
|
654
|
+
clientAcceptSpeed1h(-1),
|
606
655
|
ctx(context),
|
607
656
|
nextClientNumber(1),
|
608
657
|
nEndpoints(0),
|
@@ -611,10 +660,18 @@ public:
|
|
611
660
|
STAILQ_INIT(&freeClients);
|
612
661
|
TAILQ_INIT(&activeClients);
|
613
662
|
TAILQ_INIT(&disconnectedClients);
|
663
|
+
|
614
664
|
acceptResumptionWatcher.set(context->libev->getLoop());
|
615
665
|
acceptResumptionWatcher.set<
|
616
666
|
BaseServer<DerivedServer, Client>,
|
617
667
|
&BaseServer<DerivedServer, Client>::onAcceptResumeTimeout>(this);
|
668
|
+
|
669
|
+
statisticsUpdateWatcher.set(context->libev->getLoop());
|
670
|
+
statisticsUpdateWatcher.set<
|
671
|
+
BaseServer<DerivedServer, Client>,
|
672
|
+
&BaseServer<DerivedServer, Client>::onStatisticsUpdateTimeout>(this);
|
673
|
+
statisticsUpdateWatcher.set(5, 5);
|
674
|
+
statisticsUpdateWatcher.start();
|
618
675
|
}
|
619
676
|
|
620
677
|
virtual ~BaseServer() {
|
@@ -995,6 +1052,13 @@ public:
|
|
995
1052
|
doc["active_client_count"] = activeClientCount;
|
996
1053
|
Json::Value &disconnectedClientsDoc = doc["disconnected_clients"] = Json::Value(Json::objectValue);
|
997
1054
|
doc["disconnected_client_count"] = disconnectedClientCount;
|
1055
|
+
doc["peak_active_client_count"] = peakActiveClientCount;
|
1056
|
+
doc["client_accept_speed"]["1m"] = averageSpeedToJson(
|
1057
|
+
capFloatPrecision(clientAcceptSpeed1m * 60),
|
1058
|
+
"minute", "1 minute", -1);
|
1059
|
+
doc["client_accept_speed"]["1h"] = averageSpeedToJson(
|
1060
|
+
capFloatPrecision(clientAcceptSpeed1h * 60),
|
1061
|
+
"minute", "1 hour", -1);
|
998
1062
|
doc["total_clients_accepted"] = (Json::UInt64) totalClientsAccepted;
|
999
1063
|
doc["total_bytes_consumed"] = (Json::UInt64) totalBytesConsumed;
|
1000
1064
|
|