Page MenuHomePhabricator

D7552.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -373,6 +373,7 @@
'phutil_safe_html' => 'markup/render.php',
'phutil_split_lines' => 'utils/utils.php',
'phutil_tag' => 'markup/render.php',
+ 'phutil_tag_div' => 'markup/render.php',
'phutil_unescape_uri_path_component' => 'markup/render.php',
'phutil_utf8_console_strlen' => 'utils/utf8.php',
'phutil_utf8_convert' => 'utils/utf8.php',
@@ -400,6 +401,7 @@
'vqsprintf' => 'xsprintf/qsprintf.php',
'vqueryfx' => 'xsprintf/queryfx.php',
'vqueryfx_all' => 'xsprintf/queryfx.php',
+ 'vurisprintf' => 'xsprintf/urisprintf.php',
'xhp_parser_node_constants' => 'parser/xhpast/parser_nodes.php',
'xhpast_get_binary_path' => 'parser/xhpast/bin/xhpast_parse.php',
'xhpast_get_build_instructions' => 'parser/xhpast/bin/xhpast_parse.php',
diff --git a/src/channel/PhutilChannel.php b/src/channel/PhutilChannel.php
--- a/src/channel/PhutilChannel.php
+++ b/src/channel/PhutilChannel.php
@@ -231,6 +231,14 @@
/**
+ * Close the channel for writing.
+ *
+ * @return void
+ * @task impl
+ */
+ abstract public function closeWriteChannel();
+
+ /**
* Test if the channel is open for reading.
*
* @return bool True if the channel is open for reading.
diff --git a/src/channel/PhutilChannelChannel.php b/src/channel/PhutilChannelChannel.php
--- a/src/channel/PhutilChannelChannel.php
+++ b/src/channel/PhutilChannelChannel.php
@@ -40,6 +40,10 @@
return $this->channel->isOpen();
}
+ public function closeWriteChannel() {
+ return $this->channel->closeWriteChannel();
+ }
+
public function isOpenForReading() {
return $this->channel->isOpenForReading();
}
diff --git a/src/channel/PhutilExecChannel.php b/src/channel/PhutilExecChannel.php
--- a/src/channel/PhutilExecChannel.php
+++ b/src/channel/PhutilExecChannel.php
@@ -108,6 +108,10 @@
$this->future->write($bytes, $keep_pipe = true);
}
+ public function closeWriteChannel() {
+ $this->future->write('', $keep_pipe = false);
+ }
+
protected function writeBytes($bytes) {
throw new Exception("ExecFuture can not write bytes directly!");
}
diff --git a/src/channel/PhutilProtocolChannel.php b/src/channel/PhutilProtocolChannel.php
--- a/src/channel/PhutilProtocolChannel.php
+++ b/src/channel/PhutilProtocolChannel.php
@@ -121,11 +121,17 @@
* @task wait
*/
public function waitForMessage() {
- while ($this->update()) {
+ while (true) {
+ $is_open = $this->update();
$message = $this->read();
if ($message !== null) {
return $message;
}
+
+ if (!$is_open) {
+ break;
+ }
+
self::waitForAny(array($this));
}
diff --git a/src/channel/PhutilSocketChannel.php b/src/channel/PhutilSocketChannel.php
--- a/src/channel/PhutilSocketChannel.php
+++ b/src/channel/PhutilSocketChannel.php
@@ -173,6 +173,10 @@
}
}
+ public function closeWriteChannel() {
+ $this->closeWriteSocket();
+ }
+
private function closeOneSocket($socket) {
if (!$socket) {
return;
diff --git a/src/channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php b/src/channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php
--- a/src/channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php
+++ b/src/channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php
@@ -26,4 +26,41 @@
"Objects are not the same.");
}
+ public function testCloseSocketWriteChannel() {
+ list($x, $y) = PhutilSocketChannel::newChannelPair();
+ $xp = new PhutilPHPObjectProtocolChannel($x);
+ $yp = new PhutilPHPObjectProtocolChannel($y);
+
+ $yp->closeWriteChannel();
+ $yp->update();
+
+ // NOTE: This test is more broad than the implementation needs to be. A
+ // better test would be to verify that this throws an exception:
+ //
+ // $xp->waitForMessage();
+ //
+ // However, if the test breaks, that method will hang forever instead of
+ // returning, which would be hard to diagnose. Since the current
+ // implementation shuts down the entire channel, just test for that.
+
+ $this->assertEqual(false, $xp->update(), 'Expected channel to close.');
+ }
+
+ public function testCloseExecWriteChannel() {
+ $future = new ExecFuture('cat');
+
+ // If this test breaks, we want to explode, not hang forever.
+ $future->setTimeout(5);
+
+ $exec_channel = new PhutilExecChannel($future);
+ $exec_channel->write("quack");
+ $exec_channel->closeWriteChannel();
+
+ // If `closeWriteChannel()` did what it is supposed to, this will just
+ // echo "quack" and exit with no error code. If the channel did not close,
+ // this will time out after 5 seconds and throw.
+ $future->resolvex();
+ }
+
+
}

File Metadata

Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/nd/oi/qdc5pvilubjyfpoy
Default Alt Text
D7552.diff (4 KB)

Event Timeline