Skip to content

Commit

Permalink
Merge pull request #8837 from cakephp/psr7-client-internals
Browse files Browse the repository at this point in the history
Make Http\Client use PSR7 internally
  • Loading branch information
lorenzo committed May 19, 2016
2 parents 5a4a786 + a219020 commit 253e0b6
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 71 deletions.
31 changes: 14 additions & 17 deletions src/Http/Client.php
Expand Up @@ -421,29 +421,24 @@ public function buildUrl($url, $query = [], $options = [])
*/
protected function _createRequest($method, $url, $data, $options)
{
$request = new Request();
$request = $request->withMethod($method)
->url($url)
->body($data);

$headers = isset($options['headers']) ? (array)$options['headers'] : [];
if (isset($options['type'])) {
$request->header($this->_typeHeaders($options['type']));
}
if (isset($options['headers'])) {
$request->header($options['headers']);
$headers = array_merge($headers, $this->_typeHeaders($options['type']));
}
if (is_string($data) && !$request->header('content-type')) {
$request->header('Content-Type', 'application/x-www-form-urlencoded');
if (is_string($data) && !isset($headers['Content-Type']) && !isset($headers['content-type'])) {
$headers['Content-Type'] = 'application/x-www-form-urlencoded';
}

$request = new Request($url, $method, $headers, $data);
$request->cookie($this->_cookies->get($url));
if (isset($options['cookies'])) {
$request->cookie($options['cookies']);
}
if (isset($options['auth'])) {
$this->_addAuthentication($request, $options);
$request = $this->_addAuthentication($request, $options);
}
if (isset($options['proxy'])) {
$this->_addProxy($request, $options);
$request = $this->_addProxy($request, $options);
}
return $request;
}
Expand Down Expand Up @@ -485,13 +480,14 @@ protected function _typeHeaders($type)
*
* @param \Cake\Http\Client\Request $request The request to modify.
* @param array $options Array of options containing the 'auth' key.
* @return void
* @return \Cake\Http\Client\Request The updated request object.
*/
protected function _addAuthentication(Request $request, $options)
{
$auth = $options['auth'];
$adapter = $this->_createAuth($auth, $options);
$adapter->authentication($request, $options['auth']);
$result = $adapter->authentication($request, $options['auth']);
return $result ?: $request;
}

/**
Expand All @@ -502,13 +498,14 @@ protected function _addAuthentication(Request $request, $options)
*
* @param \Cake\Http\Client\Request $request The request to modify.
* @param array $options Array of options containing the 'proxy' key.
* @return void
* @return \Cake\Http\Client\Request The updated request object.
*/
protected function _addProxy(Request $request, $options)
{
$auth = $options['proxy'];
$adapter = $this->_createAuth($auth, $options);
$adapter->proxyAuthentication($request, $options['proxy']);
$result = $adapter->proxyAuthentication($request, $options['proxy']);
return $result ?: $request;
}

/**
Expand Down
10 changes: 6 additions & 4 deletions src/Http/Client/Auth/Basic.php
Expand Up @@ -29,31 +29,33 @@ class Basic
*
* @param \Cake\Network\Http\Request $request Request instance.
* @param array $credentials Credentials.
* @return void
* @return \Cake\Network\Http\Request The updated request.
* @see http://www.ietf.org/rfc/rfc2617.txt
*/
public function authentication(Request $request, array $credentials)
{
if (isset($credentials['username'], $credentials['password'])) {
$value = $this->_generateHeader($credentials['username'], $credentials['password']);
$request->header('Authorization', $value);
$request = $request->withHeader('Authorization', $value);
}
return $request;
}

/**
* Proxy Authentication
*
* @param \Cake\Network\Http\Request $request Request instance.
* @param array $credentials Credentials.
* @return void
* @return \Cake\Network\Http\Request The updated request.
* @see http://www.ietf.org/rfc/rfc2617.txt
*/
public function proxyAuthentication(Request $request, array $credentials)
{
if (isset($credentials['username'], $credentials['password'])) {
$value = $this->_generateHeader($credentials['username'], $credentials['password']);
$request->header('Proxy-Authorization', $value);
$request = $request->withHeader('Proxy-Authorization', $value);
}
return $request;
}

/**
Expand Down
14 changes: 7 additions & 7 deletions src/Http/Client/Auth/Digest.php
Expand Up @@ -48,22 +48,22 @@ public function __construct(Client $client, $options = null)
*
* @param \Cake\Network\Http\Request $request The request object.
* @param array $credentials Authentication credentials.
* @return void
* @return \Cake\Network\Http\Request The updated request.
* @see http://www.ietf.org/rfc/rfc2617.txt
*/
public function authentication(Request $request, array $credentials)
{
if (!isset($credentials['username'], $credentials['password'])) {
return;
return $request;
}
if (!isset($credentials['realm'])) {
$credentials = $this->_getServerInfo($request, $credentials);
}
if (!isset($credentials['realm'])) {
return;
return $request;
}
$value = $this->_generateHeader($request, $credentials);
$request->header('Authorization', $value);
return $request->withHeader('Authorization', $value);
}

/**
Expand All @@ -85,12 +85,12 @@ protected function _getServerInfo(Request $request, $credentials)
['auth' => []]
);

if (!$response->header('WWW-Authenticate')) {
if (!$response->getHeader('WWW-Authenticate')) {
return [];
}
preg_match_all(
'@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@',
$response->header('WWW-Authenticate'),
$response->getHeaderLine('WWW-Authenticate'),
$matches,
PREG_SET_ORDER
);
Expand All @@ -112,7 +112,7 @@ protected function _getServerInfo(Request $request, $credentials)
*/
protected function _generateHeader(Request $request, $credentials)
{
$path = parse_url($request->url(), PHP_URL_PATH);
$path = $request->getUri()->getPath();
$a1 = md5($credentials['username'] . ':' . $credentials['realm'] . ':' . $credentials['password']);
$a2 = md5($request->method() . ':' . $path);

Expand Down
30 changes: 13 additions & 17 deletions src/Http/Client/Auth/Oauth.php
Expand Up @@ -34,7 +34,7 @@ class Oauth
*
* @param \Cake\Network\Http\Request $request The request object.
* @param array $credentials Authentication credentials.
* @return void
* @return \Cake\Network\Http\Request The updated request.
* @throws \Cake\Core\Exception\Exception On invalid signature types.
*/
public function authentication(Request $request, array $credentials)
Expand All @@ -46,7 +46,7 @@ public function authentication(Request $request, array $credentials)
$credentials['tokenSecret']
);
if (!$hasKeys) {
return;
return $request;
}
if (empty($credentials['method'])) {
$credentials['method'] = 'hmac-sha1';
Expand All @@ -64,7 +64,7 @@ public function authentication(Request $request, array $credentials)
default:
throw new Exception(sprintf('Unknown Oauth signature method %s', $credentials['method']));
}
$request->header('Authorization', $value);
return $request->withHeader('Authorization', $value);
}

/**
Expand Down Expand Up @@ -150,8 +150,8 @@ protected function _hmacSha1($request, $credentials)
public function baseString($request, $oauthValues)
{
$parts = [
$request->method(),
$this->_normalizedUrl($request->url()),
$request->getMethod(),
$this->_normalizedUrl($request->getUri()),
$this->_normalizedParams($request, $oauthValues),
];
$parts = array_map([$this, '_encode'], $parts);
Expand All @@ -163,27 +163,23 @@ public function baseString($request, $oauthValues)
*
* Section 9.1.2. of the Oauth spec
*
* @param string $url URL
* @param Psr\Http\Message\UriInterface $uri Uri object to build a normalized version of.
* @return string Normalized URL
* @throws \Cake\Core\Exception\Exception On invalid URLs
*/
protected function _normalizedUrl($url)
protected function _normalizedUrl($uri)
{
$parts = parse_url($url);
if (!$parts) {
throw new Exception('Unable to parse URL');
}
$scheme = strtolower($parts['scheme'] ?: 'http');
$scheme = $uri->getScheme();
$defaultPorts = [
'http' => 80,
'https' => 443
];
if (isset($parts['port']) && $parts['port'] != $defaultPorts[$scheme]) {
$parts['host'] .= ':' . $parts['port'];
$port = $uri->getPort();
if ($port && $port != $defaultPorts[$scheme]) {
$parts['host'] .= ':' . $port;
}
$out = $scheme . '://';
$out .= strtolower($parts['host']);
$out .= $parts['path'];
$out .= strtolower($uri->getHost());
$out .= $uri->getPath();
return $out;
}

Expand Down
33 changes: 26 additions & 7 deletions src/Http/Client/Request.php
Expand Up @@ -34,15 +34,23 @@ class Request extends Message implements RequestInterface
* Constructor
*
* Provides backwards compatible defaults for some properties.
*
* @param string $url The request URL
* @param string $method The HTTP method to use.
* @param array $headers The HTTP headers to set.
* @param array|string $data The request body to use.
*/
public function __construct()
public function __construct($url = '', $method = self::METHOD_GET, array $headers = [], $data = null)
{
$this->method = static::METHOD_GET;

$this->header([
$this->validateMethod($method);
$this->method = $method;
$this->uri = $this->createUri($url);
$this->body($data);
$headers += [
'Connection' => 'close',
'User-Agent' => 'CakePHP'
]);
];
$this->addHeaders($headers);
}

/**
Expand Down Expand Up @@ -133,12 +141,23 @@ public function header($name = null, $value = null)
if ($value !== null && !is_array($name)) {
$name = [$name => $value];
}
foreach ($name as $key => $val) {
$this->addHeaders($name);
return $this;
}

/**
* Add an array of headers to the request.
*
* @param array $headers The headers to add.
* @return void
*/
protected function addHeaders($headers)
{
foreach ($headers as $key => $val) {
$normalized = strtolower($key);
$this->headers[$key] = (array)$val;
$this->headerNames[$normalized] = $key;
}
return $this;
}

/**
Expand Down
24 changes: 9 additions & 15 deletions tests/TestCase/Network/Http/Auth/DigestTest.php
Expand Up @@ -57,12 +57,10 @@ public function testRealmAndNonceFromExtraRequest()
->will($this->returnValue($response));

$auth = ['username' => 'admin', 'password' => '1234'];
$request = (new Request())->method(Request::METHOD_GET)
->url('http://example.com/some/path');
$request = new Request('http://example.com/some/path', Request::METHOD_GET);
$request = $this->auth->authentication($request, $auth);

$this->auth->authentication($request, $auth);

$result = $request->header('Authorization');
$result = $request->getHeaderLine('Authorization');
$this->assertContains('Digest', $result);
$this->assertContains('realm="The batcave"', $result);
$this->assertContains('nonce="4cded326c6c51"', $result);
Expand All @@ -89,11 +87,9 @@ public function testQop()
->will($this->returnValue($response));

$auth = ['username' => 'admin', 'password' => '1234'];
$request = (new Request())->method(Request::METHOD_GET)
->url('http://example.com/some/path');

$this->auth->authentication($request, $auth);
$result = $request->header('Authorization');
$request = new Request('http://example.com/some/path', Request::METHOD_GET);
$request = $this->auth->authentication($request, $auth);
$result = $request->getHeaderLine('Authorization');

$this->assertContains('qop="auth"', $result);
$this->assertContains('nc=00000001', $result);
Expand All @@ -117,11 +113,9 @@ public function testOpaque()
->will($this->returnValue($response));

$auth = ['username' => 'admin', 'password' => '1234'];
$request = (new Request())->method(Request::METHOD_GET)
->url('http://example.com/some/path');

$this->auth->authentication($request, $auth);
$result = $request->header('Authorization');
$request = new Request('http://example.com/some/path', Request::METHOD_GET);
$request = $this->auth->authentication($request, $auth);
$result = $request->getHeaderLine('Authorization');

$this->assertContains('opaque="d8ea7aa61a1693024c4cc3a516f49b3c"', $result);
}
Expand Down
8 changes: 4 additions & 4 deletions tests/TestCase/Network/Http/Auth/OauthTest.php
Expand Up @@ -56,9 +56,9 @@ public function testPlainTextSigning()
'method' => 'plaintext',
];
$request = new Request();
$auth->authentication($request, $creds);
$request = $auth->authentication($request, $creds);

$result = $request->header('Authorization');
$result = $request->getHeaderLine('Authorization');
$this->assertContains('OAuth', $result);
$this->assertContains('oauth_version="1.0"', $result);
$this->assertContains('oauth_token="a%20token%20value"', $result);
Expand Down Expand Up @@ -204,9 +204,9 @@ public function testHmacSigning()
'timestamp' => '1191242096'
];
$auth = new Oauth();
$auth->authentication($request, $options);
$request = $auth->authentication($request, $options);

$result = $request->header('Authorization');
$result = $request->getHeaderLine('Authorization');
$expected = 'tR3+Ty81lMeYAr/Fid0kMTYa/WM=';
$this->assertContains(
'oauth_signature="' . $expected . '"',
Expand Down

0 comments on commit 253e0b6

Please sign in to comment.