first commit

This commit is contained in:
2025-01-06 20:47:25 +01:00
commit 3bdbd78c2f
25591 changed files with 3586440 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
<?php
namespace GuzzleHttp\Tests\Subscriber;
use GuzzleHttp\Transaction;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Subscriber\Cookie;
use GuzzleHttp\Subscriber\History;
use GuzzleHttp\Subscriber\Mock;
/**
* @covers GuzzleHttp\Subscriber\Cookie
*/
class CookieTest extends \PHPUnit_Framework_TestCase
{
public function testExtractsAndStoresCookies()
{
$request = new Request('GET', '/');
$response = new Response(200);
$mock = $this->getMockBuilder('GuzzleHttp\Cookie\CookieJar')
->setMethods(array('extractCookies'))
->getMock();
$mock->expects($this->exactly(1))
->method('extractCookies')
->with($request, $response);
$plugin = new Cookie($mock);
$t = new Transaction(new Client(), $request);
$t->response = $response;
$plugin->onComplete(new CompleteEvent($t));
}
public function testProvidesCookieJar()
{
$jar = new CookieJar();
$plugin = new Cookie($jar);
$this->assertSame($jar, $plugin->getCookieJar());
}
public function testCookiesAreExtractedFromRedirectResponses()
{
$jar = new CookieJar();
$cookie = new Cookie($jar);
$history = new History();
$mock = new Mock([
"HTTP/1.1 302 Moved Temporarily\r\n" .
"Set-Cookie: test=583551; Domain=www.foo.com; Expires=Wednesday, 23-Mar-2050 19:49:45 GMT; Path=/\r\n" .
"Location: /redirect\r\n\r\n",
"HTTP/1.1 200 OK\r\n" .
"Content-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\n" .
"Content-Length: 0\r\n\r\n"
]);
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach($cookie);
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($history);
$client->get();
$request = $client->createRequest('GET', '/');
$client->send($request);
$this->assertEquals('test=583551', $request->getHeader('Cookie'));
$requests = $history->getRequests();
// Confirm subsequent requests have the cookie.
$this->assertEquals('test=583551', $requests[2]->getHeader('Cookie'));
// Confirm the redirected request has the cookie.
$this->assertEquals('test=583551', $requests[1]->getHeader('Cookie'));
}
}

View File

@@ -0,0 +1,140 @@
<?php
namespace GuzzleHttp\Tests\Subscriber;
use GuzzleHttp\Transaction;
use GuzzleHttp\Client;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Subscriber\History;
use GuzzleHttp\Subscriber\Mock;
/**
* @covers GuzzleHttp\Subscriber\History
*/
class HistoryTest extends \PHPUnit_Framework_TestCase
{
public function testAddsForErrorEvent()
{
$request = new Request('GET', '/');
$response = new Response(400);
$t = new Transaction(new Client(), $request);
$t->response = $response;
$e = new RequestException('foo', $request, $response);
$ev = new ErrorEvent($t, $e);
$h = new History(2);
$h->onError($ev);
// Only tracks when no response is present
$this->assertEquals([], $h->getRequests());
}
public function testLogsConnectionErrors()
{
$request = new Request('GET', '/');
$t = new Transaction(new Client(), $request);
$e = new RequestException('foo', $request);
$ev = new ErrorEvent($t, $e);
$h = new History();
$h->onError($ev);
$this->assertEquals([$request], $h->getRequests());
}
public function testMaintainsLimitValue()
{
$request = new Request('GET', '/');
$response = new Response(200);
$t = new Transaction(new Client(), $request);
$t->response = $response;
$ev = new CompleteEvent($t);
$h = new History(2);
$h->onComplete($ev);
$h->onComplete($ev);
$h->onComplete($ev);
$this->assertEquals(2, count($h));
$this->assertSame($request, $h->getLastRequest());
$this->assertSame($response, $h->getLastResponse());
foreach ($h as $trans) {
$this->assertInstanceOf('GuzzleHttp\Message\RequestInterface', $trans['request']);
$this->assertInstanceOf('GuzzleHttp\Message\ResponseInterface', $trans['response']);
}
return $h;
}
/**
* @depends testMaintainsLimitValue
*/
public function testClearsHistory($h)
{
$this->assertEquals(2, count($h));
$h->clear();
$this->assertEquals(0, count($h));
}
public function testWorksWithMock()
{
$client = new Client(['base_url' => 'http://localhost/']);
$h = new History();
$client->getEmitter()->attach($h);
$mock = new Mock([new Response(200), new Response(201), new Response(202)]);
$client->getEmitter()->attach($mock);
$request = $client->createRequest('GET', '/');
$client->send($request);
$request->setMethod('PUT');
$client->send($request);
$request->setMethod('POST');
$client->send($request);
$this->assertEquals(3, count($h));
$result = implode("\n", array_map(function ($line) {
return strpos($line, 'User-Agent') === 0
? 'User-Agent:'
: trim($line);
}, explode("\n", $h)));
$this->assertEquals("> GET / HTTP/1.1
Host: localhost
User-Agent:
< HTTP/1.1 200 OK
> PUT / HTTP/1.1
Host: localhost
User-Agent:
< HTTP/1.1 201 Created
> POST / HTTP/1.1
Host: localhost
User-Agent:
< HTTP/1.1 202 Accepted
", $result);
}
public function testCanCastToString()
{
$client = new Client(['base_url' => 'http://localhost/']);
$h = new History();
$client->getEmitter()->attach($h);
$mock = new Mock(array(
new Response(301, array('Location' => '/redirect1', 'Content-Length' => 0)),
new Response(307, array('Location' => '/redirect2', 'Content-Length' => 0)),
new Response(200, array('Content-Length' => '2'), Stream::factory('HI'))
));
$client->getEmitter()->attach($mock);
$request = $client->createRequest('GET', '/');
$client->send($request);
$this->assertEquals(3, count($h));
$h = str_replace("\r", '', $h);
$this->assertContains("> GET / HTTP/1.1\nHost: localhost\nUser-Agent:", $h);
$this->assertContains("< HTTP/1.1 301 Moved Permanently\nLocation: /redirect1", $h);
$this->assertContains("< HTTP/1.1 307 Temporary Redirect\nLocation: /redirect2", $h);
$this->assertContains("< HTTP/1.1 200 OK\nContent-Length: 2\n\nHI", $h);
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Client;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Subscriber\HttpError;
use GuzzleHttp\Transaction;
use GuzzleHttp\Subscriber\Mock;
/**
* @covers GuzzleHttp\Subscriber\HttpError
*/
class HttpErrorTest extends \PHPUnit_Framework_TestCase
{
public function testIgnoreSuccessfulRequests()
{
$event = $this->getEvent();
$event->intercept(new Response(200));
(new HttpError())->onComplete($event);
}
/**
* @expectedException \GuzzleHttp\Exception\ClientException
*/
public function testThrowsClientExceptionOnFailure()
{
$event = $this->getEvent();
$event->intercept(new Response(403));
(new HttpError())->onComplete($event);
}
/**
* @expectedException \GuzzleHttp\Exception\ServerException
*/
public function testThrowsServerExceptionOnFailure()
{
$event = $this->getEvent();
$event->intercept(new Response(500));
(new HttpError())->onComplete($event);
}
private function getEvent()
{
return new CompleteEvent(new Transaction(new Client(), new Request('PUT', '/')));
}
/**
* @expectedException \GuzzleHttp\Exception\ClientException
*/
public function testFullTransaction()
{
$client = new Client();
$client->getEmitter()->attach(new Mock([
new Response(403)
]));
$client->get('http://httpbin.org');
}
}

View File

@@ -0,0 +1,225 @@
<?php
namespace GuzzleHttp\Tests\Subscriber;
use GuzzleHttp\Client;
use GuzzleHttp\Subscriber\Mock;
use GuzzleHttp\Message\FutureResponse;
use GuzzleHttp\Transaction;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
use React\Promise\Deferred;
/**
* @covers GuzzleHttp\Subscriber\Mock
*/
class MockTest extends \PHPUnit_Framework_TestCase
{
public static function createFuture(
callable $wait,
callable $cancel = null
) {
$deferred = new Deferred();
return new FutureResponse(
$deferred->promise(),
function () use ($deferred, $wait) {
$deferred->resolve($wait());
},
$cancel
);
}
public function testDescribesSubscribedEvents()
{
$mock = new Mock();
$this->assertInternalType('array', $mock->getEvents());
}
public function testIsCountable()
{
$plugin = new Mock();
$plugin->addResponse((new MessageFactory())->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
$this->assertEquals(1, count($plugin));
}
public function testCanClearQueue()
{
$plugin = new Mock();
$plugin->addResponse((new MessageFactory())->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
$plugin->clearQueue();
$this->assertEquals(0, count($plugin));
}
public function testRetrievesResponsesFromFiles()
{
$tmp = tempnam('/tmp', 'tfile');
file_put_contents($tmp, "HTTP/1.1 201 OK\r\nContent-Length: 0\r\n\r\n");
$plugin = new Mock();
$plugin->addResponse($tmp);
unlink($tmp);
$this->assertEquals(1, count($plugin));
$q = $this->readAttribute($plugin, 'queue');
$this->assertEquals(201, $q[0]->getStatusCode());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testThrowsExceptionWhenInvalidResponse()
{
(new Mock())->addResponse(false);
}
public function testAddsMockResponseToRequestFromClient()
{
$response = new Response(200);
$t = new Transaction(new Client(), new Request('GET', '/'));
$m = new Mock([$response]);
$ev = new BeforeEvent($t);
$m->onBefore($ev);
$this->assertSame($response, $t->response);
}
/**
* @expectedException \OutOfBoundsException
*/
public function testUpdateThrowsExceptionWhenEmpty()
{
$p = new Mock();
$ev = new BeforeEvent(new Transaction(new Client(), new Request('GET', '/')));
$p->onBefore($ev);
}
public function testReadsBodiesFromMockedRequests()
{
$m = new Mock([new Response(200)]);
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach($m);
$body = Stream::factory('foo');
$client->put('/', ['body' => $body]);
$this->assertEquals(3, $body->tell());
}
public function testCanMockBadRequestExceptions()
{
$client = new Client(['base_url' => 'http://test.com']);
$request = $client->createRequest('GET', '/');
$ex = new RequestException('foo', $request);
$mock = new Mock([$ex]);
$this->assertCount(1, $mock);
$request->getEmitter()->attach($mock);
try {
$client->send($request);
$this->fail('Did not dequeue an exception');
} catch (RequestException $e) {
$this->assertSame($e, $ex);
$this->assertSame($request, $ex->getRequest());
}
}
public function testCanMockFutureResponses()
{
$client = new Client(['base_url' => 'http://test.com']);
$request = $client->createRequest('GET', '/', ['future' => true]);
$response = new Response(200);
$future = self::createFuture(function () use ($response) {
return $response;
});
$mock = new Mock([$future]);
$this->assertCount(1, $mock);
$request->getEmitter()->attach($mock);
$res = $client->send($request);
$this->assertSame($future, $res);
$this->assertFalse($this->readAttribute($res, 'isRealized'));
$this->assertSame($response, $res->wait());
}
public function testCanMockExceptionFutureResponses()
{
$client = new Client(['base_url' => 'http://test.com']);
$request = $client->createRequest('GET', '/', ['future' => true]);
$future = self::createFuture(function () use ($request) {
throw new RequestException('foo', $request);
});
$mock = new Mock([$future]);
$request->getEmitter()->attach($mock);
$response = $client->send($request);
$this->assertSame($future, $response);
$this->assertFalse($this->readAttribute($response, 'isRealized'));
try {
$response->wait();
$this->fail('Did not throw');
} catch (RequestException $e) {
$this->assertContains('foo', $e->getMessage());
}
}
public function testSaveToFile()
{
$filename = sys_get_temp_dir().'/mock_test_'.uniqid();
$file = tmpfile();
$stream = new Stream(tmpfile());
$m = new Mock([
new Response(200, [], Stream::factory('TEST FILENAME')),
new Response(200, [], Stream::factory('TEST FILE')),
new Response(200, [], Stream::factory('TEST STREAM')),
]);
$client = new Client();
$client->getEmitter()->attach($m);
$client->get('/', ['save_to' => $filename]);
$client->get('/', ['save_to' => $file]);
$client->get('/', ['save_to' => $stream]);
$this->assertFileExists($filename);
$this->assertEquals('TEST FILENAME', file_get_contents($filename));
$meta = stream_get_meta_data($file);
$this->assertFileExists($meta['uri']);
$this->assertEquals('TEST FILE', file_get_contents($meta['uri']));
$this->assertFileExists($stream->getMetadata('uri'));
$this->assertEquals('TEST STREAM', file_get_contents($stream->getMetadata('uri')));
unlink($filename);
}
public function testCanMockFailedFutureResponses()
{
$client = new Client(['base_url' => 'http://test.com']);
$request = $client->createRequest('GET', '/', ['future' => true]);
// The first mock will be a mocked future response.
$future = self::createFuture(function () use ($client) {
// When dereferenced, we will set a mocked response and send
// another request.
$client->get('http://httpbin.org', ['events' => [
'before' => function (BeforeEvent $e) {
$e->intercept(new Response(404));
}
]]);
});
$mock = new Mock([$future]);
$request->getEmitter()->attach($mock);
$response = $client->send($request);
$this->assertSame($future, $response);
$this->assertFalse($this->readAttribute($response, 'isRealized'));
try {
$response->wait();
$this->fail('Did not throw');
} catch (RequestException $e) {
$this->assertEquals(404, $e->getResponse()->getStatusCode());
}
}
}

View File

@@ -0,0 +1,213 @@
<?php
namespace GuzzleHttp\Tests\Message;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Tests\Server;
use GuzzleHttp\Transaction;
use GuzzleHttp\Client;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Stream\NoSeekStream;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Subscriber\Prepare;
/**
* @covers GuzzleHttp\Subscriber\Prepare
*/
class PrepareTest extends \PHPUnit_Framework_TestCase
{
public function testIgnoresRequestsWithNoBody()
{
$s = new Prepare();
$t = $this->getTrans();
$s->onBefore(new BeforeEvent($t));
$this->assertFalse($t->request->hasHeader('Expect'));
}
public function testAppliesPostBody()
{
$s = new Prepare();
$t = $this->getTrans();
$p = $this->getMockBuilder('GuzzleHttp\Post\PostBody')
->setMethods(['applyRequestHeaders'])
->getMockForAbstractClass();
$p->expects($this->once())
->method('applyRequestHeaders');
$t->request->setBody($p);
$s->onBefore(new BeforeEvent($t));
}
public function testAddsExpectHeaderWithTrue()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->getConfig()->set('expect', true);
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertEquals('100-Continue', $t->request->getHeader('Expect'));
}
public function testAddsExpectHeaderBySize()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->getConfig()->set('expect', 2);
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertTrue($t->request->hasHeader('Expect'));
}
public function testDoesNotModifyExpectHeaderIfPresent()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setHeader('Expect', 'foo');
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertEquals('foo', $t->request->getHeader('Expect'));
}
public function testDoesAddExpectHeaderWhenSetToFalse()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->getConfig()->set('expect', false);
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertFalse($t->request->hasHeader('Expect'));
}
public function testDoesNotAddExpectHeaderBySize()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->getConfig()->set('expect', 10);
$t->request->setBody(Stream::factory('foo'));
$s->onBefore(new BeforeEvent($t));
$this->assertFalse($t->request->hasHeader('Expect'));
}
public function testAddsExpectHeaderForNonSeekable()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody(new NoSeekStream(Stream::factory('foo')));
$s->onBefore(new BeforeEvent($t));
$this->assertTrue($t->request->hasHeader('Expect'));
}
public function testRemovesContentLengthWhenSendingWithChunked()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody(Stream::factory('foo'));
$t->request->setHeader('Transfer-Encoding', 'chunked');
$s->onBefore(new BeforeEvent($t));
$this->assertFalse($t->request->hasHeader('Content-Length'));
}
public function testUsesProvidedContentLengthAndRemovesXferEncoding()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody(Stream::factory('foo'));
$t->request->setHeader('Content-Length', '3');
$t->request->setHeader('Transfer-Encoding', 'chunked');
$s->onBefore(new BeforeEvent($t));
$this->assertEquals(3, $t->request->getHeader('Content-Length'));
$this->assertFalse($t->request->hasHeader('Transfer-Encoding'));
}
public function testSetsContentTypeIfPossibleFromStream()
{
$body = $this->getMockBody();
$sub = new Prepare();
$t = $this->getTrans();
$t->request->setBody($body);
$sub->onBefore(new BeforeEvent($t));
$this->assertEquals(
'image/jpeg',
$t->request->getHeader('Content-Type')
);
$this->assertEquals(4, $t->request->getHeader('Content-Length'));
}
public function testDoesNotOverwriteExistingContentType()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody($this->getMockBody());
$t->request->setHeader('Content-Type', 'foo/baz');
$s->onBefore(new BeforeEvent($t));
$this->assertEquals(
'foo/baz',
$t->request->getHeader('Content-Type')
);
}
public function testSetsContentLengthIfPossible()
{
$s = new Prepare();
$t = $this->getTrans();
$t->request->setBody($this->getMockBody());
$s->onBefore(new BeforeEvent($t));
$this->assertEquals(4, $t->request->getHeader('Content-Length'));
}
public function testSetsTransferEncodingChunkedIfNeeded()
{
$r = new Request('PUT', '/');
$s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
->setMethods(['getSize'])
->getMockForAbstractClass();
$s->expects($this->exactly(2))
->method('getSize')
->will($this->returnValue(null));
$r->setBody($s);
$t = $this->getTrans($r);
$s = new Prepare();
$s->onBefore(new BeforeEvent($t));
$this->assertEquals('chunked', $r->getHeader('Transfer-Encoding'));
}
public function testContentLengthIntegrationTest()
{
Server::flush();
Server::enqueue([new Response(200)]);
$client = new Client(['base_url' => Server::$url]);
$this->assertEquals(200, $client->put('/', [
'body' => 'test'
])->getStatusCode());
$request = Server::received(true)[0];
$this->assertEquals('PUT', $request->getMethod());
$this->assertEquals('4', $request->getHeader('Content-Length'));
$this->assertEquals('test', (string) $request->getBody());
}
private function getTrans($request = null)
{
return new Transaction(
new Client(),
$request ?: new Request('PUT', '/')
);
}
/**
* @return \GuzzleHttp\Stream\StreamInterface
*/
private function getMockBody()
{
$s = $this->getMockBuilder('GuzzleHttp\Stream\MetadataStreamInterface')
->setMethods(['getMetadata', 'getSize'])
->getMockForAbstractClass();
$s->expects($this->any())
->method('getMetadata')
->with('uri')
->will($this->returnValue('/foo/baz/bar.jpg'));
$s->expects($this->exactly(2))
->method('getSize')
->will($this->returnValue(4));
return $s;
}
}

View File

@@ -0,0 +1,302 @@
<?php
namespace GuzzleHttp\Tests\Plugin\Redirect;
use GuzzleHttp\Client;
use GuzzleHttp\Subscriber\History;
use GuzzleHttp\Subscriber\Mock;
/**
* @covers GuzzleHttp\Subscriber\Redirect
*/
class RedirectTest extends \PHPUnit_Framework_TestCase
{
public function testRedirectsRequests()
{
$mock = new Mock();
$history = new History();
$mock->addMultiple([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach($history);
$client->getEmitter()->attach($mock);
$request = $client->createRequest('GET', '/foo');
// Ensure "end" is called only once
$called = 0;
$request->getEmitter()->on('end', function () use (&$called) {
$called++;
});
$response = $client->send($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertContains('/redirect2', $response->getEffectiveUrl());
// Ensure that two requests were sent
$requests = $history->getRequests(true);
$this->assertEquals('/foo', $requests[0]->getPath());
$this->assertEquals('GET', $requests[0]->getMethod());
$this->assertEquals('/redirect1', $requests[1]->getPath());
$this->assertEquals('GET', $requests[1]->getMethod());
$this->assertEquals('/redirect2', $requests[2]->getPath());
$this->assertEquals('GET', $requests[2]->getMethod());
$this->assertEquals(1, $called);
}
/**
* @expectedException \GuzzleHttp\Exception\TooManyRedirectsException
* @expectedExceptionMessage Will not follow more than
*/
public function testCanLimitNumberOfRedirects()
{
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect3\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect4\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect5\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect6\r\nContent-Length: 0\r\n\r\n"
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->get('http://www.example.com/foo');
}
public function testDefaultBehaviorIsToRedirectWithGetForEntityEnclosingRequests()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$client->post('http://test.com/foo', [
'headers' => ['X-Baz' => 'bar'],
'body' => 'testing'
]);
$requests = $h->getRequests(true);
$this->assertEquals('POST', $requests[0]->getMethod());
$this->assertEquals('GET', $requests[1]->getMethod());
$this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz'));
$this->assertEquals('GET', $requests[2]->getMethod());
}
public function testCanRedirectWithStrictRfcCompliance()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$client->post('/foo', [
'headers' => ['X-Baz' => 'bar'],
'body' => 'testing',
'allow_redirects' => ['max' => 10, 'strict' => true]
]);
$requests = $h->getRequests(true);
$this->assertEquals('POST', $requests[0]->getMethod());
$this->assertEquals('POST', $requests[1]->getMethod());
$this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz'));
$this->assertEquals('POST', $requests[2]->getMethod());
}
public function testRewindsStreamWhenRedirectingIfNeeded()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$body = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
->setMethods(['seek', 'read', 'eof', 'tell'])
->getMockForAbstractClass();
$body->expects($this->once())->method('tell')->will($this->returnValue(1));
$body->expects($this->once())->method('seek')->will($this->returnValue(true));
$body->expects($this->any())->method('eof')->will($this->returnValue(true));
$body->expects($this->any())->method('read')->will($this->returnValue('foo'));
$client->post('/foo', [
'body' => $body,
'allow_redirects' => ['max' => 5, 'strict' => true]
]);
}
/**
* @expectedException \GuzzleHttp\Exception\CouldNotRewindStreamException
* @expectedExceptionMessage Unable to rewind the non-seekable request body after redirecting
*/
public function testThrowsExceptionWhenStreamCannotBeRewound()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$body = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
->setMethods(['seek', 'read', 'eof', 'tell'])
->getMockForAbstractClass();
$body->expects($this->once())->method('tell')->will($this->returnValue(1));
$body->expects($this->once())->method('seek')->will($this->returnValue(false));
$body->expects($this->any())->method('eof')->will($this->returnValue(true));
$body->expects($this->any())->method('read')->will($this->returnValue('foo'));
$client->post('http://example.com/foo', [
'body' => $body,
'allow_redirects' => ['max' => 10, 'strict' => true]
]);
}
public function testRedirectsCanBeDisabledPerRequest()
{
$client = new Client(['base_url' => 'http://test.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]));
$response = $client->put('/', ['body' => 'test', 'allow_redirects' => false]);
$this->assertEquals(301, $response->getStatusCode());
}
public function testCanRedirectWithNoLeadingSlashAndQuery()
{
$h = new History();
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect?foo=bar\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]));
$client->getEmitter()->attach($h);
$client->get('?foo=bar');
$requests = $h->getRequests(true);
$this->assertEquals('http://www.foo.com?foo=bar', $requests[0]->getUrl());
$this->assertEquals('http://www.foo.com/redirect?foo=bar', $requests[1]->getUrl());
}
public function testHandlesRedirectsWithSpacesProperly()
{
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect 1\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
]));
$h = new History();
$client->getEmitter()->attach($h);
$client->get('/foo');
$reqs = $h->getRequests(true);
$this->assertEquals('/redirect%201', $reqs[1]->getResource());
}
public function testAddsRefererWhenPossible()
{
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /bar\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
]));
$h = new History();
$client->getEmitter()->attach($h);
$client->get('/foo', ['allow_redirects' => ['max' => 5, 'referer' => true]]);
$reqs = $h->getRequests(true);
$this->assertEquals('http://www.foo.com/foo', $reqs[1]->getHeader('Referer'));
}
public function testDoesNotAddRefererWhenChangingProtocols()
{
$client = new Client(['base_url' => 'https://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\n"
. "Location: http://www.foo.com/foo\r\n"
. "Content-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
]));
$h = new History();
$client->getEmitter()->attach($h);
$client->get('/foo', ['allow_redirects' => ['max' => 5, 'referer' => true]]);
$reqs = $h->getRequests(true);
$this->assertFalse($reqs[1]->hasHeader('Referer'));
}
public function testRedirectsWithGetOn303()
{
$h = new History();
$mock = new Mock([
"HTTP/1.1 303 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->getEmitter()->attach($h);
$client->post('http://test.com/foo', ['body' => 'testing']);
$requests = $h->getRequests(true);
$this->assertEquals('POST', $requests[0]->getMethod());
$this->assertEquals('GET', $requests[1]->getMethod());
}
public function testRelativeLinkBasedLatestRequest()
{
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: http://www.bar.com\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
]));
$response = $client->get('/');
$this->assertEquals(
'http://www.bar.com/redirect',
$response->getEffectiveUrl()
);
}
public function testUpperCaseScheme()
{
$client = new Client(['base_url' => 'http://www.foo.com']);
$client->getEmitter()->attach(new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: HTTP://www.bar.com\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
]));
$response = $client->get('/');
$this->assertEquals(
'http://www.bar.com',
$response->getEffectiveUrl()
);
}
/**
* @expectedException \GuzzleHttp\Exception\BadResponseException
* @expectedExceptionMessage Redirect URL, https://foo.com/redirect2, does not use one of the allowed redirect protocols: http
*/
public function testThrowsWhenRedirectingToInvalidUrlProtocol()
{
$mock = new Mock([
"HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n",
"HTTP/1.1 301 Moved Permanently\r\nLocation: https://foo.com/redirect2\r\nContent-Length: 0\r\n\r\n"
]);
$client = new Client();
$client->getEmitter()->attach($mock);
$client->get('http://www.example.com/foo', [
'allow_redirects' => [
'protocols' => ['http']
]
]);
}
}