Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like HttpSocket often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use HttpSocket, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 31 | class HttpSocket extends CakeSocket { |
||
| 32 | |||
| 33 | /** |
||
| 34 | * When one activates the $quirksMode by setting it to true, all checks meant to |
||
| 35 | * enforce RFC 2616 (HTTP/1.1 specs). |
||
| 36 | * will be disabled and additional measures to deal with non-standard responses will be enabled. |
||
| 37 | * |
||
| 38 | * @var boolean |
||
| 39 | */ |
||
| 40 | public $quirksMode = false; |
||
| 41 | |||
| 42 | /** |
||
| 43 | * Contain information about the last request (read only) |
||
| 44 | * |
||
| 45 | * @var array |
||
| 46 | */ |
||
| 47 | public $request = array( |
||
| 48 | 'method' => 'GET', |
||
| 49 | 'uri' => array( |
||
| 50 | 'scheme' => 'http', |
||
| 51 | 'host' => null, |
||
| 52 | 'port' => 80, |
||
| 53 | 'user' => null, |
||
| 54 | 'pass' => null, |
||
| 55 | 'path' => null, |
||
| 56 | 'query' => null, |
||
| 57 | 'fragment' => null |
||
| 58 | ), |
||
| 59 | 'version' => '1.1', |
||
| 60 | 'body' => '', |
||
| 61 | 'line' => null, |
||
| 62 | 'header' => array( |
||
| 63 | 'Connection' => 'close', |
||
| 64 | 'User-Agent' => 'CakePHP' |
||
| 65 | ), |
||
| 66 | 'raw' => null, |
||
| 67 | 'redirect' => false, |
||
| 68 | 'cookies' => array(), |
||
| 69 | ); |
||
| 70 | |||
| 71 | /** |
||
| 72 | * Contain information about the last response (read only) |
||
| 73 | * |
||
| 74 | * @var array |
||
| 75 | */ |
||
| 76 | public $response = null; |
||
| 77 | |||
| 78 | /** |
||
| 79 | * Response class name |
||
| 80 | * |
||
| 81 | * @var string |
||
| 82 | */ |
||
| 83 | public $responseClass = 'HttpSocketResponse'; |
||
| 84 | |||
| 85 | /** |
||
| 86 | * Configuration settings for the HttpSocket and the requests |
||
| 87 | * |
||
| 88 | * @var array |
||
| 89 | */ |
||
| 90 | public $config = array( |
||
| 91 | 'persistent' => false, |
||
| 92 | 'host' => 'localhost', |
||
| 93 | 'protocol' => 'tcp', |
||
| 94 | 'port' => 80, |
||
| 95 | 'timeout' => 30, |
||
| 96 | 'ssl_verify_peer' => true, |
||
| 97 | 'ssl_allow_self_signed' => false, |
||
| 98 | 'ssl_verify_depth' => 5, |
||
| 99 | 'ssl_verify_host' => true, |
||
| 100 | 'request' => array( |
||
| 101 | 'uri' => array( |
||
| 102 | 'scheme' => array('http', 'https'), |
||
| 103 | 'host' => 'localhost', |
||
| 104 | 'port' => array(80, 443) |
||
| 105 | ), |
||
| 106 | 'redirect' => false, |
||
| 107 | 'cookies' => array(), |
||
| 108 | ) |
||
| 109 | ); |
||
| 110 | |||
| 111 | /** |
||
| 112 | * Authentication settings |
||
| 113 | * |
||
| 114 | * @var array |
||
| 115 | */ |
||
| 116 | protected $_auth = array(); |
||
| 117 | |||
| 118 | /** |
||
| 119 | * Proxy settings |
||
| 120 | * |
||
| 121 | * @var array |
||
| 122 | */ |
||
| 123 | protected $_proxy = array(); |
||
| 124 | |||
| 125 | /** |
||
| 126 | * Resource to receive the content of request |
||
| 127 | * |
||
| 128 | * @var mixed |
||
| 129 | */ |
||
| 130 | protected $_contentResource = null; |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Build an HTTP Socket using the specified configuration. |
||
| 134 | * |
||
| 135 | * You can use a URL string to set the URL and use default configurations for |
||
| 136 | * all other options: |
||
| 137 | * |
||
| 138 | * `$http = new HttpSocket('http://cakephp.org/');` |
||
| 139 | * |
||
| 140 | * Or use an array to configure multiple options: |
||
| 141 | * |
||
| 142 | * {{{ |
||
| 143 | * $http = new HttpSocket(array( |
||
| 144 | * 'host' => 'cakephp.org', |
||
| 145 | * 'timeout' => 20 |
||
| 146 | * )); |
||
| 147 | * }}} |
||
| 148 | * |
||
| 149 | * See HttpSocket::$config for options that can be used. |
||
| 150 | * |
||
| 151 | * @param string|array $config Configuration information, either a string URL or an array of options. |
||
| 152 | */ |
||
| 153 | public function __construct($config = array()) { |
||
| 165 | |||
| 166 | /** |
||
| 167 | * Set authentication settings. |
||
| 168 | * |
||
| 169 | * Accepts two forms of parameters. If all you need is a username + password, as with |
||
| 170 | * Basic authentication you can do the following: |
||
| 171 | * |
||
| 172 | * {{{ |
||
| 173 | * $http->configAuth('Basic', 'mark', 'secret'); |
||
| 174 | * }}} |
||
| 175 | * |
||
| 176 | * If you are using an authentication strategy that requires more inputs, like Digest authentication |
||
| 177 | * you can call `configAuth()` with an array of user information. |
||
| 178 | * |
||
| 179 | * {{{ |
||
| 180 | * $http->configAuth('Digest', array( |
||
| 181 | * 'user' => 'mark', |
||
| 182 | * 'pass' => 'secret', |
||
| 183 | * 'realm' => 'my-realm', |
||
| 184 | * 'nonce' => 1235 |
||
| 185 | * )); |
||
| 186 | * }}} |
||
| 187 | * |
||
| 188 | * To remove any set authentication strategy, call `configAuth()` with no parameters: |
||
| 189 | * |
||
| 190 | * `$http->configAuth();` |
||
| 191 | * |
||
| 192 | * @param string $method Authentication method (ie. Basic, Digest). If empty, disable authentication |
||
| 193 | * @param string|array $user Username for authentication. Can be an array with settings to authentication class |
||
| 194 | * @param string $pass Password for authentication |
||
| 195 | * @return void |
||
| 196 | */ |
||
| 197 | public function configAuth($method, $user = null, $pass = null) { |
||
| 208 | |||
| 209 | /** |
||
| 210 | * Set proxy settings |
||
| 211 | * |
||
| 212 | * @param string|array $host Proxy host. Can be an array with settings to authentication class |
||
| 213 | * @param integer $port Port. Default 3128. |
||
| 214 | * @param string $method Proxy method (ie, Basic, Digest). If empty, disable proxy authentication |
||
| 215 | * @param string $user Username if your proxy need authentication |
||
| 216 | * @param string $pass Password to proxy authentication |
||
| 217 | * @return void |
||
| 218 | */ |
||
| 219 | public function configProxy($host, $port = 3128, $method = null, $user = null, $pass = null) { |
||
| 230 | |||
| 231 | /** |
||
| 232 | * Set the resource to receive the request content. This resource must support fwrite. |
||
| 233 | * |
||
| 234 | * @param resource|boolean $resource Resource or false to disable the resource use |
||
| 235 | * @return void |
||
| 236 | * @throws SocketException |
||
| 237 | */ |
||
| 238 | public function setContentResource($resource) { |
||
| 248 | |||
| 249 | /** |
||
| 250 | * Issue the specified request. HttpSocket::get() and HttpSocket::post() wrap this |
||
| 251 | * method and provide a more granular interface. |
||
| 252 | * |
||
| 253 | * @param string|array $request Either an URI string, or an array defining host/uri |
||
| 254 | * @return mixed false on error, HttpSocketResponse on success |
||
| 255 | * @throws SocketException |
||
| 256 | */ |
||
| 257 | public function request($request = array()) { |
||
| 423 | |||
| 424 | /** |
||
| 425 | * Issues a GET request to the specified URI, query, and request. |
||
| 426 | * |
||
| 427 | * Using a string uri and an array of query string parameters: |
||
| 428 | * |
||
| 429 | * `$response = $http->get('http://google.com/search', array('q' => 'cakephp', 'client' => 'safari'));` |
||
| 430 | * |
||
| 431 | * Would do a GET request to `http://google.com/search?q=cakephp&client=safari` |
||
| 432 | * |
||
| 433 | * You could express the same thing using a uri array and query string parameters: |
||
| 434 | * |
||
| 435 | * {{{ |
||
| 436 | * $response = $http->get( |
||
| 437 | * array('host' => 'google.com', 'path' => '/search'), |
||
| 438 | * array('q' => 'cakephp', 'client' => 'safari') |
||
| 439 | * ); |
||
| 440 | * }}} |
||
| 441 | * |
||
| 442 | * @param string|array $uri URI to request. Either a string uri, or a uri array, see HttpSocket::_parseUri() |
||
| 443 | * @param array $query Querystring parameters to append to URI |
||
| 444 | * @param array $request An indexed array with indexes such as 'method' or uri |
||
| 445 | * @return mixed Result of request, either false on failure or the response to the request. |
||
| 446 | */ |
||
| 447 | public function get($uri = null, $query = array(), $request = array()) { |
||
| 461 | |||
| 462 | /** |
||
| 463 | * Issues a POST request to the specified URI, query, and request. |
||
| 464 | * |
||
| 465 | * `post()` can be used to post simple data arrays to a URL: |
||
| 466 | * |
||
| 467 | * {{{ |
||
| 468 | * $response = $http->post('http://example.com', array( |
||
| 469 | * 'username' => 'batman', |
||
| 470 | * 'password' => 'bruce_w4yne' |
||
| 471 | * )); |
||
| 472 | * }}} |
||
| 473 | * |
||
| 474 | * @param string|array $uri URI to request. See HttpSocket::_parseUri() |
||
| 475 | * @param array $data Array of request body data keys and values. |
||
| 476 | * @param array $request An indexed array with indexes such as 'method' or uri |
||
| 477 | * @return mixed Result of request, either false on failure or the response to the request. |
||
| 478 | */ |
||
| 479 | public function post($uri = null, $data = array(), $request = array()) { |
||
| 483 | |||
| 484 | /** |
||
| 485 | * Issues a PUT request to the specified URI, query, and request. |
||
| 486 | * |
||
| 487 | * @param string|array $uri URI to request, See HttpSocket::_parseUri() |
||
| 488 | * @param array $data Array of request body data keys and values. |
||
| 489 | * @param array $request An indexed array with indexes such as 'method' or uri |
||
| 490 | * @return mixed Result of request |
||
| 491 | */ |
||
| 492 | public function put($uri = null, $data = array(), $request = array()) { |
||
| 496 | |||
| 497 | /** |
||
| 498 | * Issues a PATCH request to the specified URI, query, and request. |
||
| 499 | * |
||
| 500 | * @param string|array $uri URI to request, See HttpSocket::_parseUri() |
||
| 501 | * @param array $data Array of request body data keys and values. |
||
| 502 | * @param array $request An indexed array with indexes such as 'method' or uri |
||
| 503 | * @return mixed Result of request |
||
| 504 | */ |
||
| 505 | public function patch($uri = null, $data = array(), $request = array()) { |
||
| 509 | |||
| 510 | /** |
||
| 511 | * Issues a DELETE request to the specified URI, query, and request. |
||
| 512 | * |
||
| 513 | * @param string|array $uri URI to request (see {@link _parseUri()}) |
||
| 514 | * @param array $data Array of request body data keys and values. |
||
| 515 | * @param array $request An indexed array with indexes such as 'method' or uri |
||
| 516 | * @return mixed Result of request |
||
| 517 | */ |
||
| 518 | public function delete($uri = null, $data = array(), $request = array()) { |
||
| 522 | |||
| 523 | /** |
||
| 524 | * Normalizes URLs into a $uriTemplate. If no template is provided |
||
| 525 | * a default one will be used. Will generate the URL using the |
||
| 526 | * current config information. |
||
| 527 | * |
||
| 528 | * ### Usage: |
||
| 529 | * |
||
| 530 | * After configuring part of the request parameters, you can use url() to generate |
||
| 531 | * URLs. |
||
| 532 | * |
||
| 533 | * {{{ |
||
| 534 | * $http = new HttpSocket('http://www.cakephp.org'); |
||
| 535 | * $url = $http->url('/search?q=bar'); |
||
| 536 | * }}} |
||
| 537 | * |
||
| 538 | * Would return `http://www.cakephp.org/search?q=bar` |
||
| 539 | * |
||
| 540 | * url() can also be used with custom templates: |
||
| 541 | * |
||
| 542 | * `$url = $http->url('http://www.cakephp/search?q=socket', '/%path?%query');` |
||
| 543 | * |
||
| 544 | * Would return `/search?q=socket`. |
||
| 545 | * |
||
| 546 | * @param string|array Either a string or array of URL options to create a URL with. |
||
| 547 | * @param string $uriTemplate A template string to use for URL formatting. |
||
| 548 | * @return mixed Either false on failure or a string containing the composed URL. |
||
| 549 | */ |
||
| 550 | public function url($url = null, $uriTemplate = null) { |
||
| 585 | |||
| 586 | /** |
||
| 587 | * Set authentication in request |
||
| 588 | * |
||
| 589 | * @return void |
||
| 590 | * @throws SocketException |
||
| 591 | */ |
||
| 592 | protected function _setAuth() { |
||
| 609 | |||
| 610 | /** |
||
| 611 | * Set the proxy configuration and authentication |
||
| 612 | * |
||
| 613 | * @return void |
||
| 614 | * @throws SocketException |
||
| 615 | */ |
||
| 616 | protected function _setProxy() { |
||
| 638 | |||
| 639 | /** |
||
| 640 | * Parses and sets the specified URI into current request configuration. |
||
| 641 | * |
||
| 642 | * @param string|array $uri URI, See HttpSocket::_parseUri() |
||
| 643 | * @return boolean If uri has merged in config |
||
| 644 | */ |
||
| 645 | protected function _configUri($uri = null) { |
||
| 668 | |||
| 669 | /** |
||
| 670 | * Configure the socket's context. Adds in configuration |
||
| 671 | * that can not be declared in the class definition. |
||
| 672 | * |
||
| 673 | * @param string $host The host you're connecting to. |
||
| 674 | * @return void |
||
| 675 | */ |
||
| 676 | protected function _configContext($host) { |
||
| 695 | |||
| 696 | /** |
||
| 697 | * Takes a $uri array and turns it into a fully qualified URL string |
||
| 698 | * |
||
| 699 | * @param string|array $uri Either A $uri array, or a request string. Will use $this->config if left empty. |
||
| 700 | * @param string $uriTemplate The Uri template/format to use. |
||
| 701 | * @return mixed A fully qualified URL formatted according to $uriTemplate, or false on failure |
||
| 702 | */ |
||
| 703 | protected function _buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') { |
||
| 742 | |||
| 743 | /** |
||
| 744 | * Parses the given URI and breaks it down into pieces as an indexed array with elements |
||
| 745 | * such as 'scheme', 'port', 'query'. |
||
| 746 | * |
||
| 747 | * @param string|array $uri URI to parse |
||
| 748 | * @param boolean|array $base If true use default URI config, otherwise indexed array to set 'scheme', 'host', 'port', etc. |
||
| 749 | * @return array Parsed URI |
||
| 750 | */ |
||
| 751 | protected function _parseUri($uri = null, $base = array()) { |
||
| 801 | |||
| 802 | /** |
||
| 803 | * This function can be thought of as a reverse to PHP5's http_build_query(). It takes a given query string and turns it into an array and |
||
| 804 | * supports nesting by using the php bracket syntax. So this means you can parse queries like: |
||
| 805 | * |
||
| 806 | * - ?key[subKey]=value |
||
| 807 | * - ?key[]=value1&key[]=value2 |
||
| 808 | * |
||
| 809 | * A leading '?' mark in $query is optional and does not effect the outcome of this function. |
||
| 810 | * For the complete capabilities of this implementation take a look at HttpSocketTest::testparseQuery() |
||
| 811 | * |
||
| 812 | * @param string|array $query A query string to parse into an array or an array to return directly "as is" |
||
| 813 | * @return array The $query parsed into a possibly multi-level array. If an empty $query is |
||
| 814 | * given, an empty array is returned. |
||
| 815 | */ |
||
| 816 | protected function _parseQuery($query) { |
||
| 871 | |||
| 872 | /** |
||
| 873 | * Builds a request line according to HTTP/1.1 specs. Activate quirks mode to work outside specs. |
||
| 874 | * |
||
| 875 | * @param array $request Needs to contain a 'uri' key. Should also contain a 'method' key, otherwise defaults to GET. |
||
| 876 | * @param string $versionToken The version token to use, defaults to HTTP/1.1 |
||
| 877 | * @return string Request line |
||
| 878 | * @throws SocketException |
||
| 879 | */ |
||
| 880 | protected function _buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') { |
||
| 908 | |||
| 909 | /** |
||
| 910 | * Builds the header. |
||
| 911 | * |
||
| 912 | * @param array $header Header to build |
||
| 913 | * @param string $mode |
||
| 914 | * @return string Header built from array |
||
| 915 | */ |
||
| 916 | protected function _buildHeader($header, $mode = 'standard') { |
||
| 948 | |||
| 949 | /** |
||
| 950 | * Builds cookie headers for a request. |
||
| 951 | * |
||
| 952 | * Cookies can either be in the format returned in responses, or |
||
| 953 | * a simple key => value pair. |
||
| 954 | * |
||
| 955 | * @param array $cookies Array of cookies to send with the request. |
||
| 956 | * @return string Cookie header string to be sent with the request. |
||
| 957 | */ |
||
| 958 | public function buildCookies($cookies) { |
||
| 970 | |||
| 971 | /** |
||
| 972 | * Escapes a given $token according to RFC 2616 (HTTP 1.1 specs) |
||
| 973 | * |
||
| 974 | * @param string $token Token to escape |
||
| 975 | * @param array $chars |
||
| 976 | * @return string Escaped token |
||
| 977 | */ |
||
| 978 | protected function _escapeToken($token, $chars = null) { |
||
| 983 | |||
| 984 | /** |
||
| 985 | * Gets escape chars according to RFC 2616 (HTTP 1.1 specs). |
||
| 986 | * |
||
| 987 | * @param boolean $hex true to get them as HEX values, false otherwise |
||
| 988 | * @param array $chars |
||
| 989 | * @return array Escape chars |
||
| 990 | */ |
||
| 991 | View Code Duplication | protected function _tokenEscapeChars($hex = true, $chars = null) { |
|
| 1010 | |||
| 1011 | /** |
||
| 1012 | * Resets the state of this HttpSocket instance to it's initial state (before Object::__construct got executed) or does |
||
| 1013 | * the same thing partially for the request and the response property only. |
||
| 1014 | * |
||
| 1015 | * @param boolean $full If set to false only HttpSocket::response and HttpSocket::request are reset |
||
| 1016 | * @return boolean True on success |
||
| 1017 | */ |
||
| 1018 | public function reset($full = true) { |
||
| 1031 | |||
| 1032 | } |
||
| 1033 |