Skip to content

Commit

Permalink
Merge pull request #32 from Timo-Linde/master
Browse files Browse the repository at this point in the history
Fill the Symfony Response with real responded headers
  • Loading branch information
TobiasHauck committed May 23, 2016
2 parents bbf7997 + 87e2dce commit 6e503d2
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 5 deletions.
53 changes: 53 additions & 0 deletions Parsers/HTTPHeadersParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
/**
* This file is part of CircleRestClientBundle.
*
* CircleRestClientBundle is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CircleRestClientBundle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CircleRestClientBundle. If not, see <http://www.gnu.org/licenses/>.
*/

namespace Circle\RestClientBundle\Parsers;


/**
* Gets the HTTP Headers from a string
*
* @author Timo Linde <[email protected]>
* @copyright 2016 TeeAge-Beatz UG
*/
class HTTPHeadersParser {
/**
* Parse Http Headers in array
*
* @param string $headers
* @return array
*/
public static function parse($headers) {
$fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $headers));

if(empty($fields)) return [];

return array_reduce($fields, function($carry, $field) {
$match = [];
if (!preg_match('/([^:]+): (.+)/m', $field, $match)) return $carry;

$match[1] = preg_replace_callback('/(?<=^|[\x09\x20\x2D])./',function($matches) {
return strtoupper($matches[0]);
}, strtolower(trim($match[1])));

$carry[$match[1]] = isset($carry[$match[1]]) ? [$carry[$match[1]], $match[2]] : trim($match[2]);

return $carry;
}, []);
}
}
17 changes: 12 additions & 5 deletions Services/Curl.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Symfony\Component\HttpFoundation\Response;
use Circle\RestClientBundle\Traits\Exceptions;
use Circle\RestClientBundle\Traits\Assertions;
use Circle\RestClientBundle\Types\ResponseHeaders;

/**
* Sends curl requests
Expand Down Expand Up @@ -85,19 +86,24 @@ public function sendRequest($url, $method, array $options = array(), $payload =

$this->curlOptionsHandler->setOptions($options);
$this->curlOptionsHandler->setOption(CURLOPT_RETURNTRANSFER, true);
$this->curlOptionsHandler->setOption(CURLOPT_HEADER, true);

$this->setUrl($url);
$this->setMethod($method);
$this->setPayload($payload);
curl_setopt_array($this->curl, $this->curlOptionsHandler->getOptions());

$curlResponse = $this->execute();
$headerSize = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
$headers = ResponseHeaders::create($curlResponse, $headerSize);
$content = substr($curlResponse, $headerSize);
$content = empty($content) ? '' : $content;
$curlMetaData = (object) curl_getinfo($this->curl);

$this->curlOptionsHandler->reset();
function_exists('curl_reset') ? curl_reset($this->curl) : curl_setopt_array($this->curl, $this->curlOptionsHandler->getOptions());

return $this->createResponse($curlResponse, $curlMetaData);
return $this->createResponse($content, $headers, $curlMetaData);
}

/**
Expand All @@ -122,16 +128,17 @@ private function execute() {
*
* @SuppressWarnings("PHPMD.StaticAccess");
*
* @param string $curlResponse
* @param string $content
* @param array $headers
* @param \stdClass $curlMetaData
*
* @return Response
*/
private function createResponse($curlResponse, \stdClass $curlMetaData) {
private function createResponse($content, $headers, \stdClass $curlMetaData) {
$response = new Response();
$response->setContent($curlResponse);
$response->setContent($content);
$response->headers->add($headers);
$response->setStatusCode($curlMetaData->http_code);
$response->headers->set('Content-Type', $curlMetaData->content_type);

return $response;
}
Expand Down
90 changes: 90 additions & 0 deletions Tests/Functional/Parsers/HTTPHeadersParserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php
/**
* This file is part of CircleRestClientBundle.
*
* CircleRestClientBundle is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CircleRestClientBundle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CircleRestClientBundle. If not, see <http://www.gnu.org/licenses/>.
*/

namespace Circle\RestClientBundle\Tests\Functional\Parsers;

use Circle\RestClientBundle\Parsers\HTTPHeadersParser;

/**
* Tests the HTTPHeadersParser class
*
* @author Timo Linde <[email protected]>
* @copyright 2016 TeeAge-Beatz UG
*
* @coversDefaultClass Circle\RestClientBundle\Parsers\HTTPHeadersParser
*
* @SuppressWarnings("PHPMD.StaticAccess")
*/
class ResponseHeadersTest extends \PHPUnit_Framework_TestCase {

/**
* @test
* @covers ::parse
*/
public function testParse() {
$headers = "HTTP/1.1 302 Found\r\n".
"Date: Tue, 21 Apr 2015 13:57:48 GMT\r\n".
"Server: Apache/2.2.22 (Debian)\r\n".
"Location: https://test.de\r\n".
"Vary: Accept-Encoding\r\n".
"Content-Length: 284\r\n".
"Content-Type: text/html; charset=iso-8859-1\r\n";

$parsedHeader = HTTPHeadersParser::parse($headers);
$this->assertArrayHasKey('Date', $parsedHeader);
$this->assertArrayHasKey('Server', $parsedHeader);
$this->assertArrayHasKey('Location', $parsedHeader);
$this->assertArrayHasKey('Vary', $parsedHeader);
$this->assertArrayHasKey('Content-Length', $parsedHeader);
$this->assertArrayHasKey('Content-Type', $parsedHeader);
$this->assertEquals("Tue, 21 Apr 2015 13:57:48 GMT", $parsedHeader["Date"]);
$this->assertEquals("Apache/2.2.22 (Debian)", $parsedHeader["Server"]);
$this->assertEquals("https://test.de", $parsedHeader["Location"]);
$this->assertEquals("Accept-Encoding", $parsedHeader["Vary"]);
$this->assertEquals("284", $parsedHeader["Content-Length"]);
$this->assertEquals("text/html; charset=iso-8859-1", $parsedHeader["Content-Type"]);
}

/**
* @test
* @covers ::parse
*/
public function testParseCookie() {
$headers = "Set-Cookie: foo=bar\r\n".
"Set-Cookie: baz=quux\r\n";
$returnValue = HTTPHeadersParser::parse($headers);
$this->assertTrue(is_array($returnValue));

$this->assertTrue(isset($returnValue['Set-Cookie']));
$this->assertTrue(is_array($returnValue['Set-Cookie']));
$this->assertEquals(count($returnValue['Set-Cookie']), 2);
}

/**
* @test
* @covers ::parse
*/
public function testParseFolded() {
$headers = "Folded: works\r\n\ttoo\r\n";
$returnValue = HTTPHeadersParser::parse($headers);
$this->assertTrue(is_array($returnValue));

$this->assertTrue(isset($returnValue['Folded']));
$this->assertEquals($returnValue['Folded'], "works too");
}
}
64 changes: 64 additions & 0 deletions Tests/Functional/Types/ResponseHeadersTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php
/**
* This file is part of CircleRestClientBundle.
*
* CircleRestClientBundle is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CircleRestClientBundle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CircleRestClientBundle. If not, see <http://www.gnu.org/licenses/>.
*/

namespace Circle\RestClientBundle\Tests\Functional\Types;

use Circle\RestClientBundle\Types\ResponseHeaders;

/**
* Tests the response headers class
*
* @author Timo Linde <[email protected]>
* @copyright 2016 TeeAge-Beatz UG
*
* @coversDefaultClass Circle\RestClientBundle\Types\ResponseHeaders
*
* @SuppressWarnings("PHPMD.StaticAccess")
*/
class ResponseHeadersTest extends \PHPUnit_Framework_TestCase {

/**
* @test
* @covers ::create
*/
public function testCreate() {
$content = "HTTP/1.1 302 Found\r\n".
"Date: Tue, 21 Apr 2015 13:57:48 GMT\r\n".
"Server: Apache/2.2.22 (Debian)\r\n".
"Location: https://test.de\r\n".
"Vary: Accept-Encoding\r\n".
"Content-Length: 284\r\n".
"Content-Type: text/html; charset=iso-8859-1\r\n";
$headerSize = strlen($content);
$content .= "Some Body";

$parsedHeader = ResponseHeaders::create($content, $headerSize);
$this->assertArrayHasKey('Date', $parsedHeader);
$this->assertArrayHasKey('Server', $parsedHeader);
$this->assertArrayHasKey('Location', $parsedHeader);
$this->assertArrayHasKey('Vary', $parsedHeader);
$this->assertArrayHasKey('Content-Length', $parsedHeader);
$this->assertArrayHasKey('Content-Type', $parsedHeader);
$this->assertEquals("Tue, 21 Apr 2015 13:57:48 GMT", $parsedHeader["Date"]);
$this->assertEquals("Apache/2.2.22 (Debian)", $parsedHeader["Server"]);
$this->assertEquals("https://test.de", $parsedHeader["Location"]);
$this->assertEquals("Accept-Encoding", $parsedHeader["Vary"]);
$this->assertEquals("284", $parsedHeader["Content-Length"]);
$this->assertEquals("text/html; charset=iso-8859-1", $parsedHeader["Content-Type"]);
}
}
43 changes: 43 additions & 0 deletions Types/ResponseHeaders.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* This file is part of CircleRestClientBundle.
*
* CircleRestClientBundle is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CircleRestClientBundle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CircleRestClientBundle. If not, see <http://www.gnu.org/licenses/>.
*/

namespace Circle\RestClientBundle\Types;

use Circle\RestClientBundle\Parsers\HTTPHeadersParser;

/**
* Gets the Response Headers from a Curl Response
*
* @author Timo Linde <[email protected]>
* @copyright 2016 TeeAge-Beatz UG
*/
class ResponseHeaders {
/**
* Creates Header array from a Response string
*
* @see https://pecl.php.net/
* @param string $curlResponse
* @param string $headerSize
* @return array
*/
public static function create($curlResponse, $headerSize) {
$headers = substr($curlResponse, 0, $headerSize);

return function_exists('http_parse_headers') ? http_parse_headers($headers) : HTTPHeadersParser::parse($headers);
}
}

0 comments on commit 6e503d2

Please sign in to comment.