From 69d5a149c0615b11909e4ec587c045976dd2e922 Mon Sep 17 00:00:00 2001 From: Andreas Lutro Date: Thu, 30 Jul 2015 11:51:46 +0200 Subject: [PATCH] refactor to allow http 100 continue. closes #25 --- src/Response.php | 70 ++++++++++++++++--------------------- tests/unit/ResponseTest.php | 19 ++++++++-- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/Response.php b/src/Response.php index 238528f..8bc5cbc 100644 --- a/src/Response.php +++ b/src/Response.php @@ -51,69 +51,58 @@ class Response /** * @param string $body - * @param array $headers + * @param string $headers * @param mixed $info */ public function __construct($body, $headers, $info = array()) { $this->body = $body; $this->info = $info; - if (is_array($headers)) { - $this->headers = $headers; - } else { - $this->headers = static::headerToArray($headers); - } - - if (isset($this->headers['http/1.1'])) { - $this->setCode($this->headers['http/1.1']); - } elseif (isset($this->headers['http/1.0'])) { - $this->setCode($this->headers['http/1.0']); - } + $this->parseHeader($headers); } /** - * Turn a header string into an array. + * Read a header string. * * @param string $header - * - * @return array */ - protected static function headerToArray($header) + protected function parseHeader($header) { - $headerLines = explode("\r\n", $header); + $headerLines = explode("\r\n", trim($header)); $headers = array(); + if (!preg_match('/^HTTP\/\d\.\d [0-9]{3}/', $headerLines[0])) { + throw new \InvalidArgumentException('Invalid response header'); + } + $this->setStatus($headerLines[0]); + unset($headerLines[0]); + foreach ($headerLines as $header) { - $key = null; - $val = null; - $delimiter = strpos($header, ': '); + // skip empty lines + if (!$header) { + continue; + } - if ($delimiter !== false) { - $key = substr($header, 0, $delimiter); - $val = substr($header, $delimiter + 2); - } else { - $delimiter = strpos($header, ' '); - if ($delimiter !== false) { - $key = substr($header, 0, $delimiter); - $val = substr($header, $delimiter + 1); - } + $delimiter = strpos($header, ':'); + if (!$delimiter) { + continue; } - if ($key !== null) { - $key = strtolower($key); - if (isset($headers[$key])) { - if (is_array($headers[$key])) { - $headers[$key][] = $val; - } else { - $headers[$key] = array($headers[$key], $val); - } + $key = trim(strtolower(substr($header, 0, $delimiter))); + $val = ltrim(substr($header, $delimiter + 1)); + + if (isset($headers[$key])) { + if (is_array($headers[$key])) { + $headers[$key][] = $val; } else { - $headers[$key] = $val; + $headers[$key] = array($headers[$key], $val); } + } else { + $headers[$key] = $val; } } - return $headers; + $this->headers = $headers; } /** @@ -121,8 +110,9 @@ protected static function headerToArray($header) * * @param string $code */ - protected function setCode($code) + protected function setStatus($status) { + list(, $code) = explode(' ', $status, 2); $this->statusText = $code; $code = explode(' ', $code); $this->statusCode = (int) $code[0]; diff --git a/tests/unit/ResponseTest.php b/tests/unit/ResponseTest.php index be09075..f0e73f8 100644 --- a/tests/unit/ResponseTest.php +++ b/tests/unit/ResponseTest.php @@ -24,7 +24,7 @@ public function parsesHttpResponseCodeCorrectly() /** @test */ public function parsesHeaderStringCorrectly() { - $header = "Content-Type: text/plain\r\nContent-Length: 0"; + $header = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 0"; $r = $this->makeResponse('', $header); $this->assertEquals('text/plain', $r->getHeader('content-type')); $this->assertEquals('0', $r->getHeader('content-length')); @@ -34,8 +34,23 @@ public function parsesHeaderStringCorrectly() /** @test */ public function duplicateHeadersAreHandled() { - $header = "X-Var: A\r\nX-Var: B\r\nX-Var: C"; + $header = "HTTP/1.1 200 OK\r\nX-Var: A\r\nX-Var: B\r\nX-Var: C"; $r = $this->makeResponse('', $header); $this->assertEquals(array('A', 'B', 'C'), $r->getHeader('X-Var')); } + + /** @test */ + public function httpContinueResponsesAreHandled() + { + $header = "HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK"; + $r = $this->makeResponse('', $header); + $this->assertEquals(100, $r->statusCode); + } + + /** @test */ + public function throwsExceptionIfHeaderDoesntStartWithHttpStatus() + { + $this->setExpectedException('InvalidArgumentException', 'Invalid response header'); + $this->makeResponse('', 'x-var: foo'); + } }