Hoa central
Responder.php
Go to the documentation of this file.
1 <?php
2 
37 namespace Hoa\Fastcgi;
38 
39 use Hoa\Socket;
40 
50 class Responder extends Connection
51 {
57  const REQUEST_BEGIN = 1;
58 
64  const REQUEST_ABORD = 2;
65 
71  const REQUEST_END = 3;
72 
78  const REQUEST_PARAMETERS = 4;
79 
85  const STREAM_STDIN = 5;
86 
92  const STREAM_STDOUT = 6;
93 
99  const STREAM_STDERR = 7;
100 
106  const STATUS_COMPLETE = 0;
107 
116 
123  const STATUS_OVERLOADED = 2;
124 
132 
138  protected $_client = null;
139 
145  protected $_content = null;
146 
152  protected $_headers = [];
153 
154 
155 
162  public function __construct(Socket\Client $client)
163  {
164  $this->setClient($client);
165 
166  return;
167  }
168 
181  public function send(Array $headers, $content = null)
182  {
183  $client = $this->getClient();
184  $client->connect();
185  $client->setStreamBlocking(true);
186 
187  $parameters = null;
188  $response = null;
189  $request = $this->pack(
190  self::REQUEST_BEGIN,
191  // ┌───────────────────┐
192  // │ “I'm a responder” │
193  // └─────────⌵─────────┘
194  chr(0) . chr(1) . chr((int) $client->isPersistent()) .
195  chr(0) . chr(0) . chr(0) . chr(0) . chr(0)
196  );
197 
198  $parameters .= $this->packPairs($headers);
199 
200  if (null !== $parameters) {
201  $request .= $this->pack(self::REQUEST_PARAMETERS, $parameters);
202  }
203 
204  $request .= $this->pack(self::REQUEST_PARAMETERS, '');
205 
206  if (null !== $content) {
207  $request .= $this->pack(self::STREAM_STDIN, $content);
208  }
209 
210  $request .= $this->pack(self::STREAM_STDIN, '');
211  $client->writeAll($request);
212  $handle = null;
213 
214  do {
215  if (false === $handle = $this->readPack()) {
216  throw new Exception(
217  'Bad request (not a well-formed FastCGI request).',
218  0
219  );
220  }
221 
222  if (self::STREAM_STDOUT === $handle[parent::HEADER_TYPE] ||
223  self::STREAM_STDERR === $handle[parent::HEADER_TYPE]) {
224  $response .= $handle[parent::HEADER_CONTENT];
225  }
226  } while (self::REQUEST_END !== $handle[parent::HEADER_TYPE]);
227 
228  $client->disconnect();
229 
230  switch (ord($handle[parent::HEADER_CONTENT][4])) {
231  case self::STATUS_CANNOT_MULTIPLEX:
232  throw new Exception\CannotMultiplex(
233  'Application %s that you are trying to reach does not ' .
234  'support multiplexing.',
235  0,
236  $this->getClient()->getSocket()->__toString()
237  );
238 
239  break;
240 
241  case self::STATUS_OVERLOADED:
242  throw new Exception\Overloaded(
243  'Application %s is too busy and rejects your request.',
244  1,
245  $this->getClient()->getSocket()->__toString()
246  );
247 
248  break;
249 
250  case self::STATUS_UNKNOWN_ROLE:
251  throw new Exception\UnknownRole(
252  'Server for the application %s returns an unknown role.',
253  2,
254  $this->getClient()->getSocket()->__toString()
255  );
256 
257  break;
258  }
259 
265  $pos = strpos($response, "\r\n\r\n");
266  $headers = substr($response, 0, $pos);
267 
268  foreach (explode("\r\n", $headers) as $header) {
269  $semicolon = strpos($header, ':');
270  $this->_headers[strtolower(trim(substr($header, 0, $semicolon)))]
271  = trim(substr($header, $semicolon + 1));
272  }
273 
274  return $this->_content = substr($response, $pos + 4);
275  }
276 
282  public function getResponseContent()
283  {
284  return $this->_content;
285  }
286 
292  public function getResponseHeaders()
293  {
294  return $this->_headers;
295  }
296 
303  protected function read($length)
304  {
305  return $this->getClient()->read($length);
306  }
307 
314  public function setClient(Socket\Client $client)
315  {
316  $old = $this->_client;
317  $this->_client = $client;
318 
319  return $old;
320  }
321 
327  public function getClient()
328  {
329  return $this->_client;
330  }
331 }
pack($type, $content, $id=1)
Definition: Connection.php:111
send(Array $headers, $content=null)
Definition: Responder.php:181
setClient(Socket\Client $client)
Definition: Responder.php:314
$content
Definition: Hoa.php:119
packPairs(Array $pairs)
Definition: Connection.php:133
__construct(Socket\Client $client)
Definition: Responder.php:162