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.

Files changed (106) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/CHANGELOG +15 -0
  5. data/CONTRIBUTORS +6 -0
  6. data/README.md +1 -1
  7. data/bin/passenger-install-apache2-module +24 -11
  8. data/bin/passenger-status +29 -14
  9. data/build/agents.rb +12 -10
  10. data/build/cxx_tests.rb +30 -30
  11. data/doc/Design and Architecture.html +1 -10
  12. data/doc/Design and Architecture.txt +1 -6
  13. data/doc/Users guide Apache.html +1 -19
  14. data/doc/Users guide Apache.txt +1 -1
  15. data/doc/Users guide Nginx.html +2 -20
  16. data/doc/Users guide Nginx.txt +2 -2
  17. data/doc/users_guide_snippets/tips.txt +0 -9
  18. data/ext/common/ApplicationPool2/ApiKey.h +158 -0
  19. data/ext/common/ApplicationPool2/BasicGroupInfo.h +81 -0
  20. data/ext/common/ApplicationPool2/BasicProcessInfo.h +106 -0
  21. data/ext/common/ApplicationPool2/Common.h +5 -44
  22. data/ext/common/ApplicationPool2/Context.h +94 -0
  23. data/ext/common/ApplicationPool2/Group.h +130 -1205
  24. data/ext/common/ApplicationPool2/Group/InitializationAndShutdown.cpp +190 -0
  25. data/ext/common/ApplicationPool2/Group/InternalUtils.cpp +329 -0
  26. data/ext/common/ApplicationPool2/Group/LifetimeAndBasics.cpp +103 -0
  27. data/ext/common/ApplicationPool2/{Pool/Debug.h → Group/Miscellaneous.cpp} +40 -38
  28. data/ext/common/ApplicationPool2/Group/OutOfBandWork.cpp +323 -0
  29. data/ext/common/ApplicationPool2/Group/ProcessListManagement.cpp +606 -0
  30. data/ext/common/ApplicationPool2/Group/SessionManagement.cpp +337 -0
  31. data/ext/common/ApplicationPool2/Group/SpawningAndRestarting.cpp +478 -0
  32. data/ext/common/ApplicationPool2/Group/StateInspection.cpp +197 -0
  33. data/ext/common/ApplicationPool2/Group/Verification.cpp +159 -0
  34. data/ext/common/ApplicationPool2/Implementation.cpp +19 -1401
  35. data/ext/common/ApplicationPool2/Options.h +5 -5
  36. data/ext/common/ApplicationPool2/Pool.h +260 -815
  37. data/ext/common/ApplicationPool2/Pool/{AnalyticsCollection.h → AnalyticsCollection.cpp} +55 -56
  38. data/ext/common/ApplicationPool2/Pool/{GarbageCollection.h → GarbageCollection.cpp} +49 -49
  39. data/ext/common/ApplicationPool2/Pool/GeneralUtils.cpp +241 -0
  40. data/ext/common/ApplicationPool2/Pool/GroupUtils.cpp +276 -0
  41. data/ext/common/ApplicationPool2/Pool/InitializationAndShutdown.cpp +145 -0
  42. data/ext/common/ApplicationPool2/Pool/Miscellaneous.cpp +244 -0
  43. data/ext/common/ApplicationPool2/Pool/ProcessUtils.cpp +330 -0
  44. data/ext/common/ApplicationPool2/Pool/StateInspection.cpp +299 -0
  45. data/ext/common/ApplicationPool2/Process.h +399 -205
  46. data/ext/common/ApplicationPool2/Session.h +70 -28
  47. data/ext/common/ApplicationPool2/Socket.h +1 -0
  48. data/ext/common/Constants.h +11 -3
  49. data/ext/common/Exceptions.h +1 -1
  50. data/ext/common/Logging.cpp +9 -4
  51. data/ext/common/Logging.h +6 -0
  52. data/ext/common/ServerKit/HttpServer.h +225 -215
  53. data/ext/common/ServerKit/Server.h +57 -57
  54. data/ext/common/SpawningKit/BackgroundIOCapturer.h +160 -0
  55. data/ext/common/SpawningKit/Config.h +107 -0
  56. data/ext/common/{ApplicationPool2 → SpawningKit}/DirectSpawner.h +17 -16
  57. data/ext/common/{ApplicationPool2 → SpawningKit}/DummySpawner.h +33 -33
  58. data/ext/common/{ApplicationPool2/SpawnerFactory.h → SpawningKit/Factory.h} +17 -17
  59. data/ext/common/{ApplicationPool2/ComponentInfo.h → SpawningKit/Options.h} +8 -21
  60. data/ext/common/SpawningKit/PipeWatcher.h +148 -0
  61. data/ext/common/{ApplicationPool2/PipeWatcher.h → SpawningKit/Result.h} +15 -33
  62. data/ext/common/{ApplicationPool2 → SpawningKit}/SmartSpawner.h +52 -57
  63. data/ext/common/{ApplicationPool2 → SpawningKit}/Spawner.h +83 -371
  64. data/ext/common/SpawningKit/UserSwitchingRules.h +265 -0
  65. data/ext/common/Utils/BufferedIO.h +24 -0
  66. data/ext/common/{ApplicationPool2/SpawnObject.h → Utils/ClassUtils.h} +24 -51
  67. data/ext/common/Utils/IOUtils.cpp +70 -0
  68. data/ext/common/Utils/IOUtils.h +19 -0
  69. data/ext/common/Utils/JsonUtils.h +113 -0
  70. data/ext/common/Utils/StrIntUtils.h +29 -0
  71. data/ext/common/Utils/json.h +1 -1
  72. data/ext/common/agents/ApiServerUtils.h +941 -0
  73. data/ext/common/agents/HelperAgent/{AdminServer.h → ApiServer.h} +163 -365
  74. data/ext/common/agents/HelperAgent/Main.cpp +86 -88
  75. data/ext/common/agents/HelperAgent/OptionParser.h +9 -10
  76. data/ext/common/agents/HelperAgent/RequestHandler/BufferBody.cpp +3 -0
  77. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +2 -0
  78. data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +1 -1
  79. data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +2 -2
  80. data/ext/common/agents/LoggingAgent/ApiServer.h +279 -0
  81. data/ext/common/agents/LoggingAgent/Main.cpp +41 -51
  82. data/ext/common/agents/LoggingAgent/OptionParser.h +11 -11
  83. data/ext/common/agents/Watchdog/ApiServer.h +311 -0
  84. data/ext/common/agents/Watchdog/Main.cpp +91 -65
  85. data/helper-scripts/prespawn +2 -0
  86. data/lib/phusion_passenger.rb +1 -1
  87. data/lib/phusion_passenger/admin_tools/instance.rb +1 -1
  88. data/lib/phusion_passenger/common_library.rb +27 -14
  89. data/lib/phusion_passenger/config/{admin_command_command.rb → api_call_command.rb} +19 -16
  90. data/lib/phusion_passenger/config/detach_process_command.rb +6 -3
  91. data/lib/phusion_passenger/config/main.rb +3 -5
  92. data/lib/phusion_passenger/config/reopen_logs_command.rb +29 -7
  93. data/lib/phusion_passenger/config/restart_app_command.rb +13 -4
  94. data/lib/phusion_passenger/config/utils.rb +15 -8
  95. data/lib/phusion_passenger/constants.rb +6 -2
  96. data/lib/phusion_passenger/platform_info/apache.rb +4 -0
  97. data/lib/phusion_passenger/platform_info/apache_detector.rb +18 -3
  98. data/resources/templates/apache2/mpm_unknown.txt.erb +20 -0
  99. metadata +42 -21
  100. metadata.gz.asc +7 -7
  101. data/ext/common/ApplicationPool2/Pool/GeneralUtils.h +0 -127
  102. data/ext/common/ApplicationPool2/Pool/Inspection.h +0 -219
  103. data/ext/common/ApplicationPool2/Pool/ProcessUtils.h +0 -85
  104. data/ext/common/ApplicationPool2/SuperGroup.h +0 -706
  105. data/ext/common/agents/LoggingAgent/AdminServer.h +0 -435
  106. 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/Common.h>
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
- * This class can be used outside the ApplicationPool lock, but is not thread-safe,
51
- * and so should only be access through 1 thread.
52
+ * A Session object is created from a Process object.
52
53
  *
53
- * You MUST destroy all Session objects before destroying the Pool, because Session
54
- * objects are stored inside a memory pool inside Pool.
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
- * Backpointers to the Pool, Process and Socket that this Session was made
63
- * from. `pool` is always non-NULL, but `process` and `socket` are only
64
- * non-NULL as long as the Session hasn't been closed. This is because Group
65
- * waits until all sessions are closed before destroying a Process.
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
- Pool * const pool;
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(Pool *_pool, Process *_process, Socket *_socket)
100
- : pool(_pool),
101
- process(_process),
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
- bool isClosed() const {
130
- return closed;
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
- process = NULL;
183
- socket = NULL;
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
  }
@@ -35,6 +35,7 @@
35
35
  #include <Logging.h>
36
36
  #include <StaticString.h>
37
37
  #include <ApplicationPool2/Common.h>
38
+ #include <MemoryKit/palloc.h>
38
39
  #include <Utils/SmallVector.h>
39
40
  #include <Utils/IOUtils.h>
40
41
 
@@ -64,7 +64,7 @@
64
64
 
65
65
  #define DEFAULT_HTTP_SERVER_LISTEN_ADDRESS "tcp://127.0.0.1:3000"
66
66
 
67
- #define DEFAULT_LOGGING_AGENT_ADMIN_LISTEN_ADDRESS "tcp://127.0.0.1:9345"
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.9"
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 0
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
 
@@ -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
- * SuperGroup. Or maybe the request sat in the queue for too long.
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:
@@ -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
- boost::lock_guard<boost::mutex> l(logFileMutex);
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;
@@ -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) {