diff options
author | Matt Nowack <mdnowack@gmail.com> | 2016-03-15 14:22:23 -0700 |
---|---|---|
committer | Matt Nowack <mdnowack@gmail.com> | 2016-03-15 14:22:23 -0700 |
commit | 088bb3c7c68558be1e75bf6288825c6931d94f2c (patch) | |
tree | bf6542f559a44fece85cf36caf0c1376f774b4fc | |
parent | 4e793d54c4363ffdb66ded0fa2b815eaa38ae344 (diff) | |
parent | 79470b7a5eca090de111739512cf8c7e5842cc4d (diff) | |
download | twilio-php-088bb3c7c68558be1e75bf6288825c6931d94f2c.zip twilio-php-088bb3c7c68558be1e75bf6288825c6931d94f2c.tar.gz twilio-php-088bb3c7c68558be1e75bf6288825c6931d94f2c.tar.bz2 |
Merge pull request #37 from twilio/actually-do-http-right5.0.0-RC2
Actually do http right
-rw-r--r-- | Twilio/Http/CurlClient.php | 122 | ||||
-rw-r--r-- | Twilio/Tests/Bootstrap.php | 2 | ||||
-rw-r--r-- | Twilio/Tests/Unit/Http/CurlClientTest.php | 224 | ||||
-rw-r--r-- | Twilio/Tests/Unit/UnitTest.php | 10 |
4 files changed, 303 insertions, 55 deletions
diff --git a/Twilio/Http/CurlClient.php b/Twilio/Http/CurlClient.php index c397929..e296b2e 100644 --- a/Twilio/Http/CurlClient.php +++ b/Twilio/Http/CurlClient.php @@ -12,59 +12,8 @@ class CurlClient implements Client { public function request($method, $url, $params = array(), $data = array(), $headers = array(), $user = null, $password = null, $timeout = null) { - $timeout = is_null($timeout) - ? self::DEFAULT_TIMEOUT - : $timeout; - - $options = array( - CURLOPT_URL => $url, - CURLOPT_HEADER => true, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_INFILESIZE => -1, - CURLOPT_HTTPHEADER => array(), - CURLOPT_TIMEOUT => $timeout, - ); - - foreach ($headers as $key => $value) { - $options[CURLOPT_HTTPHEADER][] = "$key: $value"; - } - - if ($user && $password) { - $options[CURLOPT_HTTPHEADER][] = 'Authorization: Basic ' . base64_encode("$user:$password"); - } - - $body = $this->buildQuery($params); - - switch (strtolower(trim($method))) { - case 'get': - $options[CURLOPT_HTTPGET] = true; - if ($body) { - $options[CURLOPT_URL] = $options[CURLOPT_URL] . '?' . $body; - } - break; - case 'post': - $options[CURLOPT_POST] = true; - $options[CURLOPT_POSTFIELDS] = $body; - break; - case 'put': - $options[CURLOPT_PUT] = true; - if ($body) { - if ($buffer = fopen('php://memory', 'w+')) { - fwrite($buffer, $body); - fseek($buffer, 0); - $options[CURLOPT_INFILE] = $buffer; - $options[CURLOPT_INFILESIZE] = strlen($body); - } - } else { - throw new EnvironmentException('Unable to open a temporary file'); - } - break; - case 'head': - $opts[CURLOPT_NOBODY] = true; - break; - default: - $opts[CURLOPT_CUSTOMREQUEST] = strtoupper($method); - } + $options = $this->options($method, $url, $params, $data, $headers, + $user, $password, $timeout); try { if (!$curl = curl_init()) { @@ -114,9 +63,74 @@ class CurlClient implements Client { } } - protected function buildQuery($params) { + public function options($method, $url, $params = array(), $data = array(), + $headers = array(), $user = null, $password = null, + $timeout = null) { + + $timeout = is_null($timeout) + ? self::DEFAULT_TIMEOUT + : $timeout; + + $options = array( + CURLOPT_URL => $url, + CURLOPT_HEADER => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_INFILESIZE => -1, + CURLOPT_HTTPHEADER => array(), + CURLOPT_TIMEOUT => $timeout, + ); + + foreach ($headers as $key => $value) { + $options[CURLOPT_HTTPHEADER][] = "$key: $value"; + } + + if ($user && $password) { + $options[CURLOPT_HTTPHEADER][] = 'Authorization: Basic ' . base64_encode("$user:$password"); + } + + $body = $this->buildQuery($params); + if ($body) { + $options[CURLOPT_URL] .= '?' . $body; + } + + switch (strtolower(trim($method))) { + case 'get': + $options[CURLOPT_HTTPGET] = true; + break; + case 'post': + $options[CURLOPT_POST] = true; + $options[CURLOPT_POSTFIELDS] = $this->buildQuery($data); + + break; + case 'put': + $options[CURLOPT_PUT] = true; + if ($data) { + if ($buffer = fopen('php://memory', 'w+')) { + $dataString = $this->buildQuery($data); + fwrite($buffer, $dataString); + fseek($buffer, 0); + $options[CURLOPT_INFILE] = $buffer; + $options[CURLOPT_INFILESIZE] = strlen($dataString); + } else { + throw new EnvironmentException('Unable to open a temporary file'); + } + } + break; + case 'head': + $options[CURLOPT_NOBODY] = true; + break; + default: + $options[CURLOPT_CUSTOMREQUEST] = strtoupper($method); + } + + return $options; + } + + public function buildQuery($params) { $parts = array(); + $params = $params ?: array(); + foreach ($params as $key => $value) { if (is_array($value)) { foreach ($value as $item) { diff --git a/Twilio/Tests/Bootstrap.php b/Twilio/Tests/Bootstrap.php index d3ff346..0a55cb2 100644 --- a/Twilio/Tests/Bootstrap.php +++ b/Twilio/Tests/Bootstrap.php @@ -10,7 +10,7 @@ $tests = "$root/Tests"; $path = array($library, $tests, get_include_path()); set_include_path(implode(PATH_SEPARATOR, $path)); -$vendorFilename = dirname(__FILE__) . '/../vendor/autoload.php'; +$vendorFilename = dirname(__FILE__) . '/../../vendor/autoload.php'; if (file_exists($vendorFilename)) { /* composer install */ /** @noinspection PhpIncludeInspection */ diff --git a/Twilio/Tests/Unit/Http/CurlClientTest.php b/Twilio/Tests/Unit/Http/CurlClientTest.php new file mode 100644 index 0000000..6d1fb1f --- /dev/null +++ b/Twilio/Tests/Unit/Http/CurlClientTest.php @@ -0,0 +1,224 @@ +<?php + + +namespace Twilio\Tests\Unit\Http; + + +use Twilio\Http\CurlClient; +use Twilio\Tests\Unit\UnitTest; + +class CurlClientTest extends UnitTest { + + public function testPreemptiveAuthorization() { + $client = new CurlClient(); + + $options = $client->options( + 'GET', + 'http://api.twilio.com', + array(), + array(), + array(), + 'test-user', + 'test-password' + ); + + $this->assertArrayHasKey(CURLOPT_HTTPHEADER, $options); + + $headers = $options[CURLOPT_HTTPHEADER]; + + $authorization = null; + foreach ($headers as $header) { + $parse = explode(':', $header); + $headerKey = $parse[0]; + if ($headerKey == 'Authorization') { + $authorization = $header; + break; + } + } + + $this->assertNotNull($authorization); + + $authorizationPayload = explode(' ', $authorization); + $encodedAuthorization = array_pop($authorizationPayload); + $decodedAuthorization = base64_decode($encodedAuthorization); + + $this->assertEquals('test-user:test-password', $decodedAuthorization); + } + + + /** + * @param string $message Failure Message + * @param mixed[] $params Params with which to build the query + * @param string $expected Expected query string + * @dataProvider buildQueryProvider + */ + public function testBuildQuery($message, $params, $expected) { + $client = new CurlClient(); + $actual = $client->buildQuery($params); + $this->assertEquals($expected, $actual, $message); + } + + public function buildQueryProvider() { + return array( + array( + 'Null Params', + null, + '' + ), + array( + 'Empty Params', + array(), + '', + ), + array( + 'Single Scalar', + array('a' => 'z'), + 'a=z', + ), + array( + 'Multiple Scalars', + array( + 'a' => 'z', + 'b' => 'y', + ), + 'a=z&b=y', + ), + array( + 'Type Coercion: Booleans', + array( + 'a' => true, + 'b' => false, + ), + 'a=1&b=', + ), + array( + 'Type Coercion: Integers', + array( + 'a' => 7, + 'b' => -14, + 'c' => 0, + ), + 'a=7&b=-14&c=0', + ), + array( + 'Nested Arrays', + array( + 'a' => array(1, 2, 3), + 'b' => array('x', 'y', 'z'), + ), + 'a=1&a=2&a=3&b=x&b=y&b=z', + ), + array( + 'URL Safety', + array( + 'a' => 'un$afe:// value!', + ), + 'a=un%24afe%3A%2F%2F+value%21', + ) + ); + } + + /** + * @param $method + * @param $params + * @param $expected + * @dataProvider queryStringProvider + * @throws \Twilio\Exceptions\EnvironmentException + */ + public function testQueryString($method, $params, $expected) { + $client = new CurlClient(); + + $actual = $client->options($method, 'url', $params); + + $this->assertEquals($expected, $actual[CURLOPT_URL]); + } + + public function queryStringProvider() { + $methods = array('GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'HEAD', 'CUSTOM'); + $cases = array(); + + foreach ($methods as $method) { + $cases[] = array( + $method, + array(), + 'url', + ); + + $cases[] = array( + $method, + array( + 'a' => '$z', + 'b' => 7, + 'c' => array(1, 'x', 2), + ), + 'url?a=%24z&b=7&c=1&c=x&c=2', + ); + } + + return $cases; + } + + /** + * @param $params + * @param $data + * @dataProvider postFieldsProvider + * @throws \Twilio\Exceptions\EnvironmentException + */ + public function testPostFields($params, $data, $expected) { + $client = new CurlClient(); + + $actual = $client->options('POST', 'url', $params, $data); + + $this->assertEquals($expected, $actual[CURLOPT_POSTFIELDS]); + } + + public function postFieldsProvider() { + return array( + array( + array(), + array(), + '', + ), + + array( + array( + 'a' => 'x', + ), + array( + 'a' => 'b', + ), + 'a=b' + ), + + array( + array( + 'a' => 'x', + ), + array( + 'a' => 'x', + ), + 'a=x' + ), + + array( + array( + 'a' => 'x', + ), + array( + 'a' => 'z', + 'b' => 7, + 'c' => array(1, 2, 3), + ), + 'a=z&b=7&c=1&c=2&c=3', + ), + ); + } + + public function testPutFile() { + $client = new CurlClient(); + $actual = $client->options('PUT', 'url', array(), array('a' => 1, 'b' => 2)); + $this->assertNotNull($actual[CURLOPT_INFILE]); + $this->assertEquals('a=1&b=2', fread($actual[CURLOPT_INFILE], $actual[CURLOPT_INFILESIZE])); + $this->assertEquals(7, $actual[CURLOPT_INFILESIZE]); + } +}
\ No newline at end of file diff --git a/Twilio/Tests/Unit/UnitTest.php b/Twilio/Tests/Unit/UnitTest.php new file mode 100644 index 0000000..50ad366 --- /dev/null +++ b/Twilio/Tests/Unit/UnitTest.php @@ -0,0 +1,10 @@ +<?php + + +namespace Twilio\Tests\Unit; + +use \PHPUnit_Framework_TestCase; + +abstract class UnitTest extends PHPUnit_Framework_TestCase { + +}
\ No newline at end of file |