passenger 5.0.9 → 5.0.10
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/CHANGELOG +15 -0
- data/CONTRIBUTORS +6 -0
- data/README.md +1 -1
- data/bin/passenger-install-apache2-module +24 -11
- data/bin/passenger-status +29 -14
- data/build/agents.rb +12 -10
- data/build/cxx_tests.rb +30 -30
- data/doc/Design and Architecture.html +1 -10
- data/doc/Design and Architecture.txt +1 -6
- data/doc/Users guide Apache.html +1 -19
- data/doc/Users guide Apache.txt +1 -1
- data/doc/Users guide Nginx.html +2 -20
- data/doc/Users guide Nginx.txt +2 -2
- data/doc/users_guide_snippets/tips.txt +0 -9
- data/ext/common/ApplicationPool2/ApiKey.h +158 -0
- data/ext/common/ApplicationPool2/BasicGroupInfo.h +81 -0
- data/ext/common/ApplicationPool2/BasicProcessInfo.h +106 -0
- data/ext/common/ApplicationPool2/Common.h +5 -44
- data/ext/common/ApplicationPool2/Context.h +94 -0
- data/ext/common/ApplicationPool2/Group.h +130 -1205
- data/ext/common/ApplicationPool2/Group/InitializationAndShutdown.cpp +190 -0
- data/ext/common/ApplicationPool2/Group/InternalUtils.cpp +329 -0
- data/ext/common/ApplicationPool2/Group/LifetimeAndBasics.cpp +103 -0
- data/ext/common/ApplicationPool2/{Pool/Debug.h → Group/Miscellaneous.cpp} +40 -38
- data/ext/common/ApplicationPool2/Group/OutOfBandWork.cpp +323 -0
- data/ext/common/ApplicationPool2/Group/ProcessListManagement.cpp +606 -0
- data/ext/common/ApplicationPool2/Group/SessionManagement.cpp +337 -0
- data/ext/common/ApplicationPool2/Group/SpawningAndRestarting.cpp +478 -0
- data/ext/common/ApplicationPool2/Group/StateInspection.cpp +197 -0
- data/ext/common/ApplicationPool2/Group/Verification.cpp +159 -0
- data/ext/common/ApplicationPool2/Implementation.cpp +19 -1401
- data/ext/common/ApplicationPool2/Options.h +5 -5
- data/ext/common/ApplicationPool2/Pool.h +260 -815
- data/ext/common/ApplicationPool2/Pool/{AnalyticsCollection.h → AnalyticsCollection.cpp} +55 -56
- data/ext/common/ApplicationPool2/Pool/{GarbageCollection.h → GarbageCollection.cpp} +49 -49
- data/ext/common/ApplicationPool2/Pool/GeneralUtils.cpp +241 -0
- data/ext/common/ApplicationPool2/Pool/GroupUtils.cpp +276 -0
- data/ext/common/ApplicationPool2/Pool/InitializationAndShutdown.cpp +145 -0
- data/ext/common/ApplicationPool2/Pool/Miscellaneous.cpp +244 -0
- data/ext/common/ApplicationPool2/Pool/ProcessUtils.cpp +330 -0
- data/ext/common/ApplicationPool2/Pool/StateInspection.cpp +299 -0
- data/ext/common/ApplicationPool2/Process.h +399 -205
- data/ext/common/ApplicationPool2/Session.h +70 -28
- data/ext/common/ApplicationPool2/Socket.h +1 -0
- data/ext/common/Constants.h +11 -3
- data/ext/common/Exceptions.h +1 -1
- data/ext/common/Logging.cpp +9 -4
- data/ext/common/Logging.h +6 -0
- data/ext/common/ServerKit/HttpServer.h +225 -215
- data/ext/common/ServerKit/Server.h +57 -57
- data/ext/common/SpawningKit/BackgroundIOCapturer.h +160 -0
- data/ext/common/SpawningKit/Config.h +107 -0
- data/ext/common/{ApplicationPool2 → SpawningKit}/DirectSpawner.h +17 -16
- data/ext/common/{ApplicationPool2 → SpawningKit}/DummySpawner.h +33 -33
- data/ext/common/{ApplicationPool2/SpawnerFactory.h → SpawningKit/Factory.h} +17 -17
- data/ext/common/{ApplicationPool2/ComponentInfo.h → SpawningKit/Options.h} +8 -21
- data/ext/common/SpawningKit/PipeWatcher.h +148 -0
- data/ext/common/{ApplicationPool2/PipeWatcher.h → SpawningKit/Result.h} +15 -33
- data/ext/common/{ApplicationPool2 → SpawningKit}/SmartSpawner.h +52 -57
- data/ext/common/{ApplicationPool2 → SpawningKit}/Spawner.h +83 -371
- data/ext/common/SpawningKit/UserSwitchingRules.h +265 -0
- data/ext/common/Utils/BufferedIO.h +24 -0
- data/ext/common/{ApplicationPool2/SpawnObject.h → Utils/ClassUtils.h} +24 -51
- data/ext/common/Utils/IOUtils.cpp +70 -0
- data/ext/common/Utils/IOUtils.h +19 -0
- data/ext/common/Utils/JsonUtils.h +113 -0
- data/ext/common/Utils/StrIntUtils.h +29 -0
- data/ext/common/Utils/json.h +1 -1
- data/ext/common/agents/ApiServerUtils.h +941 -0
- data/ext/common/agents/HelperAgent/{AdminServer.h → ApiServer.h} +163 -365
- data/ext/common/agents/HelperAgent/Main.cpp +86 -88
- data/ext/common/agents/HelperAgent/OptionParser.h +9 -10
- data/ext/common/agents/HelperAgent/RequestHandler/BufferBody.cpp +3 -0
- data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +2 -0
- data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +2 -2
- data/ext/common/agents/LoggingAgent/ApiServer.h +279 -0
- data/ext/common/agents/LoggingAgent/Main.cpp +41 -51
- data/ext/common/agents/LoggingAgent/OptionParser.h +11 -11
- data/ext/common/agents/Watchdog/ApiServer.h +311 -0
- data/ext/common/agents/Watchdog/Main.cpp +91 -65
- data/helper-scripts/prespawn +2 -0
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/admin_tools/instance.rb +1 -1
- data/lib/phusion_passenger/common_library.rb +27 -14
- data/lib/phusion_passenger/config/{admin_command_command.rb → api_call_command.rb} +19 -16
- data/lib/phusion_passenger/config/detach_process_command.rb +6 -3
- data/lib/phusion_passenger/config/main.rb +3 -5
- data/lib/phusion_passenger/config/reopen_logs_command.rb +29 -7
- data/lib/phusion_passenger/config/restart_app_command.rb +13 -4
- data/lib/phusion_passenger/config/utils.rb +15 -8
- data/lib/phusion_passenger/constants.rb +6 -2
- data/lib/phusion_passenger/platform_info/apache.rb +4 -0
- data/lib/phusion_passenger/platform_info/apache_detector.rb +18 -3
- data/resources/templates/apache2/mpm_unknown.txt.erb +20 -0
- metadata +42 -21
- metadata.gz.asc +7 -7
- data/ext/common/ApplicationPool2/Pool/GeneralUtils.h +0 -127
- data/ext/common/ApplicationPool2/Pool/Inspection.h +0 -219
- data/ext/common/ApplicationPool2/Pool/ProcessUtils.h +0 -85
- data/ext/common/ApplicationPool2/SuperGroup.h +0 -706
- data/ext/common/agents/LoggingAgent/AdminServer.h +0 -435
- data/ext/common/agents/Watchdog/AdminServer.h +0 -432
@@ -31,10 +31,12 @@
|
|
31
31
|
#include <oxt/macros.hpp>
|
32
32
|
#include <oxt/system_calls.hpp>
|
33
33
|
#include <oxt/backtrace.hpp>
|
34
|
-
#include <ApplicationPool2/
|
34
|
+
#include <ApplicationPool2/Context.h>
|
35
|
+
#include <ApplicationPool2/BasicProcessInfo.h>
|
36
|
+
#include <ApplicationPool2/BasicGroupInfo.h>
|
35
37
|
#include <ApplicationPool2/Socket.h>
|
36
|
-
#include <FileDescriptor.h>
|
37
38
|
#include <Utils/ScopeGuard.h>
|
39
|
+
#include <Utils/Lock.h>
|
38
40
|
|
39
41
|
namespace Passenger {
|
40
42
|
namespace ApplicationPool2 {
|
@@ -47,11 +49,16 @@ using namespace oxt;
|
|
47
49
|
* within Phusion Passenger is usually a single request + response but the API
|
48
50
|
* allows arbitrary I/O. See Process's class overview for normal usage of Session.
|
49
51
|
*
|
50
|
-
*
|
51
|
-
* and so should only be access through 1 thread.
|
52
|
+
* A Session object is created from a Process object.
|
52
53
|
*
|
53
|
-
*
|
54
|
-
*
|
54
|
+
* This class can be used outside the ApplicationPool lock, because the methods in this
|
55
|
+
* class only return immutable data and only modify data inside the Session object.
|
56
|
+
* However, it is not thread-safe, and so should only be accessed through 1 thread.
|
57
|
+
*
|
58
|
+
* You MUST destroy all Session objects before destroying the Context that
|
59
|
+
* it was allocated from. Outside unit tests, Context lives in Pool, so
|
60
|
+
* so in that case you must not destroy Pool before destroying all Session
|
61
|
+
* objects.
|
55
62
|
*/
|
56
63
|
class Session {
|
57
64
|
public:
|
@@ -59,13 +66,20 @@ public:
|
|
59
66
|
|
60
67
|
private:
|
61
68
|
/**
|
62
|
-
*
|
63
|
-
*
|
64
|
-
*
|
65
|
-
|
69
|
+
* Pointer to the Context that this Session was allocated from. Always
|
70
|
+
* non-NULL. Allows the Session to free itself from the memory pool
|
71
|
+
* inside the Context.
|
72
|
+
*/
|
73
|
+
Context * const context;
|
74
|
+
/**
|
75
|
+
* Backpointers to Socket that this Session was made from, as well as the immutable info
|
76
|
+
* of the Group and Process that this Session belongs to.
|
77
|
+
*
|
78
|
+
* These are non-NULL if and only if the Session hasn't been closed.
|
79
|
+
* This works because Group waits until all sessions are closed
|
80
|
+
* before destroying a Process.
|
66
81
|
*/
|
67
|
-
|
68
|
-
Process *process;
|
82
|
+
const BasicProcessInfo *processInfo;
|
69
83
|
Socket *socket;
|
70
84
|
|
71
85
|
Connection connection;
|
@@ -92,13 +106,19 @@ private:
|
|
92
106
|
closed = true;
|
93
107
|
}
|
94
108
|
|
109
|
+
void destroySelf() const {
|
110
|
+
this->~Session();
|
111
|
+
LockGuard l(context->getMmSyncher());
|
112
|
+
context->getSessionObjectPool().free(const_cast<Session *>(this));
|
113
|
+
}
|
114
|
+
|
95
115
|
public:
|
96
116
|
Callback onInitiateFailure;
|
97
117
|
Callback onClose;
|
98
118
|
|
99
|
-
Session(
|
100
|
-
:
|
101
|
-
|
119
|
+
Session(Context *_context, const BasicProcessInfo *_processInfo, Socket *_socket)
|
120
|
+
: context(_context),
|
121
|
+
processInfo(_processInfo),
|
102
122
|
socket(_socket),
|
103
123
|
refcount(1),
|
104
124
|
closed(false),
|
@@ -117,22 +137,36 @@ public:
|
|
117
137
|
}
|
118
138
|
}
|
119
139
|
|
120
|
-
StaticString getGroupSecret() const;
|
121
|
-
pid_t getPid() const;
|
122
|
-
StaticString getGupid() const;
|
123
|
-
unsigned int getStickySessionId() const;
|
124
|
-
Group *getGroup() const;
|
125
|
-
void requestOOBW();
|
126
|
-
int kill(int signo);
|
127
|
-
void destroySelf() const;
|
128
140
|
|
129
|
-
|
130
|
-
|
141
|
+
Group *getGroup() const {
|
142
|
+
assert(!closed);
|
143
|
+
return processInfo->groupInfo->group;
|
131
144
|
}
|
132
145
|
|
133
146
|
Process *getProcess() const {
|
134
147
|
assert(!closed);
|
135
|
-
return process;
|
148
|
+
return processInfo->process;
|
149
|
+
}
|
150
|
+
|
151
|
+
|
152
|
+
const ApiKey &getApiKey() const {
|
153
|
+
assert(!closed);
|
154
|
+
return processInfo->groupInfo->apiKey;
|
155
|
+
}
|
156
|
+
|
157
|
+
pid_t getPid() const {
|
158
|
+
assert(!closed);
|
159
|
+
return processInfo->pid;
|
160
|
+
}
|
161
|
+
|
162
|
+
StaticString getGupid() const {
|
163
|
+
assert(!closed);
|
164
|
+
return StaticString(processInfo->gupid, processInfo->gupidSize);
|
165
|
+
}
|
166
|
+
|
167
|
+
unsigned int getStickySessionId() const {
|
168
|
+
assert(!closed);
|
169
|
+
return processInfo->stickySessionId;
|
136
170
|
}
|
137
171
|
|
138
172
|
Socket *getSocket() const {
|
@@ -144,6 +178,7 @@ public:
|
|
144
178
|
return getSocket()->protocol;
|
145
179
|
}
|
146
180
|
|
181
|
+
|
147
182
|
void initiate(bool blocking = true) {
|
148
183
|
assert(!closed);
|
149
184
|
ScopeGuard g(boost::bind(&Session::callOnInitiateFailure, this));
|
@@ -179,10 +214,17 @@ public:
|
|
179
214
|
if (OXT_LIKELY(!closed)) {
|
180
215
|
callOnClose();
|
181
216
|
}
|
182
|
-
|
183
|
-
socket
|
217
|
+
processInfo = NULL;
|
218
|
+
socket = NULL;
|
184
219
|
}
|
185
220
|
|
221
|
+
bool isClosed() const {
|
222
|
+
return closed;
|
223
|
+
}
|
224
|
+
|
225
|
+
void requestOOBW();
|
226
|
+
|
227
|
+
|
186
228
|
void ref() const {
|
187
229
|
refcount.fetch_add(1, boost::memory_order_relaxed);
|
188
230
|
}
|
data/ext/common/Constants.h
CHANGED
@@ -64,7 +64,7 @@
|
|
64
64
|
|
65
65
|
#define DEFAULT_HTTP_SERVER_LISTEN_ADDRESS "tcp://127.0.0.1:3000"
|
66
66
|
|
67
|
-
#define
|
67
|
+
#define DEFAULT_LOGGING_AGENT_API_LISTEN_ADDRESS "tcp://127.0.0.1:9345"
|
68
68
|
|
69
69
|
#define DEFAULT_LOGGING_AGENT_LISTEN_ADDRESS "tcp://127.0.0.1:9344"
|
70
70
|
|
@@ -114,9 +114,15 @@
|
|
114
114
|
|
115
115
|
#define NGINX_DOC_URL "https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html"
|
116
116
|
|
117
|
+
#define PASSENGER_API_VERSION "0.2"
|
118
|
+
|
119
|
+
#define PASSENGER_API_VERSION_MAJOR 0
|
120
|
+
|
121
|
+
#define PASSENGER_API_VERSION_MINOR 2
|
122
|
+
|
117
123
|
#define PASSENGER_DEFAULT_USER "nobody"
|
118
124
|
|
119
|
-
#define PASSENGER_VERSION "5.0.
|
125
|
+
#define PASSENGER_VERSION "5.0.10"
|
120
126
|
|
121
127
|
#define POOL_HELPER_THREAD_STACK_SIZE 262144
|
122
128
|
|
@@ -136,7 +142,9 @@
|
|
136
142
|
|
137
143
|
#define SERVER_INSTANCE_DIR_STRUCTURE_MAJOR_VERSION 2
|
138
144
|
|
139
|
-
#define SERVER_INSTANCE_DIR_STRUCTURE_MINOR_VERSION
|
145
|
+
#define SERVER_INSTANCE_DIR_STRUCTURE_MINOR_VERSION 1
|
146
|
+
|
147
|
+
#define SERVER_INSTANCE_DIR_STRUCTURE_MIN_SUPPORTED_MINOR_VERSION 0
|
140
148
|
|
141
149
|
#define SERVER_KIT_MAX_SERVER_ENDPOINTS 4
|
142
150
|
|
data/ext/common/Exceptions.h
CHANGED
@@ -369,7 +369,7 @@ public:
|
|
369
369
|
* Indicates that a Pool::get() or Pool::asyncGet() request was denied.
|
370
370
|
* The request never reached a process. This could be because, before the
|
371
371
|
* request could reach a process, the administrator detached the containing
|
372
|
-
*
|
372
|
+
* group. Or maybe the request sat in the queue for too long.
|
373
373
|
*/
|
374
374
|
class GetAbortedException: public oxt::tracable_exception {
|
375
375
|
private:
|
data/ext/common/Logging.cpp
CHANGED
@@ -66,11 +66,8 @@ bool
|
|
66
66
|
setLogFile(const string &path, int *errcode) {
|
67
67
|
int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644);
|
68
68
|
if (fd != -1) {
|
69
|
-
|
70
|
-
dup2(fd, STDOUT_FILENO);
|
71
|
-
dup2(fd, STDERR_FILENO);
|
69
|
+
setLogFileWithFd(path, fd);
|
72
70
|
close(fd);
|
73
|
-
logFile = path;
|
74
71
|
return true;
|
75
72
|
} else {
|
76
73
|
if (errcode != NULL) {
|
@@ -80,6 +77,14 @@ setLogFile(const string &path, int *errcode) {
|
|
80
77
|
}
|
81
78
|
}
|
82
79
|
|
80
|
+
void
|
81
|
+
setLogFileWithFd(const string &path, int fd) {
|
82
|
+
boost::lock_guard<boost::mutex> l(logFileMutex);
|
83
|
+
dup2(fd, STDOUT_FILENO);
|
84
|
+
dup2(fd, STDERR_FILENO);
|
85
|
+
logFile = path;
|
86
|
+
}
|
87
|
+
|
83
88
|
bool
|
84
89
|
hasFileDescriptorLogFile() {
|
85
90
|
return fileDescriptorLog != -1;
|
data/ext/common/Logging.h
CHANGED
@@ -96,6 +96,12 @@ string getLogFile();
|
|
96
96
|
*/
|
97
97
|
bool setLogFile(const string &path, int *errcode = NULL);
|
98
98
|
|
99
|
+
/**
|
100
|
+
* Sets the general log file, assuming that it's already opened
|
101
|
+
* at the given fd. This method is thread-safe.
|
102
|
+
*/
|
103
|
+
void setLogFileWithFd(const string &path, int fd);
|
104
|
+
|
99
105
|
/**
|
100
106
|
* Returns whether we're using a separate log file for logging file
|
101
107
|
* descriptor opening and closing.
|
@@ -657,221 +657,6 @@ private:
|
|
657
657
|
}
|
658
658
|
|
659
659
|
protected:
|
660
|
-
/***** Protected API *****/
|
661
|
-
|
662
|
-
/** Increase request reference count. */
|
663
|
-
void refRequest(Request *req, const char *file, unsigned int line) {
|
664
|
-
int oldRefcount = req->refcount.fetch_add(1, boost::memory_order_relaxed);
|
665
|
-
SKC_TRACE_WITH_POS(static_cast<Client *>(req->client), 3, file, line,
|
666
|
-
"Request refcount increased; it is now " << (oldRefcount + 1));
|
667
|
-
}
|
668
|
-
|
669
|
-
/** Decrease request reference count. Adds request to the
|
670
|
-
* freelist if reference count drops to 0.
|
671
|
-
*/
|
672
|
-
void unrefRequest(Request *req, const char *file, unsigned int line) {
|
673
|
-
int oldRefcount = req->refcount.fetch_sub(1, boost::memory_order_release);
|
674
|
-
assert(oldRefcount >= 1);
|
675
|
-
|
676
|
-
SKC_TRACE_WITH_POS(static_cast<Client *>(req->client), 3, file, line,
|
677
|
-
"Request refcount decreased; it is now " << (oldRefcount - 1));
|
678
|
-
if (oldRefcount == 1) {
|
679
|
-
boost::atomic_thread_fence(boost::memory_order_acquire);
|
680
|
-
|
681
|
-
if (this->getContext()->libev->onEventLoopThread()) {
|
682
|
-
requestReachedZeroRefcount(req);
|
683
|
-
} else {
|
684
|
-
// Let the event loop handle the request reaching the 0 refcount.
|
685
|
-
passRequestToEventLoopThread(req);
|
686
|
-
}
|
687
|
-
}
|
688
|
-
}
|
689
|
-
|
690
|
-
object_pool<HttpHeaderParserState> &getHeaderParserStatePool() {
|
691
|
-
return headerParserStatePool;
|
692
|
-
}
|
693
|
-
|
694
|
-
bool canKeepAlive(Request *req) const {
|
695
|
-
return req->wantKeepAlive
|
696
|
-
&& req->bodyFullyRead()
|
697
|
-
&& HttpServer::serverState < HttpServer::SHUTTING_DOWN;
|
698
|
-
}
|
699
|
-
|
700
|
-
void writeResponse(Client *client, const MemoryKit::mbuf &buffer) {
|
701
|
-
client->currentRequest->responseBegun = true;
|
702
|
-
client->output.feedWithoutRefGuard(buffer);
|
703
|
-
}
|
704
|
-
|
705
|
-
void writeResponse(Client *client, const char *data, unsigned int size) {
|
706
|
-
writeResponse(client, MemoryKit::mbuf(data, size));
|
707
|
-
}
|
708
|
-
|
709
|
-
void writeResponse(Client *client, const StaticString &data) {
|
710
|
-
writeResponse(client, data.data(), data.size());
|
711
|
-
}
|
712
|
-
|
713
|
-
void
|
714
|
-
writeSimpleResponse(Client *client, int code, const HeaderTable *headers,
|
715
|
-
const StaticString &body)
|
716
|
-
{
|
717
|
-
unsigned int headerBufSize = 300;
|
718
|
-
|
719
|
-
if (headers != NULL) {
|
720
|
-
HeaderTable::ConstIterator it(*headers);
|
721
|
-
while (*it != NULL) {
|
722
|
-
headerBufSize += it->header->key.size + sizeof(": ") - 1;
|
723
|
-
headerBufSize += it->header->val.size + sizeof("\r\n") - 1;
|
724
|
-
it.next();
|
725
|
-
}
|
726
|
-
}
|
727
|
-
|
728
|
-
Request *req = client->currentRequest;
|
729
|
-
char *header = (char *) psg_pnalloc(req->pool, headerBufSize);
|
730
|
-
char statusBuffer[50];
|
731
|
-
char *pos = header;
|
732
|
-
const char *end = header + headerBufSize;
|
733
|
-
const char *status;
|
734
|
-
const LString *value;
|
735
|
-
|
736
|
-
status = getStatusCodeAndReasonPhrase(code);
|
737
|
-
if (status == NULL) {
|
738
|
-
snprintf(statusBuffer, sizeof(statusBuffer), "%d Unknown Reason-Phrase", code);
|
739
|
-
status = statusBuffer;
|
740
|
-
}
|
741
|
-
|
742
|
-
pos += snprintf(pos, end - pos,
|
743
|
-
"HTTP/%d.%d %s\r\n"
|
744
|
-
"Status: %s\r\n",
|
745
|
-
(int) req->httpMajor, (int) req->httpMinor, status, status);
|
746
|
-
|
747
|
-
value = (headers != NULL) ? headers->lookup(P_STATIC_STRING("content-type")) : NULL;
|
748
|
-
if (value == NULL) {
|
749
|
-
pos = appendData(pos, end, P_STATIC_STRING("Content-Type: text/html; charset=UTF-8\r\n"));
|
750
|
-
} else {
|
751
|
-
pos = appendData(pos, end, P_STATIC_STRING("Content-Type: "));
|
752
|
-
pos = appendLStringData(pos, end, value);
|
753
|
-
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
754
|
-
}
|
755
|
-
|
756
|
-
value = (headers != NULL) ? headers->lookup(P_STATIC_STRING("date")) : NULL;
|
757
|
-
pos = appendData(pos, end, P_STATIC_STRING("Date: "));
|
758
|
-
if (value == NULL) {
|
759
|
-
time_t the_time = time(NULL);
|
760
|
-
struct tm the_tm;
|
761
|
-
gmtime_r(&the_time, &the_tm);
|
762
|
-
pos += strftime(pos, end - pos, "%a, %d %b %Y %H:%M:%S %z", &the_tm);
|
763
|
-
} else {
|
764
|
-
pos = appendLStringData(pos, end, value);
|
765
|
-
}
|
766
|
-
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
767
|
-
|
768
|
-
value = (headers != NULL) ? headers->lookup(P_STATIC_STRING("connection")) : NULL;
|
769
|
-
if (value == NULL) {
|
770
|
-
if (canKeepAlive(req)) {
|
771
|
-
pos = appendData(pos, end, P_STATIC_STRING("Connection: keep-alive\r\n"));
|
772
|
-
} else {
|
773
|
-
pos = appendData(pos, end, P_STATIC_STRING("Connection: close\r\n"));
|
774
|
-
}
|
775
|
-
} else {
|
776
|
-
pos = appendData(pos, end, P_STATIC_STRING("Connection: "));
|
777
|
-
pos = appendLStringData(pos, end, value);
|
778
|
-
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
779
|
-
if (!psg_lstr_cmp(value, P_STATIC_STRING("Keep-Alive"))
|
780
|
-
&& !psg_lstr_cmp(value, P_STATIC_STRING("keep-alive")))
|
781
|
-
{
|
782
|
-
req->wantKeepAlive = false;
|
783
|
-
}
|
784
|
-
}
|
785
|
-
|
786
|
-
value = (headers != NULL) ? headers->lookup(P_STATIC_STRING("content-length")) : NULL;
|
787
|
-
pos = appendData(pos, end, P_STATIC_STRING("Content-Length: "));
|
788
|
-
if (value == NULL) {
|
789
|
-
pos += snprintf(pos, end - pos, "%u", (unsigned int) body.size());
|
790
|
-
} else {
|
791
|
-
pos = appendLStringData(pos, end, value);
|
792
|
-
}
|
793
|
-
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
794
|
-
|
795
|
-
if (headers != NULL) {
|
796
|
-
HeaderTable::ConstIterator it(*headers);
|
797
|
-
while (*it != NULL) {
|
798
|
-
if (!psg_lstr_cmp(&it->header->key, P_STATIC_STRING("content-type"))
|
799
|
-
&& !psg_lstr_cmp(&it->header->key, P_STATIC_STRING("date"))
|
800
|
-
&& !psg_lstr_cmp(&it->header->key, P_STATIC_STRING("connection"))
|
801
|
-
&& !psg_lstr_cmp(&it->header->key, P_STATIC_STRING("content-length")))
|
802
|
-
{
|
803
|
-
pos = appendLStringData(pos, end, &it->header->key);
|
804
|
-
pos = appendData(pos, end, P_STATIC_STRING(": "));
|
805
|
-
pos = appendLStringData(pos, end, &it->header->val);
|
806
|
-
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
807
|
-
}
|
808
|
-
it.next();
|
809
|
-
}
|
810
|
-
}
|
811
|
-
|
812
|
-
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
813
|
-
|
814
|
-
writeResponse(client, header, pos - header);
|
815
|
-
if (!req->ended() && req->method != HTTP_HEAD) {
|
816
|
-
writeResponse(client, body.data(), body.size());
|
817
|
-
}
|
818
|
-
}
|
819
|
-
|
820
|
-
bool endRequest(Client **client, Request **request) {
|
821
|
-
Client *c = *client;
|
822
|
-
Request *req = *request;
|
823
|
-
psg_pool_t *pool;
|
824
|
-
|
825
|
-
*client = NULL;
|
826
|
-
*request = NULL;
|
827
|
-
|
828
|
-
if (req->ended()) {
|
829
|
-
return false;
|
830
|
-
}
|
831
|
-
|
832
|
-
SKC_TRACE(c, 2, "Ending request");
|
833
|
-
assert(c->currentRequest == req);
|
834
|
-
|
835
|
-
if (OXT_UNLIKELY(!req->responseBegun)) {
|
836
|
-
writeDefault500Response(c, req);
|
837
|
-
if (req->ended()) {
|
838
|
-
return false;
|
839
|
-
}
|
840
|
-
}
|
841
|
-
|
842
|
-
// The memory buffers that we're writing out during the
|
843
|
-
// FLUSHING_OUTPUT state might live in the palloc pool,
|
844
|
-
// so we want to deinitialize the request while preserving
|
845
|
-
// the pool. We'll destroy the pool when the output is
|
846
|
-
// flushed.
|
847
|
-
pool = req->pool;
|
848
|
-
req->pool = NULL;
|
849
|
-
deinitializeRequestAndAddToFreelist(c, req);
|
850
|
-
req->pool = pool;
|
851
|
-
|
852
|
-
if (!c->output.ended()) {
|
853
|
-
c->output.feedWithoutRefGuard(MemoryKit::mbuf());
|
854
|
-
}
|
855
|
-
if (c->output.endAcked()) {
|
856
|
-
doneWithCurrentRequest(&c);
|
857
|
-
} else {
|
858
|
-
// Call doneWithCurrentRequest() when data flushed
|
859
|
-
SKC_TRACE(c, 2, "Waiting until output is flushed");
|
860
|
-
req->httpState = Request::FLUSHING_OUTPUT;
|
861
|
-
// If the request body is not fully read at this time,
|
862
|
-
// then ensure that onClientDataReceived() discards any
|
863
|
-
// request body data that we receive from now on.
|
864
|
-
req->wantKeepAlive = canKeepAlive(req);
|
865
|
-
}
|
866
|
-
|
867
|
-
return true;
|
868
|
-
}
|
869
|
-
|
870
|
-
void endAsBadRequest(Client **client, Request **req, const StaticString &body) {
|
871
|
-
endWithErrorResponse(client, req, 400, body);
|
872
|
-
}
|
873
|
-
|
874
|
-
|
875
660
|
/***** Hook overrides *****/
|
876
661
|
|
877
662
|
virtual void onClientObjectCreated(Client *client) {
|
@@ -1079,6 +864,9 @@ public:
|
|
1079
864
|
STAILQ_INIT(&freeRequests);
|
1080
865
|
}
|
1081
866
|
|
867
|
+
|
868
|
+
/***** Server management *****/
|
869
|
+
|
1082
870
|
virtual void compact(int logLevel = LVL_NOTICE) {
|
1083
871
|
ParentClass::compact();
|
1084
872
|
unsigned int count = freeRequestCount;
|
@@ -1100,6 +888,220 @@ public:
|
|
1100
888
|
"Freed " << count << " spare request objects");
|
1101
889
|
}
|
1102
890
|
|
891
|
+
|
892
|
+
/***** Request manipulation *****/
|
893
|
+
|
894
|
+
/** Increase request reference count. */
|
895
|
+
void refRequest(Request *req, const char *file, unsigned int line) {
|
896
|
+
int oldRefcount = req->refcount.fetch_add(1, boost::memory_order_relaxed);
|
897
|
+
SKC_TRACE_WITH_POS(static_cast<Client *>(req->client), 3, file, line,
|
898
|
+
"Request refcount increased; it is now " << (oldRefcount + 1));
|
899
|
+
}
|
900
|
+
|
901
|
+
/** Decrease request reference count. Adds request to the
|
902
|
+
* freelist if reference count drops to 0.
|
903
|
+
*/
|
904
|
+
void unrefRequest(Request *req, const char *file, unsigned int line) {
|
905
|
+
int oldRefcount = req->refcount.fetch_sub(1, boost::memory_order_release);
|
906
|
+
assert(oldRefcount >= 1);
|
907
|
+
|
908
|
+
SKC_TRACE_WITH_POS(static_cast<Client *>(req->client), 3, file, line,
|
909
|
+
"Request refcount decreased; it is now " << (oldRefcount - 1));
|
910
|
+
if (oldRefcount == 1) {
|
911
|
+
boost::atomic_thread_fence(boost::memory_order_acquire);
|
912
|
+
|
913
|
+
if (this->getContext()->libev->onEventLoopThread()) {
|
914
|
+
requestReachedZeroRefcount(req);
|
915
|
+
} else {
|
916
|
+
// Let the event loop handle the request reaching the 0 refcount.
|
917
|
+
passRequestToEventLoopThread(req);
|
918
|
+
}
|
919
|
+
}
|
920
|
+
}
|
921
|
+
|
922
|
+
bool canKeepAlive(Request *req) const {
|
923
|
+
return req->wantKeepAlive
|
924
|
+
&& req->bodyFullyRead()
|
925
|
+
&& HttpServer::serverState < HttpServer::SHUTTING_DOWN;
|
926
|
+
}
|
927
|
+
|
928
|
+
void writeResponse(Client *client, const MemoryKit::mbuf &buffer) {
|
929
|
+
client->currentRequest->responseBegun = true;
|
930
|
+
client->output.feedWithoutRefGuard(buffer);
|
931
|
+
}
|
932
|
+
|
933
|
+
void writeResponse(Client *client, const char *data, unsigned int size) {
|
934
|
+
writeResponse(client, MemoryKit::mbuf(data, size));
|
935
|
+
}
|
936
|
+
|
937
|
+
void writeResponse(Client *client, const StaticString &data) {
|
938
|
+
writeResponse(client, data.data(), data.size());
|
939
|
+
}
|
940
|
+
|
941
|
+
void
|
942
|
+
writeSimpleResponse(Client *client, int code, const HeaderTable *headers,
|
943
|
+
const StaticString &body)
|
944
|
+
{
|
945
|
+
unsigned int headerBufSize = 300;
|
946
|
+
|
947
|
+
if (headers != NULL) {
|
948
|
+
HeaderTable::ConstIterator it(*headers);
|
949
|
+
while (*it != NULL) {
|
950
|
+
headerBufSize += it->header->key.size + sizeof(": ") - 1;
|
951
|
+
headerBufSize += it->header->val.size + sizeof("\r\n") - 1;
|
952
|
+
it.next();
|
953
|
+
}
|
954
|
+
}
|
955
|
+
|
956
|
+
Request *req = client->currentRequest;
|
957
|
+
char *header = (char *) psg_pnalloc(req->pool, headerBufSize);
|
958
|
+
char statusBuffer[50];
|
959
|
+
char *pos = header;
|
960
|
+
const char *end = header + headerBufSize;
|
961
|
+
const char *status;
|
962
|
+
const LString *value;
|
963
|
+
|
964
|
+
status = getStatusCodeAndReasonPhrase(code);
|
965
|
+
if (status == NULL) {
|
966
|
+
snprintf(statusBuffer, sizeof(statusBuffer), "%d Unknown Reason-Phrase", code);
|
967
|
+
status = statusBuffer;
|
968
|
+
}
|
969
|
+
|
970
|
+
pos += snprintf(pos, end - pos,
|
971
|
+
"HTTP/%d.%d %s\r\n"
|
972
|
+
"Status: %s\r\n",
|
973
|
+
(int) req->httpMajor, (int) req->httpMinor, status, status);
|
974
|
+
|
975
|
+
value = (headers != NULL) ? headers->lookup(P_STATIC_STRING("content-type")) : NULL;
|
976
|
+
if (value == NULL) {
|
977
|
+
pos = appendData(pos, end, P_STATIC_STRING("Content-Type: text/html; charset=UTF-8\r\n"));
|
978
|
+
} else {
|
979
|
+
pos = appendData(pos, end, P_STATIC_STRING("Content-Type: "));
|
980
|
+
pos = appendLStringData(pos, end, value);
|
981
|
+
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
982
|
+
}
|
983
|
+
|
984
|
+
value = (headers != NULL) ? headers->lookup(P_STATIC_STRING("date")) : NULL;
|
985
|
+
pos = appendData(pos, end, P_STATIC_STRING("Date: "));
|
986
|
+
if (value == NULL) {
|
987
|
+
time_t the_time = time(NULL);
|
988
|
+
struct tm the_tm;
|
989
|
+
gmtime_r(&the_time, &the_tm);
|
990
|
+
pos += strftime(pos, end - pos, "%a, %d %b %Y %H:%M:%S %z", &the_tm);
|
991
|
+
} else {
|
992
|
+
pos = appendLStringData(pos, end, value);
|
993
|
+
}
|
994
|
+
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
995
|
+
|
996
|
+
value = (headers != NULL) ? headers->lookup(P_STATIC_STRING("connection")) : NULL;
|
997
|
+
if (value == NULL) {
|
998
|
+
if (canKeepAlive(req)) {
|
999
|
+
pos = appendData(pos, end, P_STATIC_STRING("Connection: keep-alive\r\n"));
|
1000
|
+
} else {
|
1001
|
+
pos = appendData(pos, end, P_STATIC_STRING("Connection: close\r\n"));
|
1002
|
+
}
|
1003
|
+
} else {
|
1004
|
+
pos = appendData(pos, end, P_STATIC_STRING("Connection: "));
|
1005
|
+
pos = appendLStringData(pos, end, value);
|
1006
|
+
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
1007
|
+
if (!psg_lstr_cmp(value, P_STATIC_STRING("Keep-Alive"))
|
1008
|
+
&& !psg_lstr_cmp(value, P_STATIC_STRING("keep-alive")))
|
1009
|
+
{
|
1010
|
+
req->wantKeepAlive = false;
|
1011
|
+
}
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
value = (headers != NULL) ? headers->lookup(P_STATIC_STRING("content-length")) : NULL;
|
1015
|
+
pos = appendData(pos, end, P_STATIC_STRING("Content-Length: "));
|
1016
|
+
if (value == NULL) {
|
1017
|
+
pos += snprintf(pos, end - pos, "%u", (unsigned int) body.size());
|
1018
|
+
} else {
|
1019
|
+
pos = appendLStringData(pos, end, value);
|
1020
|
+
}
|
1021
|
+
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
1022
|
+
|
1023
|
+
if (headers != NULL) {
|
1024
|
+
HeaderTable::ConstIterator it(*headers);
|
1025
|
+
while (*it != NULL) {
|
1026
|
+
if (!psg_lstr_cmp(&it->header->key, P_STATIC_STRING("content-type"))
|
1027
|
+
&& !psg_lstr_cmp(&it->header->key, P_STATIC_STRING("date"))
|
1028
|
+
&& !psg_lstr_cmp(&it->header->key, P_STATIC_STRING("connection"))
|
1029
|
+
&& !psg_lstr_cmp(&it->header->key, P_STATIC_STRING("content-length")))
|
1030
|
+
{
|
1031
|
+
pos = appendLStringData(pos, end, &it->header->origKey);
|
1032
|
+
pos = appendData(pos, end, P_STATIC_STRING(": "));
|
1033
|
+
pos = appendLStringData(pos, end, &it->header->val);
|
1034
|
+
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
1035
|
+
}
|
1036
|
+
it.next();
|
1037
|
+
}
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
pos = appendData(pos, end, P_STATIC_STRING("\r\n"));
|
1041
|
+
|
1042
|
+
writeResponse(client, header, pos - header);
|
1043
|
+
if (!req->ended() && req->method != HTTP_HEAD) {
|
1044
|
+
writeResponse(client, body.data(), body.size());
|
1045
|
+
}
|
1046
|
+
}
|
1047
|
+
|
1048
|
+
bool endRequest(Client **client, Request **request) {
|
1049
|
+
Client *c = *client;
|
1050
|
+
Request *req = *request;
|
1051
|
+
psg_pool_t *pool;
|
1052
|
+
|
1053
|
+
*client = NULL;
|
1054
|
+
*request = NULL;
|
1055
|
+
|
1056
|
+
if (req->ended()) {
|
1057
|
+
return false;
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
SKC_TRACE(c, 2, "Ending request");
|
1061
|
+
assert(c->currentRequest == req);
|
1062
|
+
|
1063
|
+
if (OXT_UNLIKELY(!req->responseBegun)) {
|
1064
|
+
writeDefault500Response(c, req);
|
1065
|
+
if (req->ended()) {
|
1066
|
+
return false;
|
1067
|
+
}
|
1068
|
+
}
|
1069
|
+
|
1070
|
+
// The memory buffers that we're writing out during the
|
1071
|
+
// FLUSHING_OUTPUT state might live in the palloc pool,
|
1072
|
+
// so we want to deinitialize the request while preserving
|
1073
|
+
// the pool. We'll destroy the pool when the output is
|
1074
|
+
// flushed.
|
1075
|
+
pool = req->pool;
|
1076
|
+
req->pool = NULL;
|
1077
|
+
deinitializeRequestAndAddToFreelist(c, req);
|
1078
|
+
req->pool = pool;
|
1079
|
+
|
1080
|
+
if (!c->output.ended()) {
|
1081
|
+
c->output.feedWithoutRefGuard(MemoryKit::mbuf());
|
1082
|
+
}
|
1083
|
+
if (c->output.endAcked()) {
|
1084
|
+
doneWithCurrentRequest(&c);
|
1085
|
+
} else {
|
1086
|
+
// Call doneWithCurrentRequest() when data flushed
|
1087
|
+
SKC_TRACE(c, 2, "Waiting until output is flushed");
|
1088
|
+
req->httpState = Request::FLUSHING_OUTPUT;
|
1089
|
+
// If the request body is not fully read at this time,
|
1090
|
+
// then ensure that onClientDataReceived() discards any
|
1091
|
+
// request body data that we receive from now on.
|
1092
|
+
req->wantKeepAlive = canKeepAlive(req);
|
1093
|
+
}
|
1094
|
+
|
1095
|
+
return true;
|
1096
|
+
}
|
1097
|
+
|
1098
|
+
void endAsBadRequest(Client **client, Request **req, const StaticString &body) {
|
1099
|
+
endWithErrorResponse(client, req, 400, body);
|
1100
|
+
}
|
1101
|
+
|
1102
|
+
|
1103
|
+
/***** Configuration and introspection *****/
|
1104
|
+
|
1103
1105
|
virtual void configure(const Json::Value &doc) {
|
1104
1106
|
ParentClass::configure(doc);
|
1105
1107
|
if (doc.isMember("request_freelist_limit")) {
|
@@ -1184,6 +1186,14 @@ public:
|
|
1184
1186
|
return doc;
|
1185
1187
|
}
|
1186
1188
|
|
1189
|
+
|
1190
|
+
/***** Miscellaneous *****/
|
1191
|
+
|
1192
|
+
object_pool<HttpHeaderParserState> &getHeaderParserStatePool() {
|
1193
|
+
return headerParserStatePool;
|
1194
|
+
}
|
1195
|
+
|
1196
|
+
|
1187
1197
|
/***** Friend-public methods and hook implementations *****/
|
1188
1198
|
|
1189
1199
|
void _refRequest(Request *request, const char *file, unsigned int line) {
|