Cleaning up HttpSocket public/protected api; all protected methods are now prefixed with an underscore. Refactored associated tests.

This commit is contained in:
jperras 2009-05-07 14:49:21 -04:00
parent 70e0316cd2
commit 2e2aa0cd3a
2 changed files with 195 additions and 92 deletions

View file

@ -40,7 +40,8 @@ class HttpSocket extends CakeSocket {
*/
var $description = 'HTTP-based DataSource Interface';
/**
* When one activates the $quirksMode by setting it to true, all checks meant to enforce RFC 2616 (HTTP/1.1 specs)
* When one activates the $quirksMode by setting it to true, all checks meant to
* enforce RFC 2616 (HTTP/1.1 specs).
* will be disabled and additional measures to deal with non-standard responses will be enabled.
*
* @var boolean
@ -143,10 +144,10 @@ class HttpSocket extends CakeSocket {
*/
function __construct($config = array()) {
if (is_string($config)) {
$this->configUri($config);
$this->_configUri($config);
} elseif (is_array($config)) {
if (isset($config['request']['uri']) && is_string($config['request']['uri'])) {
$this->configUri($config['request']['uri']);
$this->_configUri($config['request']['uri']);
unset($config['request']['uri']);
}
$this->config = Set::merge($this->config, $config);
@ -172,7 +173,7 @@ class HttpSocket extends CakeSocket {
if (!isset($request['uri'])) {
$request['uri'] = null;
}
$uri = $this->parseUri($request['uri']);
$uri = $this->_parseUri($request['uri']);
if (!isset($uri['host'])) {
$host = $this->config['host'];
@ -183,10 +184,10 @@ class HttpSocket extends CakeSocket {
}
$request['uri'] = $this->url($request['uri']);
$request['uri'] = $this->parseUri($request['uri'], true);
$request['uri'] = $this->_parseUri($request['uri'], true);
$this->request = Set::merge($this->request, $this->config['request'], $request);
$this->configUri($this->request['uri']);
$this->_configUri($this->request['uri']);
if (isset($host)) {
$this->config['host'] = $host;
@ -194,7 +195,7 @@ class HttpSocket extends CakeSocket {
$cookies = null;
if (is_array($this->request['header'])) {
$this->request['header'] = $this->parseHeader($this->request['header']);
$this->request['header'] = $this->_parseHeader($this->request['header']);
if (!empty($this->request['cookies'])) {
$cookies = $this->buildCookies($this->request['cookies']);
}
@ -209,7 +210,7 @@ class HttpSocket extends CakeSocket {
}
if (is_array($this->request['body'])) {
$this->request['body'] = $this->httpSerialize($this->request['body']);
$this->request['body'] = $this->_httpSerialize($this->request['body']);
}
if (!empty($this->request['body']) && !isset($this->request['header']['Content-Type'])) {
@ -221,10 +222,10 @@ class HttpSocket extends CakeSocket {
}
$connectionType = @$this->request['header']['Connection'];
$this->request['header'] = $this->buildHeader($this->request['header']).$cookies;
$this->request['header'] = $this->_buildHeader($this->request['header']).$cookies;
if (empty($this->request['line'])) {
$this->request['line'] = $this->buildRequestLine($this->request);
$this->request['line'] = $this->_buildRequestLine($this->request);
}
if ($this->quirksMode === false && $this->request['line'] === false) {
@ -252,7 +253,7 @@ class HttpSocket extends CakeSocket {
$this->disconnect();
}
$this->response = $this->parseResponse($response);
$this->response = $this->_parseResponse($response);
if (!empty($this->response['cookies'])) {
$this->config['request']['cookies'] = array_merge($this->config['request']['cookies'], $this->response['cookies']);
}
@ -262,7 +263,7 @@ class HttpSocket extends CakeSocket {
/**
* Issues a GET request to the specified URI, query, and request.
*
* @param mixed $uri URI to request (see {@link parseUri()})
* @param mixed $uri URI to request (see {@link _parseUri()})
* @param array $query Query to append to URI
* @param array $request An indexed array with indexes such as 'method' or uri
* @return mixed Result of request
@ -270,13 +271,13 @@ class HttpSocket extends CakeSocket {
*/
function get($uri = null, $query = array(), $request = array()) {
if (!empty($query)) {
$uri =$this->parseUri($uri);
$uri =$this->_parseUri($uri);
if (isset($uri['query'])) {
$uri['query'] = array_merge($uri['query'], $query);
} else {
$uri['query'] = $query;
}
$uri = $this->buildUri($uri);
$uri = $this->_buildUri($uri);
}
$request = Set::merge(array('method' => 'GET', 'uri' => $uri), $request);
@ -286,7 +287,7 @@ class HttpSocket extends CakeSocket {
/**
* Issues a POST request to the specified URI, query, and request.
*
* @param mixed $uri URI to request (see {@link parseUri()})
* @param mixed $uri URI to request (see {@link _parseUri()})
* @param array $query Query to append to URI
* @param array $request An indexed array with indexes such as 'method' or uri
* @return mixed Result of request
@ -299,7 +300,7 @@ class HttpSocket extends CakeSocket {
/**
* Issues a PUT request to the specified URI, query, and request.
*
* @param mixed $uri URI to request (see {@link parseUri()})
* @param mixed $uri URI to request (see {@link _parseUri()})
* @param array $query Query to append to URI
* @param array $request An indexed array with indexes such as 'method' or uri
* @return mixed Result of request
@ -312,7 +313,7 @@ class HttpSocket extends CakeSocket {
/**
* Issues a DELETE request to the specified URI, query, and request.
*
* @param mixed $uri URI to request (see {@link parseUri()})
* @param mixed $uri URI to request (see {@link _parseUri()})
* @param array $query Query to append to URI
* @param array $request An indexed array with indexes such as 'method' or uri
* @return mixed Result of request
@ -346,16 +347,16 @@ class HttpSocket extends CakeSocket {
}
$base = array_merge($this->config['request']['uri'], array('scheme' => array('http', 'https'), 'port' => array(80, 443)));
$url = $this->parseUri($url, $base);
$url = $this->_parseUri($url, $base);
if (empty($url)) {
$url = $this->config['request']['uri'];
}
if (!empty($uriTemplate)) {
return $this->buildUri($url, $uriTemplate);
return $this->_buildUri($url, $uriTemplate);
}
return $this->buildUri($url);
return $this->_buildUri($url);
}
/**
* Parses the given message and breaks it down in parts.
@ -364,7 +365,7 @@ class HttpSocket extends CakeSocket {
* @return array Parsed message (with indexed elements such as raw, status, header, body)
* @access protected
*/
function parseResponse($message) {
function _parseResponse($message) {
if (is_array($message)) {
return $message;
} elseif (!is_string($message)) {
@ -394,12 +395,12 @@ class HttpSocket extends CakeSocket {
$response['status']['reason-phrase'] = $match[3];
}
$response['header'] = $this->parseHeader($response['raw']['header']);
$decoded = $this->decodeBody($response['raw']['body'], @$response['header']['Transfer-Encoding']);
$response['header'] = $this->_parseHeader($response['raw']['header']);
$decoded = $this->_decodeBody($response['raw']['body'], @$response['header']['Transfer-Encoding']);
$response['body'] = $decoded['body'];
if (!empty($decoded['header'])) {
$response['header'] = $this->parseHeader($this->buildHeader($response['header']).$this->buildHeader($decoded['header']));
$response['header'] = $this->_parseHeader($this->_buildHeader($response['header']).$this->_buildHeader($decoded['header']));
}
if (!empty($response['header'])) {
@ -423,7 +424,7 @@ class HttpSocket extends CakeSocket {
* @return mixed Array or false
* @access protected
*/
function decodeBody($body, $encoding = 'chunked') {
function _decodeBody($body, $encoding = 'chunked') {
if (!is_string($body)) {
return false;
}
@ -434,7 +435,7 @@ class HttpSocket extends CakeSocket {
if (!is_callable(array(&$this, $decodeMethod))) {
if (!$this->quirksMode) {
trigger_error(sprintf(__('HttpSocket::decodeBody - Unknown encoding: %s. Activate quirks mode to surpress error.', true), h($encoding)), E_USER_WARNING);
trigger_error(sprintf(__('HttpSocket::_decodeBody - Unknown encoding: %s. Activate quirks mode to surpress error.', true), h($encoding)), E_USER_WARNING);
}
return array('body' => $body, 'header' => false);
}
@ -448,7 +449,7 @@ class HttpSocket extends CakeSocket {
* @return mixed Array or false
* @access protected
*/
function decodeChunkedBody($body) {
function _decodeChunkedBody($body) {
if (!is_string($body)) {
return false;
}
@ -459,7 +460,7 @@ class HttpSocket extends CakeSocket {
while ($chunkLength !== 0) {
if (!preg_match("/^([0-9a-f]+) *(?:;(.+)=(.+))?\r\n/iU", $body, $match)) {
if (!$this->quirksMode) {
trigger_error(__('HttpSocket::decodeChunkedBody - Could not parse malformed chunk. Activate quirks mode to do this.', true), E_USER_WARNING);
trigger_error(__('HttpSocket::_decodeChunkedBody - Could not parse malformed chunk. Activate quirks mode to do this.', true), E_USER_WARNING);
return false;
}
break;
@ -498,26 +499,26 @@ class HttpSocket extends CakeSocket {
$entityHeader = false;
if (!empty($body)) {
$entityHeader = $this->parseHeader($body);
$entityHeader = $this->_parseHeader($body);
}
return array('body' => $decodedBody, 'header' => $entityHeader);
}
/**
* Parses and sets the specified URI into current request configuration.
*
* @param mixed $uri URI (see {@link parseUri()})
* @param mixed $uri URI (see {@link _parseUri()})
* @return array Current configuration settings
* @access protected
*/
function configUri($uri = null) {
function _configUri($uri = null) {
if (empty($uri)) {
return false;
}
if (is_array($uri)) {
$uri = $this->parseUri($uri);
$uri = $this->_parseUri($uri);
} else {
$uri = $this->parseUri($uri, true);
$uri = $this->_parseUri($uri, true);
}
if (!isset($uri['host'])) {
@ -542,18 +543,18 @@ class HttpSocket extends CakeSocket {
* @return string A fully qualified URL formated according to $uriTemplate
* @access protected
*/
function buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') {
function _buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') {
if (is_string($uri)) {
$uri = array('host' => $uri);
}
$uri = $this->parseUri($uri, true);
$uri = $this->_parseUri($uri, true);
if (!is_array($uri) || empty($uri)) {
return false;
}
$uri['path'] = preg_replace('/^\//', null, $uri['path']);
$uri['query'] = $this->httpSerialize($uri['query']);
$uri['query'] = $this->_httpSerialize($uri['query']);
$stripIfEmpty = array(
'query' => '?%query',
'fragment' => '#%fragment',
@ -589,7 +590,7 @@ class HttpSocket extends CakeSocket {
* @return array Parsed URI
* @access protected
*/
function parseUri($uri = null, $base = array()) {
function _parseUri($uri = null, $base = array()) {
$uriBase = array(
'scheme' => array('http', 'https'),
'host' => null,
@ -631,7 +632,7 @@ class HttpSocket extends CakeSocket {
}
if (array_key_exists('query', $uri)) {
$uri['query'] = $this->parseQuery($uri['query']);
$uri['query'] = $this->_parseQuery($uri['query']);
}
if (!array_intersect_key($uriBase, $uri)) {
@ -647,13 +648,13 @@ class HttpSocket extends CakeSocket {
* - ?key[]=value1&key[]=value2
*
* A leading '?' mark in $query is optional and does not effect the outcome of this function. For the complete capabilities of this implementation
* take a look at HttpSocketTest::testParseQuery()
* take a look at HttpSocketTest::testparseQuery()
*
* @param mixed $query A query string to parse into an array or an array to return directly "as is"
* @return array The $query parsed into a possibly multi-level array. If an empty $query is given, an empty array is returned.
* @access protected
*/
function parseQuery($query) {
function _parseQuery($query) {
if (is_array($query)) {
return $query;
}
@ -710,13 +711,13 @@ class HttpSocket extends CakeSocket {
* @return string Request line
* @access protected
*/
function buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') {
function _buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') {
$asteriskMethods = array('OPTIONS');
if (is_string($request)) {
$isValid = preg_match("/(.+) (.+) (.+)\r\n/U", $request, $match);
if (!$this->quirksMode && (!$isValid || ($match[2] == '*' && !in_array($match[3], $asteriskMethods)))) {
trigger_error(__('HttpSocket::buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.', true), E_USER_WARNING);
trigger_error(__('HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.', true), E_USER_WARNING);
return false;
}
return $request;
@ -726,12 +727,12 @@ class HttpSocket extends CakeSocket {
return false;
}
$request['uri'] = $this->parseUri($request['uri']);
$request['uri'] = $this->_parseUri($request['uri']);
$request = array_merge(array('method' => 'GET'), $request);
$request['uri'] = $this->buildUri($request['uri'], '/%path?%query');
$request['uri'] = $this->_buildUri($request['uri'], '/%path?%query');
if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) {
trigger_error(sprintf(__('HttpSocket::buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.', true), join(',', $asteriskMethods)), E_USER_WARNING);
trigger_error(sprintf(__('HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.', true), join(',', $asteriskMethods)), E_USER_WARNING);
return false;
}
return $request['method'].' '.$request['uri'].' '.$versionToken.$this->lineBreak;
@ -743,7 +744,7 @@ class HttpSocket extends CakeSocket {
* @return string Serialized variable
* @access protected
*/
function httpSerialize($data = array()) {
function _httpSerialize($data = array()) {
if (is_string($data)) {
return $data;
}
@ -759,7 +760,7 @@ class HttpSocket extends CakeSocket {
* @return string Header built from array
* @access protected
*/
function buildHeader($header, $mode = 'standard') {
function _buildHeader($header, $mode = 'standard') {
if (is_string($header)) {
return $header;
} elseif (!is_array($header)) {
@ -773,7 +774,7 @@ class HttpSocket extends CakeSocket {
}
foreach ((array)$contents as $content) {
$contents = preg_replace("/\r\n(?![\t ])/", "\r\n ", $content);
$field = $this->escapeToken($field);
$field = $this->_escapeToken($field);
$returnHeader .= $field.': '.$contents.$this->lineBreak;
}
@ -788,7 +789,7 @@ class HttpSocket extends CakeSocket {
* @return array Parsed header
* @access protected
*/
function parseHeader($header) {
function _parseHeader($header) {
if (is_array($header)) {
foreach ($header as $field => $value) {
unset($header[$field]);
@ -814,7 +815,7 @@ class HttpSocket extends CakeSocket {
$value = trim($value);
$value = preg_replace("/[\t ]\r\n/", "\r\n", $value);
$field = $this->unescapeToken($field);
$field = $this->_unescapeToken($field);
$field = strtolower($field);
preg_match_all('/(?:^|(?<=-))[a-z]/U', $field, $offsets, PREG_OFFSET_CAPTURE);
@ -875,29 +876,11 @@ class HttpSocket extends CakeSocket {
function buildCookies($cookies) {
$header = array();
foreach ($cookies as $name => $cookie) {
$header[] = $name.'='.$this->escapeToken($cookie['value'], array(';'));
$header[] = $name.'='.$this->_escapeToken($cookie['value'], array(';'));
}
$header = $this->buildHeader(array('Cookie' => $header), 'pragmatic');
$header = $this->_buildHeader(array('Cookie' => $header), 'pragmatic');
return $header;
}
/**
* undocumented function
*
* @return void
* @access public
*/
function saveCookies() {
}
/**
* undocumented function
*
* @return void
* @access public
*/
function loadCookies() {
}
/**
* Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs)
*
@ -906,8 +889,8 @@ class HttpSocket extends CakeSocket {
* @access protected
* @todo Test $chars parameter
*/
function unescapeToken($token, $chars = null) {
$regex = '/"(['.join('', $this->__tokenEscapeChars(true, $chars)).'])"/';
function _unescapeToken($token, $chars = null) {
$regex = '/"(['.join('', $this->_tokenEscapeChars(true, $chars)).'])"/';
$token = preg_replace($regex, '\\1', $token);
return $token;
}
@ -919,8 +902,8 @@ class HttpSocket extends CakeSocket {
* @access protected
* @todo Test $chars parameter
*/
function escapeToken($token, $chars = null) {
$regex = '/(['.join('', $this->__tokenEscapeChars(true, $chars)).'])/';
function _escapeToken($token, $chars = null) {
$regex = '/(['.join('', $this->_tokenEscapeChars(true, $chars)).'])/';
$token = preg_replace($regex, '"\\1"', $token);
return $token;
}
@ -929,10 +912,10 @@ class HttpSocket extends CakeSocket {
*
* @param boolean $hex true to get them as HEX values, false otherwise
* @return array Escape chars
* @access private
* @access protected
* @todo Test $chars parameter
*/
function __tokenEscapeChars($hex = true, $chars = null) {
function _tokenEscapeChars($hex = true, $chars = null) {
if (!empty($chars)) {
$escape = $chars;
} else {

View file

@ -25,6 +25,132 @@
* @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
*/
App::import('Core', 'HttpSocket');
class TestHttpSocket extends HttpSocket {
/**
* Convenience method for testing protected method
*
* @param mixed $uri URI (see {@link _parseUri()})
* @return array Current configuration settings
*/
function configUri($uri = null) {
return parent::_configUri($uri);
}
/**
* Convenience method for testing protected method
*
* @param string $uri URI to parse
* @param mixed $base If true use default URI config, otherwise indexed array to set 'scheme', 'host', 'port', etc.
* @return array Parsed URI
*/
function parseUri($uri = null, $base = array()) {
return parent::_parseUri($uri, $base);
}
/**
* Convenience method for testing protected method
*
* @param array $uri A $uri array, or uses $this->config if left empty
* @param string $uriTemplate The Uri template/format to use
* @return string A fully qualified URL formated according to $uriTemplate
*/
function buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') {
return parent::_buildUri($uri, $uriTemplate);
}
/**
* Convenience method for testing protected method
*
* @param array $header Header to build
* @return string Header built from array
*/
function buildHeader($header, $mode = 'standard') {
return parent::_buildHeader($header, $mode);
}
/**
* Convenience method for testing protected method
*
* @param string $message Message to parse
* @return array Parsed message (with indexed elements such as raw, status, header, body)
*/
function parseResponse($message) {
return parent::_parseResponse($message);
}
/**
* Convenience method for testing protected method
*
* @param array $header Header as an indexed array (field => value)
* @return array Parsed header
*/
function parseHeader($header) {
return parent::_parseHeader($header);
}
/**
* Convenience method for testing protected method
*
* @param mixed $query A query string to parse into an array or an array to return directly "as is"
* @return array The $query parsed into a possibly multi-level array. If an empty $query is given, an empty array is returned.
*/
function parseQuery($query) {
return parent::_parseQuery($query);
}
/**
* Convenience method for testing protected method
*
* @param string $body A string continaing the body to decode
* @param mixed $encoding Can be false in case no encoding is being used, or a string representing the encoding
* @return mixed Array or false
*/
function decodeBody($body, $encoding = 'chunked') {
return parent::_decodeBody($body, $encoding);
}
/**
* Convenience method for testing protected method
*
* @param string $body A string continaing the chunked body to decode
* @return mixed Array or false
*/
function decodeChunkedBody($body) {
return parent::_decodeChunkedBody($body);
}
/**
* Convenience method for testing protected method
*
* @param array $request Needs to contain a 'uri' key. Should also contain a 'method' key, otherwise defaults to GET.
* @param string $versionToken The version token to use, defaults to HTTP/1.1
* @return string Request line
*/
function buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') {
return parent::_buildRequestLine($request, $versionToken);
}
/**
* Convenience method for testing protected method
*
* @param boolean $hex true to get them as HEX values, false otherwise
* @return array Escape chars
*/
function tokenEscapeChars($hex = true, $chars = null) {
return parent::_tokenEscapeChars($hex, $chars);
}
/**
* Convenience method for testing protected method
*
* @param string $token Token to escape
* @return string Escaped token
*/
function EscapeToken($token, $chars = null) {
return parent::_escapeToken($token, $chars);
}
/**
* Convenience method for testing protected method
*
* @param string $token Token to unescape
* @return string Unescaped token
*/
function unescapeToken($token, $chars = null) {
return parent::_unescapeToken($token, $chars);
}
}
/**
* Short description for class.
*
@ -51,13 +177,13 @@ class HttpSocketTest extends CakeTestCase {
*
*/
function setUp() {
if (!class_exists('TestHttpSocket')) {
Mock::generatePartial('HttpSocket', 'TestHttpSocket', array('read', 'write', 'connect'));
Mock::generatePartial('HttpSocket', 'TestHttpSocketRequests', array('read', 'write', 'connect', 'request'));
if (!class_exists('MockHttpSocket')) {
Mock::generatePartial('TestHttpSocket', 'MockHttpSocket', array('read', 'write', 'connect'));
Mock::generatePartial('TestHttpSocket', 'MockHttpSocketRequests', array('read', 'write', 'connect', 'request'));
}
$this->Socket =& new TestHttpSocket();
$this->RequestSocket =& new TestHttpSocketRequests();
$this->Socket =& new MockHttpSocket();
$this->RequestSocket =& new MockHttpSocketRequests();
}
/**
* We use this function to clean up after the test case was executed
@ -365,12 +491,6 @@ class HttpSocketTest extends CakeTestCase {
$r = array('config' => $this->Socket->config, 'request' => $this->Socket->request);
$v = $this->assertIdentical($r, $expectation, '%s in test #'.$i.' ');
if (!$v) {
debug('Result:');
debug($r);
debug('Expected:');
debug($expectation);
}
$expectation['request']['raw'] = $raw;
}
@ -1189,7 +1309,7 @@ class HttpSocketTest extends CakeTestCase {
$this->assertEqual($result, $expect);
}
/**
* Tests that HttpSocket::__tokenEscapeChars() returns the right characters.
* Tests that HttpSocket::_tokenEscapeChars() returns the right characters.
*
*/
function testTokenEscapeChars() {
@ -1201,14 +1321,14 @@ class HttpSocketTest extends CakeTestCase {
'\x0e','\x0f','\x10','\x11','\x12','\x13','\x14','\x15','\x16','\x17','\x18','\x19','\x1a','\x1b','\x1c','\x1d',
'\x1e','\x1f','\x7f'
);
$r = $this->Socket->__tokenEscapeChars();
$r = $this->Socket->tokenEscapeChars();
$this->assertEqual($r, $expected);
foreach ($expected as $key => $char) {
$expected[$key] = chr(hexdec(substr($char, 2)));
}
$r = $this->Socket->__tokenEscapeChars(false);
$r = $this->Socket->tokenEscapeChars(false);
$this->assertEqual($r, $expected);
}
@ -1221,7 +1341,7 @@ class HttpSocketTest extends CakeTestCase {
$this->assertIdentical($this->Socket->escapeToken('Foo'), 'Foo');
$escape = $this->Socket->__tokenEscapeChars(false);
$escape = $this->Socket->tokenEscapeChars(false);
foreach ($escape as $char) {
$token = 'My-special-'.$char.'-Token';
$escapedToken = $this->Socket->escapeToken($token);
@ -1245,7 +1365,7 @@ class HttpSocketTest extends CakeTestCase {
$this->assertIdentical($this->Socket->unescapeToken('Foo'), 'Foo');
$escape = $this->Socket->__tokenEscapeChars(false);
$escape = $this->Socket->tokenEscapeChars(false);
foreach ($escape as $char) {
$token = 'My-special-"'.$char.'"-Token';
$unescapedToken = $this->Socket->unescapeToken($token);