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.

Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +20 -0
  3. data/CONTRIBUTORS +1 -0
  4. data/build/cxx_dependency_map.rb +7338 -7104
  5. data/build/cxx_tests.rb +3 -3
  6. data/build/misc.rb +1 -0
  7. data/dev/index_cxx_dependencies.rb +3 -2
  8. data/resources/templates/standalone/config.erb +1 -1
  9. data/resources/templates/standalone/http.erb +1 -0
  10. data/resources/templates/standalone/server.erb +1 -0
  11. data/src/agent/Core/ApplicationPool/AbstractSession.h +83 -0
  12. data/src/agent/Core/ApplicationPool/Common.h +6 -4
  13. data/src/agent/Core/ApplicationPool/Options.h +4 -1
  14. data/src/agent/Core/ApplicationPool/Pool.h +2 -2
  15. data/src/agent/Core/ApplicationPool/Pool/AnalyticsCollection.cpp +3 -6
  16. data/src/agent/Core/ApplicationPool/Pool/GeneralUtils.cpp +3 -3
  17. data/src/agent/Core/ApplicationPool/Session.h +15 -27
  18. data/src/agent/Core/ApplicationPool/TestSession.h +188 -0
  19. data/src/agent/Core/Controller.h +15 -6
  20. data/src/agent/Core/Controller/CheckoutSession.cpp +13 -5
  21. data/src/agent/Core/Controller/ForwardResponse.cpp +20 -2
  22. data/src/agent/Core/Controller/Hooks.cpp +15 -2
  23. data/src/agent/Core/Controller/InitRequest.cpp +5 -1
  24. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +1 -0
  25. data/src/agent/Core/Controller/Request.h +11 -4
  26. data/src/agent/Core/Controller/SendRequest.cpp +34 -13
  27. data/src/agent/Core/Controller/StateInspectionAndConfiguration.cpp +2 -2
  28. data/src/agent/Core/CoreMain.cpp +27 -1
  29. data/src/agent/Core/OptionParser.h +11 -1
  30. data/src/agent/Core/SpawningKit/DirectSpawner.h +1 -0
  31. data/src/agent/Core/SpawningKit/SmartSpawner.h +1 -0
  32. data/src/agent/Core/SpawningKit/Spawner.h +21 -1
  33. data/src/agent/SpawnPreparer/SpawnPreparerMain.cpp +1 -1
  34. data/src/agent/UstRouter/OptionParser.h +7 -1
  35. data/src/agent/UstRouter/UstRouterMain.cpp +27 -1
  36. data/src/cxx_supportlib/Algorithms/MovingAverage.h +223 -0
  37. data/src/cxx_supportlib/Constants.h +2 -2
  38. data/src/cxx_supportlib/DataStructures/StringKeyTable.h +96 -40
  39. data/src/cxx_supportlib/ResourceLocator.h +33 -14
  40. data/src/cxx_supportlib/ServerKit/Channel.h +198 -69
  41. data/src/cxx_supportlib/ServerKit/Errors.h +6 -1
  42. data/src/cxx_supportlib/ServerKit/HttpRequest.h +20 -1
  43. data/src/cxx_supportlib/ServerKit/HttpServer.h +124 -32
  44. data/src/cxx_supportlib/ServerKit/Server.h +65 -1
  45. data/src/cxx_supportlib/Utils/IOUtils.cpp +12 -22
  46. data/src/cxx_supportlib/Utils/JsonUtils.h +87 -1
  47. data/src/cxx_supportlib/Utils/StrIntUtils.cpp +16 -1
  48. data/src/cxx_supportlib/Utils/StrIntUtils.h +31 -1
  49. data/src/cxx_supportlib/Utils/VariantMap.h +6 -1
  50. data/src/cxx_supportlib/WatchdogLauncher.h +17 -9
  51. data/src/cxx_supportlib/vendor-copy/libuv/AUTHORS +43 -0
  52. data/src/cxx_supportlib/vendor-copy/libuv/ChangeLog +350 -1
  53. data/src/cxx_supportlib/vendor-copy/libuv/Makefile.am +9 -1
  54. data/src/cxx_supportlib/vendor-copy/libuv/README.md +48 -0
  55. data/src/cxx_supportlib/vendor-copy/libuv/checksparse.sh +1 -0
  56. data/src/cxx_supportlib/vendor-copy/libuv/common.gypi +5 -5
  57. data/src/cxx_supportlib/vendor-copy/libuv/configure.ac +2 -1
  58. data/src/cxx_supportlib/vendor-copy/libuv/gyp_uv.py +0 -3
  59. data/src/cxx_supportlib/vendor-copy/libuv/include/uv-version.h +5 -1
  60. data/src/cxx_supportlib/vendor-copy/libuv/include/uv.h +30 -3
  61. data/src/cxx_supportlib/vendor-copy/libuv/src/fs-poll.c +3 -3
  62. data/src/cxx_supportlib/vendor-copy/libuv/src/inet.c +0 -4
  63. data/src/cxx_supportlib/vendor-copy/libuv/src/queue.h +17 -1
  64. data/src/cxx_supportlib/vendor-copy/libuv/src/threadpool.c +10 -10
  65. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/aix.c +84 -166
  66. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/android-ifaddrs.c +11 -11
  67. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/async.c +7 -1
  68. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/atomic-ops.h +17 -0
  69. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/core.c +140 -21
  70. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/darwin.c +15 -11
  71. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/dl.c +4 -7
  72. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/freebsd.c +52 -37
  73. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fs.c +181 -60
  74. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fsevents.c +39 -34
  75. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/getaddrinfo.c +4 -4
  76. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/internal.h +3 -1
  77. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/kqueue.c +12 -4
  78. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-core.c +38 -15
  79. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-inotify.c +36 -8
  80. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.c +4 -4
  81. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.h +2 -2
  82. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop-watcher.c +6 -1
  83. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop.c +28 -8
  84. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/netbsd.c +18 -16
  85. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/openbsd.c +18 -16
  86. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pipe.c +3 -3
  87. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/process.c +18 -6
  88. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/proctitle.c +2 -2
  89. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pthread-fixes.c +1 -0
  90. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/signal.c +2 -0
  91. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/stream.c +47 -30
  92. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/sunos.c +13 -11
  93. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tcp.c +43 -8
  94. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/thread.c +21 -15
  95. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tty.c +16 -2
  96. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/udp.c +54 -14
  97. data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.c +104 -21
  98. data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.h +14 -1
  99. data/src/cxx_supportlib/vendor-copy/libuv/src/version.c +1 -5
  100. data/src/cxx_supportlib/vendor-copy/libuv/uv.gyp +22 -1
  101. data/src/nginx_module/CacheLocationConfig.c +52 -0
  102. data/src/nginx_module/CacheLocationConfig.c.erb +13 -1
  103. data/src/nginx_module/Configuration.c +1 -0
  104. data/src/nginx_module/Configuration.h +1 -0
  105. data/src/nginx_module/ConfigurationCommands.c +20 -0
  106. data/src/nginx_module/ConfigurationFields.h +4 -0
  107. data/src/nginx_module/CreateLocationConfig.c +8 -0
  108. data/src/nginx_module/MergeLocationConfig.c +12 -0
  109. data/src/nginx_module/config +31 -13
  110. data/src/nginx_module/ngx_http_passenger_module.c +4 -0
  111. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  112. data/src/ruby_supportlib/phusion_passenger/constants.rb +1 -1
  113. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +11 -1
  114. data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +6 -1
  115. data/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb +32 -31
  116. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +13 -2
  117. data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -0
  118. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +6 -1
  119. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +6 -0
  120. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +29 -19
  121. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/context.rb +2 -2
  122. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter.rb +2 -3
  123. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/simple_json.rb +2 -1
  124. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/spec_helper.rb +2 -0
  125. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/time_point.rb +3 -17
  126. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/transaction.rb +7 -10
  127. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/utils.rb +11 -9
  128. metadata +5 -2
@@ -60,6 +60,7 @@ private:
60
60
  string docDir;
61
61
  string rubyLibDir;
62
62
  string nodeLibDir;
63
+ string buildSystemDir;
63
64
 
64
65
  static string getOption(const string &file, const IniFileSectionPtr &section, const string &key) {
65
66
  if (section->hasKey(key)) {
@@ -69,13 +70,20 @@ private:
69
70
  }
70
71
  }
71
72
 
73
+ static string getOptionalSection(const string &file, const IniFileSectionPtr &section, const string &key) {
74
+ if (section->hasKey(key)) {
75
+ return section->get(key);
76
+ } else {
77
+ return string();
78
+ }
79
+ }
80
+
72
81
  public:
73
82
  ResourceLocator() { }
74
83
 
75
- ResourceLocator(const string &rootOrFile) {
76
- root = rootOrFile;
77
- if (getFileType(rootOrFile) == FT_REGULAR) {
78
- string file = rootOrFile;
84
+ ResourceLocator(const string &installSpec) {
85
+ if (getFileType(installSpec) == FT_REGULAR) {
86
+ const string &file = installSpec;
79
87
  IniFileSectionPtr options = IniFile(file).section("locations");
80
88
  binDir = getOption(file, options, "bin_dir");
81
89
  supportBinariesDir = getOption(file, options, "support_binaries_dir");
@@ -84,8 +92,9 @@ public:
84
92
  docDir = getOption(file, options, "doc_dir");
85
93
  rubyLibDir = getOption(file, options, "ruby_libdir");
86
94
  nodeLibDir = getOption(file, options, "node_libdir");
95
+ buildSystemDir = getOptionalSection(file, options, "node_libdir");
87
96
  } else {
88
- string root = rootOrFile;
97
+ const string &root = installSpec;
89
98
  binDir = root + "/bin";
90
99
  supportBinariesDir = root + "/buildout/support-binaries";
91
100
  helperScriptsDir = root + "/src/helper-scripts";
@@ -93,14 +102,19 @@ public:
93
102
  docDir = root + "/doc";
94
103
  rubyLibDir = root + "/src/ruby_supportlib";
95
104
  nodeLibDir = root + "/src/nodejs_supportlib";
105
+ buildSystemDir = root;
96
106
  }
97
107
  }
98
108
 
99
- string getRoot() const {
109
+ const string &getRoot() const {
100
110
  return root;
101
111
  }
102
112
 
103
- string getSupportBinariesDir() const {
113
+ const string &getBinDir() const {
114
+ return binDir;
115
+ }
116
+
117
+ const string &getSupportBinariesDir() const {
104
118
  return supportBinariesDir;
105
119
  }
106
120
 
@@ -132,27 +146,31 @@ public:
132
146
  return result;
133
147
  }
134
148
 
135
- string getHelperScriptsDir() const {
149
+ const string &getHelperScriptsDir() const {
136
150
  return helperScriptsDir;
137
151
  }
138
152
 
139
- string getResourcesDir() const {
153
+ const string &getResourcesDir() const {
140
154
  return resourcesDir;
141
155
  }
142
156
 
143
- string getDocDir() const {
157
+ const string &getDocDir() const {
144
158
  return docDir;
145
159
  }
146
160
 
147
- // Can be empty.
148
- string getRubyLibDir() const {
161
+ const string &getRubyLibDir() const {
149
162
  return rubyLibDir;
150
163
  }
151
164
 
152
- string getNodeLibDir() const {
165
+ const string &getNodeLibDir() const {
153
166
  return nodeLibDir;
154
167
  }
155
168
 
169
+ // Can be empty.
170
+ const string &getBuildSystemDir() const {
171
+ return buildSystemDir;
172
+ }
173
+
156
174
  string findSupportBinary(const string &name) {
157
175
  string path = getSupportBinariesDir() + "/" + name;
158
176
  bool found;
@@ -170,7 +188,8 @@ public:
170
188
  return path;
171
189
  }
172
190
 
173
- throw RuntimeException("Support binary " + name + " not found (tried: " + getSupportBinariesDir() + "/" + name + " and " + path + ")");
191
+ throw RuntimeException("Support binary " + name + " not found (tried: "
192
+ + getSupportBinariesDir() + "/" + name + " and " + path + ")");
174
193
  }
175
194
  };
176
195
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2014 Phusion Holding B.V.
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.
@@ -58,8 +58,20 @@ using namespace boost;
58
58
  *
59
59
  * Writing all this code is complicated, error-prone, its flow is hard to test (because
60
60
  * it depends on network conditions), and it's ridden with boilerplate. The Channel class
61
- * solves this problem with a nice abstraction. First, you attach a data callback to a
62
- * Channel. Whatever is written to the Channel, will be forwarded to the data callback.
61
+ * solves this problem with a nice abstraction. A Channel is used in combination with a
62
+ * callback. Channel allows you to:
63
+ *
64
+ * - Pass data to the callback, which can consume the data at its own pace.
65
+ * - Be notified when the data has fully consumed by the callback.
66
+ * - Be notified when the callback is refusing to consume further data (e.g. because
67
+ * it is done consuming or because it has encountered an error).
68
+ * - Pass error conditions to the callback.
69
+ *
70
+ *
71
+ * ## Typical usage
72
+ *
73
+ * First, you attach a data callback to a Channel. Whatever is written to the Channel
74
+ * will be forwarded to the data callback.
63
75
  *
64
76
  * The data callback can consume the buffer immediately, and tell Channel how many bytes
65
77
  * it has consumed, and whether it accepts any further data, by returning a Channel::Result.
@@ -131,11 +143,21 @@ using namespace boost;
131
143
  * {
132
144
  * if (buffer.size() > 0) {
133
145
  * int bytesProcessed;
146
+ * int errcode;
134
147
  * bool acceptFurtherData;
135
148
  *
136
149
  * ...process buffer....
137
150
  *
138
- * return Channel::Result(bytesProcessed, !acceptFurtherData);
151
+ * if (errcode == 0) {
152
+ * // Everything OK.
153
+ * return Channel::Result(bytesProcessed, !acceptFurtherData);
154
+ * } else {
155
+ * // An error occurred.
156
+ * feedError(errcode);
157
+ * // If you called feedError() then it doesn't matter what
158
+ * // you return.
159
+ * return Channel::Result(0, false);
160
+ * }
139
161
  * } else if (errcode == 0) {
140
162
  * // EOF reached. Result doesn't matter in this case.
141
163
  * return Channel::Result(0, false);
@@ -146,12 +168,66 @@ using namespace boost;
146
168
  * }
147
169
  * }
148
170
  *
149
- * A good example of this is FdInputChannel. It reads data from a file descriptor using
171
+ * ### Recommended example: FdSourceChannel
172
+ *
173
+ * A good example is FdSourceChannel. It reads data from a file descriptor using
150
174
  * `read()`, then writes them to a Channel. It stops reading from the file descriptor
151
175
  * when the Channel is not accepting reads, and it starts reading from the file
152
176
  * descriptor when the channel is accepting reads again.
153
177
  *
154
- * ## Asynchronous consumption
178
+ *
179
+ * ## The data callback
180
+ *
181
+ * The data callback is called when the Channel wants to pass data to the callback,
182
+ * or when the channel wants to notify the callback of an error.
183
+ *
184
+ * ### Arguments
185
+ *
186
+ * - `channel` -- the Channel object that called it.
187
+ * - `buffer` -- a buffer containing data. This buffer may be empty because
188
+ * the writer called `channel.feed()` with an empty buffer, or because of
189
+ * an error.
190
+ * - `error` -- an error code. A value of 0 means that there is no error. All
191
+ * other values indicate an error.
192
+ *
193
+ * If an error occurred then the buffer is always empty. If the buffer is non-empty
194
+ * then errcode is always zero.
195
+ *
196
+ * Be sure to check for errors correctly: you may only use `buffer` if `errcode` is 0.
197
+ *
198
+ * ### Returning consumption result
199
+ *
200
+ * The data callback is to return a `Channel::Result` object in order to tell Channel
201
+ * how many bytes have been consumed (the `consumed` field), and whether it accepts
202
+ * further data (the `end` field).
203
+ *
204
+ * Returning `end == true` will set the Channel to the "end acknowledged" state. This
205
+ * causes the Channel to stop accepting and/or forwarding further data or error to the
206
+ * callback (even if there is pending unconsumed data). The writer can detect this state
207
+ * by calling:
208
+ *
209
+ * - `channel.acceptingInput()` -- will return false.
210
+ * - `channel.mayAcceptInputLater()` -- will return false.
211
+ * - `channel.ended()` -- will return true.
212
+ * - `channel.endAcked()` -- will return true.
213
+ * - `channel.hasError()` -- will return false.
214
+ *
215
+ * ### Returning error result
216
+ *
217
+ * The data callback can tell the Channel that an error during consumption has occurred
218
+ * by calling `channel.feedError()` with a non-zero error code. Once `feedError()` has
219
+ * been called, it doesn't matter what the data callback returns: anything is fine.
220
+ * The Channel will enter the "end acknowledged with error" state and/or will stop
221
+ * forwarding further data or error to the callback (even if there is pending unconsumed
222
+ * data). The writer will observe:
223
+ *
224
+ * - `channel.acceptingInput()` -- will return false.
225
+ * - `channel.mayAcceptInputLater()` -- will return false.
226
+ * - `channel.ended()` -- will return true.
227
+ * - `channel.endAcked()` -- will return true.
228
+ * - `channel.hasError()` -- will return true.
229
+ *
230
+ * ### Asynchronous consumption
155
231
  *
156
232
  * The data callback can also tell Channel that it wants to consume the buffer
157
233
  * *asynchronously*, by returning a Channel::Result with a negative consumption size.
@@ -159,7 +235,22 @@ using namespace boost;
159
235
  * by calling `channel.consumed()`. Until that happens, the Channel will tell the
160
236
  * writer that it is not accepting any new data, so that the writer can stop writing
161
237
  * temporarily. When the buffer is consumed, the Channel notifies the writer about
162
- * this so that it can continue writing.
238
+ * this (via `consumedCallback`) so that it can continue writing.
239
+ *
240
+ * The arguments passed to `channel.consumed()` are the same as those used to create
241
+ * a `Channel::Result`. The `size` arguments tells Channel how many bytes have been
242
+ * consumed. The `end` argument tells whether the callback is done consuming.
243
+ *
244
+ * If Channel has no further pending data to be passed to the callback, then Channel
245
+ * immediately calls `consumedCallback`. Otherwise, Channel will pass the remaining
246
+ * data in the next event loop iteration.
247
+ *
248
+ * ### Asynchronous consumption error reporting
249
+ *
250
+ * If you are using asynchronous consumption (by returning a Channel::Result with a
251
+ * negative consumption size) then the way to signal a consumption error is by calling
252
+ * `channel.feedError()` instead of calling `channel.consumed()`. This will cause the
253
+ * channel to immediately enter the "end acknowledged with error" state.
163
254
  */
164
255
  class Channel: public boost::noncopyable {
165
256
  public:
@@ -232,19 +323,20 @@ public:
232
323
  * An end-of-file or error has been passed to the callback, and we're
233
324
  * now waiting for the callback to return.
234
325
  */
235
- CALLING_WITH_EOF,
326
+ CALLING_WITH_EOF_OR_ERROR,
236
327
 
237
328
  /**
238
329
  * An end-of-file or error has been passed to the callback, but the
239
- * callback hasn't called `consumed()` yet.
330
+ * callback hasn't called `consumed()` yet. We're now waiting for
331
+ * that call.
240
332
  */
241
- EOF_WAITING,
333
+ WAITING_FOR_CALLBACK_WITH_EOF_OR_ERROR,
242
334
 
243
335
  /**
244
336
  * An end-of-file or error has been passed to the callback, and the
245
337
  * callback has returned and completed.
246
338
  */
247
- EOF_REACHED
339
+ EOF_OR_ERROR_ACKNOWLEDGED
248
340
  };
249
341
 
250
342
  protected:
@@ -270,9 +362,9 @@ protected:
270
362
 
271
363
  begin:
272
364
 
273
- assert(state == CALLING || state == CALLING_WITH_EOF);
365
+ assert(state == CALLING || state == CALLING_WITH_EOF_OR_ERROR);
274
366
  assert(state != CALLING || !buffer.empty());
275
- assert(state != CALLING_WITH_EOF || buffer.empty());
367
+ assert(state != CALLING_WITH_EOF_OR_ERROR || buffer.empty());
276
368
 
277
369
  {
278
370
  // Make a copy of the buffer so that if the callback calls
@@ -291,7 +383,7 @@ protected:
291
383
  assert(state != STOPPED);
292
384
  assert(state != STOPPED_WHILE_WAITING);
293
385
  assert(state != PLANNING_TO_CALL);
294
- assert(state != EOF_WAITING);
386
+ assert(state != WAITING_FOR_CALLBACK_WITH_EOF_OR_ERROR);
295
387
 
296
388
  if (cbResult.consumed >= 0) {
297
389
  bytesConsumed += cbResult.consumed;
@@ -305,7 +397,7 @@ protected:
305
397
  switch (state) {
306
398
  case CALLING:
307
399
  if (cbResult.end) {
308
- state = EOF_REACHED;
400
+ state = EOF_OR_ERROR_ACKNOWLEDGED;
309
401
  callConsumedCallback();
310
402
  return bytesConsumed;
311
403
  } else if (buffer.empty()) {
@@ -325,21 +417,20 @@ protected:
325
417
  }
326
418
  case STOPPED_WHILE_CALLING:
327
419
  if (cbResult.end) {
328
- state = EOF_REACHED;
420
+ state = EOF_OR_ERROR_ACKNOWLEDGED;
329
421
  callConsumedCallback();
330
422
  return bytesConsumed;
331
423
  } else {
332
424
  state = STOPPED;
333
425
  return -1;
334
426
  }
335
- case CALLING_WITH_EOF:
336
- state = EOF_REACHED;
427
+ case CALLING_WITH_EOF_OR_ERROR:
428
+ state = EOF_OR_ERROR_ACKNOWLEDGED;
337
429
  callConsumedCallback();
338
430
  return bytesConsumed;
339
- case EOF_REACHED:
431
+ case EOF_OR_ERROR_ACKNOWLEDGED:
340
432
  // feedError() called inside callback, so we
341
433
  // don't callConsumedCallback() here.
342
- state = EOF_REACHED;
343
434
  return bytesConsumed;
344
435
  default:
345
436
  P_BUG("Unknown state" << toString((int) state));
@@ -354,9 +445,9 @@ protected:
354
445
  case STOPPED_WHILE_CALLING:
355
446
  state = STOPPED_WHILE_WAITING;
356
447
  break;
357
- case CALLING_WITH_EOF:
358
- case EOF_REACHED:
359
- state = EOF_WAITING;
448
+ case CALLING_WITH_EOF_OR_ERROR:
449
+ case EOF_OR_ERROR_ACKNOWLEDGED:
450
+ state = WAITING_FOR_CALLBACK_WITH_EOF_OR_ERROR;
360
451
  break;
361
452
  default:
362
453
  P_BUG("Unknown state" << toString((int) state));
@@ -407,7 +498,7 @@ public:
407
498
  * you call `setContext()`.
408
499
  */
409
500
  Channel()
410
- : state(EOF_REACHED),
501
+ : state(EOF_OR_ERROR_ACKNOWLEDGED),
411
502
  planId(0),
412
503
  errcode(0),
413
504
  generation(0),
@@ -473,7 +564,8 @@ public:
473
564
  }
474
565
 
475
566
  /**
476
- * Feed data to the Channel. The data will be passed to the callback.
567
+ * Feed data to the Channel. The data will be passed to the callback. You can signal
568
+ * EOF by feeding an empty buffer.
477
569
  *
478
570
  * @pre acceptingInput()
479
571
  */
@@ -503,7 +595,7 @@ public:
503
595
  P_ASSERT_EQ(state, IDLE);
504
596
  P_ASSERT_EQ(bytesConsumed, 0);
505
597
  if (mbuf.empty()) {
506
- state = CALLING_WITH_EOF;
598
+ state = CALLING_WITH_EOF_OR_ERROR;
507
599
  } else {
508
600
  state = CALLING;
509
601
  }
@@ -514,37 +606,54 @@ public:
514
606
  /**
515
607
  * Tell the Channel that an error has occurred.
516
608
  *
517
- * If this method is called while the data callback is not active, and the
518
- * channel is idle, then the error will be passed to the callback immediately.
519
- * Otherwise (if the channel isn't idle), it will be passed to the callback
520
- * when the channel becomes idle.
609
+ * This method can be called with two purposes. You can either use it to
610
+ * pass an error to the data callback, or you can use it to register an
611
+ * error that occurred inside the data callback (a consumption error).
612
+ *
613
+ * ## Passing an error to the data callback
614
+ *
615
+ * If you want to pass an error to the data callback then you can only do that
616
+ * when `acceptingInput()` is true. Calling `feedError()` in this state will
617
+ * call the data callback immediately.
618
+ *
619
+ * ## Registering a consumption error
620
+ *
621
+ * The data callback can tell the Channel about a consumption error by calling
622
+ * this method inside the data callback, or (if the data callback is using
623
+ * asynchronous consumption by having returned -1) by calling this method
624
+ * in place of `consumed()`.
521
625
  *
522
- * If this method is called inside the data callback, or (if the data callback returned -1)
523
- * when the data callback hasn't called `consumed()` yet, then the channel transitions
524
- * to the end state immediately, and stops calling the data callback even when the
525
- * current invocation of the data callback doesn't fully consume the buffer.
626
+ * ## Effect
526
627
  *
527
- * Once an error has been fed, no more data will be accepted by `feed()`.
628
+ * In both of the above cases, the Channel will begin transitioning to an end error state:
629
+ *
630
+ * acceptingInput() -- will return false.
631
+ * mayAcceptInputLater() -- will return false.
632
+ * ended() -- will return true.
633
+ * endAcked() -- depending on the situation, will return true immediately,
634
+ * or will return true eventually.
635
+ * hasError() -- will return true.
636
+ *
637
+ * No more data will be accepted by `feed()`.
528
638
  */
529
639
  void feedError(int errcode) {
530
640
  assert(errcode != 0);
531
641
  switch (state) {
532
642
  case IDLE:
533
643
  this->errcode = errcode;
534
- state = CALLING_WITH_EOF;
644
+ state = CALLING_WITH_EOF_OR_ERROR;
535
645
  callDataCallback();
536
646
  break;
537
647
  case CALLING:
538
648
  case WAITING_FOR_CALLBACK:
539
- case CALLING_WITH_EOF:
540
- case EOF_WAITING:
649
+ case CALLING_WITH_EOF_OR_ERROR:
650
+ case WAITING_FOR_CALLBACK_WITH_EOF_OR_ERROR:
541
651
  this->errcode = errcode;
542
- state = EOF_REACHED;
652
+ state = EOF_OR_ERROR_ACKNOWLEDGED;
543
653
  callConsumedCallback();
544
654
  break;
545
- case EOF_REACHED:
655
+ case EOF_OR_ERROR_ACKNOWLEDGED:
546
656
  this->errcode = errcode;
547
- state = EOF_REACHED;
548
657
  break;
549
658
  case STOPPED:
550
659
  case STOPPED_WHILE_CALLING:
@@ -556,7 +665,7 @@ public:
556
665
  ctx->libev->cancelCommand(planId);
557
666
  planId = 0;
558
667
  this->errcode = errcode;
559
- state = EOF_REACHED;
668
+ state = EOF_OR_ERROR_ACKNOWLEDGED;
560
669
  callConsumedCallback();
561
670
  break;
562
671
  default:
@@ -574,9 +683,9 @@ public:
574
683
  case CALLING:
575
684
  case PLANNING_TO_CALL:
576
685
  case WAITING_FOR_CALLBACK:
577
- case CALLING_WITH_EOF:
578
- case EOF_WAITING:
579
- case EOF_REACHED:
686
+ case CALLING_WITH_EOF_OR_ERROR:
687
+ case WAITING_FOR_CALLBACK_WITH_EOF_OR_ERROR:
688
+ case EOF_OR_ERROR_ACKNOWLEDGED:
580
689
  break;
581
690
  case STOPPED:
582
691
  planNextActivity();
@@ -602,9 +711,9 @@ public:
602
711
  case STOPPED:
603
712
  case STOPPED_WHILE_CALLING:
604
713
  case STOPPED_WHILE_WAITING:
605
- case CALLING_WITH_EOF:
606
- case EOF_WAITING:
607
- case EOF_REACHED:
714
+ case CALLING_WITH_EOF_OR_ERROR:
715
+ case WAITING_FOR_CALLBACK_WITH_EOF_OR_ERROR:
716
+ case EOF_OR_ERROR_ACKNOWLEDGED:
608
717
  break;
609
718
  case IDLE:
610
719
  case PLANNING_TO_CALL:
@@ -636,8 +745,8 @@ public:
636
745
  assert(state != STOPPED);
637
746
  assert(state != STOPPED_WHILE_CALLING);
638
747
  assert(state != PLANNING_TO_CALL);
639
- assert(state != CALLING_WITH_EOF);
640
- assert(state != EOF_REACHED);
748
+ assert(state != CALLING_WITH_EOF_OR_ERROR);
749
+ assert(state != EOF_OR_ERROR_ACKNOWLEDGED);
641
750
 
642
751
  size = std::min<unsigned int>(size, buffer.size());
643
752
  bytesConsumed += size;
@@ -651,7 +760,7 @@ public:
651
760
  switch (state) {
652
761
  case WAITING_FOR_CALLBACK:
653
762
  if (end) {
654
- state = EOF_REACHED;
763
+ state = EOF_OR_ERROR_ACKNOWLEDGED;
655
764
  callConsumedCallback();
656
765
  } else {
657
766
  planNextActivity();
@@ -659,14 +768,14 @@ public:
659
768
  break;
660
769
  case STOPPED_WHILE_WAITING:
661
770
  if (end) {
662
- state = EOF_REACHED;
771
+ state = EOF_OR_ERROR_ACKNOWLEDGED;
663
772
  callConsumedCallback();
664
773
  } else {
665
774
  state = STOPPED;
666
775
  }
667
776
  break;
668
- case EOF_WAITING:
669
- state = EOF_REACHED;
777
+ case WAITING_FOR_CALLBACK_WITH_EOF_OR_ERROR:
778
+ state = EOF_OR_ERROR_ACKNOWLEDGED;
670
779
  callConsumedCallback();
671
780
  break;
672
781
  default:
@@ -693,10 +802,13 @@ public:
693
802
  * Returns whether this Channel accepts more input right now.
694
803
  * There are three reasons why this might not be the case:
695
804
  *
696
- * 1. The callback isn't done yet.
697
- * 2. EOF has been fed, or the data callback has ended consumption.
698
- * Use `ended()` to check for this.
699
- * 3. An error had been fed. Use `hasError()` to check for this.
805
+ * 1. The callback isn't done yet, or the callback is done but the Channel
806
+ * isn't done updating internal book keeping yet. Use `mayAcceptInputLater()`
807
+ * to check for this.
808
+ * 2. EOF has been fed (by passing an empty buffer to `feed()`), or the data callback
809
+ * has ended consumption (by returning a Channel::Result with end == true, or by calling
810
+ * consumed() with end == true). Use `ended()` to check for this.
811
+ * 3. An error had been fed (using `feedError()`). Use `hasError()` to check for this.
700
812
  */
701
813
  OXT_FORCE_INLINE
702
814
  bool acceptingInput() const {
@@ -705,9 +817,9 @@ public:
705
817
 
706
818
  /**
707
819
  * Returns whether this Channel's callback is currently processing the
708
- * fed data, and is not accepting any more input now, but may accept
709
- * more input later. You should wait for that event by setting
710
- * `consumedCallback`.
820
+ * fed data, and is not accepting any more input now. However, no EOF or
821
+ * error has been reported so far, so it may accept more input later. You
822
+ * should wait for that event by setting `consumedCallback`.
711
823
  */
712
824
  bool mayAcceptInputLater() const {
713
825
  // Branchless code
@@ -715,9 +827,15 @@ public:
715
827
  }
716
828
 
717
829
  /**
718
- * Returns whether an error flag has been set. Note that this does not
719
- * necessarily mean that the callback has consumed the error yet.
720
- * Use `hasError() && endAcked()` to check for that.
830
+ * Returns whether an error flag has been set. This happens if `feedError()`
831
+ * was called.
832
+ *
833
+ * `hasError()` always implies `end()`.
834
+ *
835
+ * Note that `hasError()` does not necessarily mean that the callback has
836
+ * consumed the error yet. The callback may be called at a later time to
837
+ * notify it about the error. When the callback is done consuming the error,
838
+ * `hasError() && endAcked()` will be true.
721
839
  */
722
840
  OXT_FORCE_INLINE
723
841
  bool hasError() const {
@@ -730,17 +848,28 @@ public:
730
848
  }
731
849
 
732
850
  /**
733
- * Returns whether the EOF flag has been set. Note that this does not
734
- * necessarily mean that the callback has consumed the EOF yet.
735
- * Use `endAcked()` to check for that.
851
+ * Returns whether the EOF flag has been set. This happens if `feed()` was
852
+ * called with an empty buffer.
853
+ *
854
+ * Note that this does not necessarily mean that the callback has consumed
855
+ * the EOF yet. The callback may be called at a later time to notify it about
856
+ * the EOF event. When the callback is done consuming the EOF event, `endAcked()`
857
+ * will be true.
736
858
  */
737
859
  bool ended() const {
738
- return state == CALLING_WITH_EOF || state == EOF_WAITING || state == EOF_REACHED;
860
+ return state == CALLING_WITH_EOF_OR_ERROR
861
+ || state == WAITING_FOR_CALLBACK_WITH_EOF_OR_ERROR
862
+ || state == EOF_OR_ERROR_ACKNOWLEDGED;
739
863
  }
740
864
 
865
+ /**
866
+ * Returns whether the data callback has consumed an EOF event.
867
+ *
868
+ * `endAcked()` always implies `ended()`.
869
+ */
741
870
  OXT_FORCE_INLINE
742
871
  bool endAcked() const {
743
- return state == EOF_REACHED;
872
+ return state == EOF_OR_ERROR_ACKNOWLEDGED;
744
873
  }
745
874
 
746
875
  Json::Value inspectAsJson() const {