Skip to content
This repository was archived by the owner on Jan 30, 2020. It is now read-only.

Handle 100 continue responses proposal #131

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions src/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace Zend\Http;

use Zend\Http\Exception\RuntimeException;
use Zend\Stdlib\ErrorHandler;
use Zend\Stdlib\ResponseInterface;

Expand Down Expand Up @@ -189,20 +190,18 @@ public static function fromString($string)
$firstLine = array_shift($lines);

$response = new static();
$response->parseStatusLine($firstLine);

$regex = '/^HTTP\/(?P<version>1\.[01]) (?P<status>\d{3})(?:[ ]+(?P<reason>.*))?$/';
$matches = [];
if (! preg_match($regex, $firstLine, $matches)) {
throw new Exception\InvalidArgumentException(
'A valid response status line was not found in the provided string'
);
/**
* @link https://tools.ietf.org/html/rfc7231#section-6.2.1
*/
if ($response->statusCode === static::STATUS_CODE_100) {
$next = array_shift($lines); // take next line
$next = !empty($next) ? $next : array_shift($lines); // take next or skip if empty
$response->parseStatusLine($next);
}

$response->version = $matches['version'];
$response->setStatusCode($matches['status']);
$response->setReasonPhrase((isset($matches['reason']) ? $matches['reason'] : ''));

if (empty($lines)) {
if (count($lines) === 0) {
return $response;
}

Expand Down Expand Up @@ -243,6 +242,26 @@ public static function fromString($string)
return $response;
}

/**
* @param string $line
* @throws Exception\InvalidArgumentException
* @throws Exception\RuntimeException
*/
protected function parseStatusLine($line)
{
$regex = '/^HTTP\/(?P<version>1\.[01]) (?P<status>\d{3})(?:[ ]+(?P<reason>.*))?$/';
$matches = [];
if (! preg_match($regex, $line, $matches)) {
throw new Exception\InvalidArgumentException(
'A valid response status line was not found in the provided string'
);
}

$this->version = $matches['version'];
$this->setStatusCode($matches['status']);
$this->setReasonPhrase((isset($matches['reason']) ? $matches['reason'] : ''));
}

/**
* @return Header\SetCookie[]
*/
Expand Down
16 changes: 6 additions & 10 deletions test/Client/CurlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ public function testConfigSetAsZendConfig()
*/
public function testSetConfigInvalidConfig($config)
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Array or Traversable object expected');
$this->setExpectedException(InvalidArgumentException::class, 'Array or Traversable object expected');

$this->_adapter->setOptions($config);
}
Expand All @@ -129,8 +128,7 @@ public function testSettingInvalidCurlOption()
];
$this->client = new Client($this->client->getUri(true), $config);

$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Unknown or erroreous cURL option');
$this->setExpectedException(RuntimeException::class, 'Unknown or erroreous cURL option');
$this->client->send();
}

Expand Down Expand Up @@ -176,9 +174,8 @@ public function testRedirectPostToGetWithCurlFollowLocationOptionLeadsToTimeout(
$this->client->setParameterGet(['swallow' => 'african']);
$this->client->setParameterPost(['Camelot' => 'A silly place']);
$this->client->setMethod('POST');
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage(
'Error in cURL request: Operation timed out after 1000 milliseconds with 0 bytes received'
$this->setExpectedException(
RuntimeException::class, 'Error in cURL request: Operation timed out after 1000 milliseconds with 0 bytes received'
);
$this->client->send();
}
Expand Down Expand Up @@ -239,15 +236,14 @@ public function testPutFileHandleWithHttpClient()
public function testWritingAndNotConnectedWithCurlHandleThrowsException()
{
$adapter = new Adapter\Curl();
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Trying to write but we are not connected');
$this->setExpectedException(RuntimeException::class, 'Trying to write but we are not connected');
$adapter->write('GET', 'someUri');
}

public function testSetConfigIsNotArray()
{
$adapter = new Adapter\Curl();
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
$adapter->setOptions('foo');
}

Expand Down
9 changes: 5 additions & 4 deletions test/Client/SocketTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ public function testConfigSetAsZendConfig()
*/
public function testSetConfigInvalidConfig($config)
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Array or Zend\Config object expected');
$this->setExpectedException(InvalidArgumentException::class, 'Array or Zend\Config object expected');

$this->_adapter->setOptions($config);
}
Expand Down Expand Up @@ -225,8 +224,10 @@ public function testSetNewStreamContextOptions()
*/
public function testSetInvalidContextOptions($invalid)
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Expecting either a stream context resource or array');
$this->setExpectedException(
InvalidArgumentException::class,
'Expecting either a stream context resource or array'
);

$adapterClass = $this->config['adapter'];
$adapter = new $adapterClass();
Expand Down
30 changes: 16 additions & 14 deletions test/Client/StaticTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,10 @@ public function testGetHeader()
*/
public function testExceptUnsupportedAuthDynamic()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid or not supported authentication type: \'SuperStrongAlgo\'');
$this->setExpectedException(
InvalidArgumentException::class,
'Invalid or not supported authentication type: \'SuperStrongAlgo\''
);

$this->_client->setAuth('shahar', '1234', 'SuperStrongAlgo');
}
Expand Down Expand Up @@ -200,8 +202,10 @@ public function testUnsetCookies()
*/
public function testSetInvalidCookies()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid parameter type passed as Cookie');
$this->setExpectedException(
InvalidArgumentException::class,
'Invalid parameter type passed as Cookie'
);

$this->_client->addCookie('cookie');
}
Expand Down Expand Up @@ -259,8 +263,7 @@ public function testConfigSetAsZendConfig()
*/
public function testConfigSetInvalid($config)
{
$this->expectException(ClientException\InvalidArgumentException::class);
$this->expectExceptionMessage('Config parameter is not valid');
$this->setExpectedException(ClientException\InvalidArgumentException::class, 'Config parameter is not valid');

$this->_client->setOptions($config);
}
Expand Down Expand Up @@ -345,8 +348,7 @@ public function testInvalidPostContentType()
HTTPClient::class
));
}
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Cannot handle content type \'x-foo/something-fake\' automatically');
$this->setExpectedException(RuntimeException::class, 'Cannot handle content type \'x-foo/something-fake\' automatically');

$this->_client->setEncType('x-foo/something-fake');
$this->_client->setParameterPost(['parameter' => 'value']);
Expand All @@ -366,8 +368,10 @@ public function testSocketErrorException()
HTTPClient::class
));
}
$this->expectException(ClientAdapterException\RuntimeException::class);
$this->expectExceptionMessage('Unable to connect to 255.255.255.255:80');
$this->setExpectedException(
ClientAdapterException\RuntimeException::class,
'Unable to connect to 255.255.255.255:80'
);

// Try to connect to an invalid host
$this->_client->setUri('http://255.255.255.255');
Expand All @@ -389,8 +393,7 @@ public function testSocketErrorException()
*/
public function testSettingInvalidMethodThrowsException($method)
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid HTTP method passed');
$this->setExpectedException(InvalidArgumentException::class, 'Invalid HTTP method passed');

$this->_client->setMethod($method);
}
Expand Down Expand Up @@ -522,8 +525,7 @@ public function testOpenTempStreamWithBogusFileClosesTheConnection()
$client = new HTTPClient($url, $config);
$client->setMethod('GET');

$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Could not open temp file /path/to/bogus/file.ext');
$this->setExpectedException(RuntimeException::class, 'Could not open temp file /path/to/bogus/file.ext');
$client->send();
}

Expand Down
3 changes: 1 addition & 2 deletions test/Client/TestAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ public function tearDown()
*/
public function testSetConfigThrowsOnInvalidConfig()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Array or Traversable object expected');
$this->setExpectedException(InvalidArgumentException::class, 'Array or Traversable object expected');

$this->adapter->setOptions('foo');
}
Expand Down
9 changes: 5 additions & 4 deletions test/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ public function testIfNullValueCookiesThrowsException()
{
$client = new Client();

$this->expectException(HttpException\InvalidArgumentException::class);
$this->setExpectedException(HttpException\InvalidArgumentException::class);

$client->addCookie('test', null);
}

Expand Down Expand Up @@ -217,13 +218,13 @@ public function testEncodeAuthHeaderWorksAsExpected()

public function testEncodeAuthHeaderThrowsExceptionWhenUsernameContainsSemiColon()
{
$this->expectException(ClientException\InvalidArgumentException::class);
$this->setExpectedException(ClientException\InvalidArgumentException::class);
Client::encodeAuthHeader('test:', 'test');
}

public function testEncodeAuthHeaderThrowsExceptionWhenInvalidAuthTypeIsUsed()
{
$this->expectException(ClientException\InvalidArgumentException::class);
$this->setExpectedException(ClientException\InvalidArgumentException::class);
Client::encodeAuthHeader('test', 'test', 'test');
}

Expand Down Expand Up @@ -453,7 +454,7 @@ public function testHttpQueryParametersCastToString()
{
$client = new Client();

$adapter = $this->createMock(AdapterInterface::class);
$adapter = $this->getMock(AdapterInterface::class);

$client->setAdapter($adapter);

Expand Down
5 changes: 2 additions & 3 deletions test/Header/AcceptCharsetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public function testWildcharCharset()
*/
public function testPreventsCRLFAttackViaFromString()
{
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
AcceptCharset::fromString("Accept-Charset: iso-8859-5\r\n\r\nevilContent");
}

Expand All @@ -105,8 +105,7 @@ public function testPreventsCRLFAttackViaFromString()
public function testPreventsCRLFAttackViaSetters()
{
$header = new AcceptCharset();
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('valid type');
$this->setExpectedException(InvalidArgumentException::class, 'valid type');
$header->addCharset("\niso\r-8859-\r\n5");
}
}
5 changes: 2 additions & 3 deletions test/Header/AcceptEncodingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public function testWildcharEncoder()
*/
public function testPreventsCRLFAttackViaFromString()
{
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
$header = AcceptEncoding::fromString("Accept-Encoding: compress\r\n\r\nevilContent");
}

Expand All @@ -106,8 +106,7 @@ public function testPreventsCRLFAttackViaFromString()
public function testPreventsCRLFAttackViaSetters()
{
$header = new AcceptEncoding();
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('valid type');
$this->setExpectedException(InvalidArgumentException::class, 'valid type');

$header->addEncoding("\nc\rom\r\npress");
}
Expand Down
5 changes: 2 additions & 3 deletions test/Header/AcceptLanguageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public function testWildcards()
*/
public function testPreventsCRLFAttackViaFromString()
{
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
$header = AcceptLanguage::fromString("Accept-Language: da\r\n\r\nevilContent");
}

Expand All @@ -122,8 +122,7 @@ public function testPreventsCRLFAttackViaFromString()
public function testPreventsCRLFAttackViaSetters()
{
$header = new AcceptLanguage();
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('valid type');
$this->setExpectedException(InvalidArgumentException::class, 'valid type');

$header->addLanguage("\nen\r-\r\nus");
}
Expand Down
4 changes: 2 additions & 2 deletions test/Header/AcceptRangesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function testAcceptRangesToStringReturnsHeaderFormattedString()
*/
public function testPreventsCRLFAttackViaFromString()
{
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
$header = AcceptRanges::fromString("Accept-Ranges: bytes;\r\n\r\nevilContent");
}

Expand All @@ -61,7 +61,7 @@ public function testPreventsCRLFAttackViaFromString()
*/
public function testPreventsCRLFAttackViaConstructor()
{
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
$header = new AcceptRanges("bytes;\r\n\r\nevilContent");
}
}
6 changes: 3 additions & 3 deletions test/Header/AcceptTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AcceptTest extends TestCase
{
public function testInvalidHeaderLine()
{
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
Accept::fromString('');
}

Expand Down Expand Up @@ -60,7 +60,7 @@ public function testAcceptToStringReturnsHeaderFormattedString()
$acceptHeader->toString()
);

$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
$acceptHeader->addMediaType('\\', 0.9);
}

Expand Down Expand Up @@ -464,7 +464,7 @@ public function testWildcardDefaults()
*/
public function testPreventsCRLFAttackViaFromString()
{
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
Accept::fromString("Accept: application/text\r\n\r\nevilContent");
}

Expand Down
4 changes: 2 additions & 2 deletions test/Header/AgeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function testAgeCorrectsDeltaSecondsOverflow()
*/
public function testPreventsCRLFAttackViaFromString()
{
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
$header = Age::fromString("Age: 100\r\n\r\nevilContent");
}

Expand All @@ -65,7 +65,7 @@ public function testPreventsCRLFAttackViaFromString()
*/
public function testPreventsCRLFAttackViaConstructor()
{
$this->expectException(InvalidArgumentException::class);
$this->setExpectedException(InvalidArgumentException::class);
$header = new Age("100\r\n\r\nevilContent");
}
}
Loading