[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class DiffusionSSHMercurialWireClientProtocolChannel 4 extends PhutilProtocolChannel { 5 6 private $buffer = ''; 7 private $state = 'command'; 8 private $expectArgumentCount; 9 private $argumentName; 10 private $expectBytes; 11 private $command; 12 private $arguments; 13 private $raw; 14 15 protected function encodeMessage($message) { 16 return $message; 17 } 18 19 private function initializeState($last_command = null) { 20 if ($last_command == 'unbundle') { 21 $this->command = '<raw-data>'; 22 $this->state = 'data-length'; 23 } else { 24 $this->state = 'command'; 25 } 26 $this->expectArgumentCount = null; 27 $this->expectBytes = null; 28 $this->command = null; 29 $this->argumentName = null; 30 $this->arguments = array(); 31 $this->raw = ''; 32 } 33 34 private function readProtocolLine() { 35 $pos = strpos($this->buffer, "\n"); 36 37 if ($pos === false) { 38 return null; 39 } 40 41 $line = substr($this->buffer, 0, $pos); 42 43 $this->raw .= $line."\n"; 44 $this->buffer = substr($this->buffer, $pos + 1); 45 46 return $line; 47 } 48 49 private function readProtocolBytes() { 50 if (strlen($this->buffer) < $this->expectBytes) { 51 return null; 52 } 53 54 $bytes = substr($this->buffer, 0, $this->expectBytes); 55 $this->raw .= $bytes; 56 $this->buffer = substr($this->buffer, $this->expectBytes); 57 58 return $bytes; 59 } 60 61 private function newMessageAndResetState() { 62 $message = array( 63 'command' => $this->command, 64 'arguments' => $this->arguments, 65 'raw' => $this->raw, 66 ); 67 $this->initializeState($this->command); 68 return $message; 69 } 70 71 private function newDataMessage($bytes) { 72 $message = array( 73 'command' => '<raw-data>', 74 'raw' => strlen($bytes)."\n".$bytes, 75 ); 76 return $message; 77 } 78 79 protected function decodeStream($data) { 80 $this->buffer .= $data; 81 82 $out = array(); 83 $messages = array(); 84 85 while (true) { 86 if ($this->state == 'command') { 87 $this->initializeState(); 88 89 // We're reading a command. It looks like: 90 // 91 // <command> 92 93 $line = $this->readProtocolLine(); 94 if ($line === null) { 95 break; 96 } 97 98 $this->command = $line; 99 $this->state = 'arguments'; 100 } else if ($this->state == 'arguments') { 101 102 // Check if we're still waiting for arguments. 103 $args = DiffusionMercurialWireProtocol::getCommandArgs($this->command); 104 $have = array_select_keys($this->arguments, $args); 105 if (count($have) == count($args)) { 106 // We have all the arguments. Emit a message and read the next 107 // command. 108 $messages[] = $this->newMessageAndResetState(); 109 } else { 110 // We're still reading arguments. They can either look like: 111 // 112 // <name> <length(value)> 113 // <value> 114 // ... 115 // 116 // ...or like this: 117 // 118 // * <count> 119 // <name1> <length(value1)> 120 // <value1> 121 // ... 122 123 $line = $this->readProtocolLine(); 124 if ($line === null) { 125 break; 126 } 127 128 list($arg, $size) = explode(' ', $line, 2); 129 $size = (int)$size; 130 131 if ($arg != '*') { 132 $this->expectBytes = $size; 133 $this->argumentName = $arg; 134 $this->state = 'value'; 135 } else { 136 $this->arguments['*'] = array(); 137 $this->expectArgumentCount = $size; 138 $this->state = 'argv'; 139 } 140 } 141 } else if ($this->state == 'value' || $this->state == 'argv-value') { 142 143 // We're reading the value of an argument. We just need to wait for 144 // the right number of bytes to show up. 145 146 $bytes = $this->readProtocolBytes(); 147 if ($bytes === null) { 148 break; 149 } 150 151 if ($this->state == 'argv-value') { 152 $this->arguments['*'][$this->argumentName] = $bytes; 153 $this->state = 'argv'; 154 } else { 155 $this->arguments[$this->argumentName] = $bytes; 156 $this->state = 'arguments'; 157 } 158 159 160 } else if ($this->state == 'argv') { 161 162 // We're reading a variable number of arguments. We need to wait for 163 // the arguments to arrive. 164 165 if ($this->expectArgumentCount) { 166 $line = $this->readProtocolLine(); 167 if ($line === null) { 168 break; 169 } 170 171 list($arg, $size) = explode(' ', $line, 2); 172 $size = (int)$size; 173 174 $this->expectBytes = $size; 175 $this->argumentName = $arg; 176 $this->state = 'argv-value'; 177 178 $this->expectArgumentCount--; 179 } else { 180 $this->state = 'arguments'; 181 } 182 } else if ($this->state == 'data-length') { 183 $line = $this->readProtocolLine(); 184 if ($line === null) { 185 break; 186 } 187 $this->expectBytes = (int)$line; 188 if (!$this->expectBytes) { 189 $messages[] = $this->newDataMessage(''); 190 $this->initializeState(); 191 } else { 192 $this->state = 'data-bytes'; 193 } 194 } else if ($this->state == 'data-bytes') { 195 $bytes = substr($this->buffer, 0, $this->expectBytes); 196 $this->buffer = substr($this->buffer, strlen($bytes)); 197 $this->expectBytes -= strlen($bytes); 198 199 $messages[] = $this->newDataMessage($bytes); 200 201 if (!$this->expectBytes) { 202 // We've finished reading this chunk, so go read the next chunk. 203 $this->state = 'data-length'; 204 } else { 205 // We're waiting for more data, and have read everything available 206 // to us so far. 207 break; 208 } 209 } else { 210 throw new Exception("Bad parser state '{$this->state}'!"); 211 } 212 } 213 214 return $messages; 215 } 216 217 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |