WordPress.org

Make WordPress Core

Ticket #9072: 9072.patch

File 9072.patch, 11.6 KB (added by jacobsantos, 5 years ago)

Tested and working patch for Sockets. Will need a bit more testing, but it does handle requests and appears to work fine.

  • class-http.php

     
    9292                        if ( true === WP_Http_ExtHttp::test($args) ) { 
    9393                                $working_transport['exthttp'] = new WP_Http_ExtHttp(); 
    9494                                $blocking_transport[] = &$working_transport['exthttp']; 
    95                         } else if ( true === WP_Http_Curl::test($args) ) { 
     95                        } 
     96                        if ( true === WP_Http_Curl::test($args) ) { 
    9697                                $working_transport['curl'] = new WP_Http_Curl(); 
    9798                                $blocking_transport[] = &$working_transport['curl']; 
    98                         } else if ( true === WP_Http_Streams::test($args) ) { 
     99                        } 
     100                        if ( true === WP_Http_Sockets::test($args) ) { 
     101                                $working_transport['sockets'] = new WP_Http_Sockets(); 
     102                                $blocking_transport[] = &$working_transport['sockets']; 
     103                        } 
     104                        if ( true === WP_Http_Streams::test($args) ) { 
    99105                                $working_transport['streams'] = new WP_Http_Streams(); 
    100106                                $blocking_transport[] = &$working_transport['streams']; 
    101                         } else if ( true === WP_Http_Fopen::test($args) ) { 
     107                        } 
     108                        if ( true === WP_Http_Fopen::test($args) ) { 
    102109                                $working_transport['fopen'] = new WP_Http_Fopen(); 
    103110                                $blocking_transport[] = &$working_transport['fopen']; 
    104                         } else if ( true === WP_Http_Fsockopen::test($args) ) { 
     111                        } 
     112                        if ( true === WP_Http_Fsockopen::test($args) ) { 
    105113                                $working_transport['fsockopen'] = new WP_Http_Fsockopen(); 
    106114                                $blocking_transport[] = &$working_transport['fsockopen']; 
    107115                        } 
     
    142150                        if ( true === WP_Http_ExtHttp::test($args) ) { 
    143151                                $working_transport['exthttp'] = new WP_Http_ExtHttp(); 
    144152                                $blocking_transport[] = &$working_transport['exthttp']; 
    145                         } else if ( true === WP_Http_Curl::test($args) ) { 
     153                        } 
     154                        if ( true === WP_Http_Curl::test($args) ) { 
    146155                                $working_transport['curl'] = new WP_Http_Curl(); 
    147156                                $blocking_transport[] = &$working_transport['curl']; 
    148                         } else if ( true === WP_Http_Streams::test($args) ) { 
     157                        } 
     158                        if ( true === WP_Http_Sockets::test($args) ) { 
     159                                $working_transport['sockets'] = new WP_Http_Sockets(); 
     160                                $blocking_transport[] = &$working_transport['sockets']; 
     161                        } 
     162                        if ( true === WP_Http_Streams::test($args) ) { 
    149163                                $working_transport['streams'] = new WP_Http_Streams(); 
    150164                                $blocking_transport[] = &$working_transport['streams']; 
    151                         } else if ( true === WP_Http_Fsockopen::test($args) ) { 
     165                        } 
     166                        if ( true === WP_Http_Fsockopen::test($args) ) { 
    152167                                $working_transport['fsockopen'] = new WP_Http_Fsockopen(); 
    153168                                $blocking_transport[] = &$working_transport['fsockopen']; 
    154169                        } 
     
    11101125} 
    11111126 
    11121127/** 
     1128 * HTTP request method uses PHP5 sockets to retrieve the url. 
     1129 * 
     1130 * Actually, this works pretty well. It supports SSL, nonblocking, quick, handles redirection and, 
     1131 * if cURL is not available and on PHP5, this will be preferred. 
     1132 * 
     1133 * @package WordPress 
     1134 * @subpackage HTTP 
     1135 * @since {unknown} 
     1136 */ 
     1137class WP_Http_Sockets { 
     1138        /** 
     1139         * Send a HTTP request to a URI using streams with stream_socket_client(). 
     1140         * 
     1141         * @access public 
     1142         * @since {unknown} 
     1143         * 
     1144         * @param string $url 
     1145         * @param str|array $args Optional. Override the defaults. 
     1146         * @return array 'headers', 'body', 'cookies' and 'response' keys. 
     1147         */ 
     1148        function request($url, $args = array()) { 
     1149                $defaults = array( 
     1150                        'method' => 'GET', 'timeout' => 5, 
     1151                        'redirection' => 5, 'httpversion' => '1.0', 
     1152                        'blocking' => true, 
     1153                        'headers' => array(), 'body' => null, 'cookies' => array() 
     1154                ); 
     1155 
     1156                $r = wp_parse_args( $args, $defaults ); 
     1157 
     1158                // Construct Cookie: header if any cookies are set 
     1159                WP_Http::buildCookieHeader( $r ); 
     1160 
     1161                if ( isset($r['headers']['User-Agent']) ) { 
     1162                        $r['user-agent'] = $r['headers']['User-Agent']; 
     1163                        unset($r['headers']['User-Agent']); 
     1164                } else if( isset($r['headers']['user-agent']) ) { 
     1165                        $r['user-agent'] = $r['headers']['user-agent']; 
     1166                        unset($r['headers']['user-agent']); 
     1167                } 
     1168 
     1169                $arrURL = parse_url($url); 
     1170 
     1171                // Not the best check for URLs, but works for the purposes of what we are using it. 
     1172                if ( false === $arrURL ) 
     1173                        return new WP_Error('http_request_failed', sprintf(__('Malformed URL: %s'), $url)); 
     1174 
     1175                // Only do this check once. 
     1176                if ( ! isset($r['ssl']) ) 
     1177                        $r['ssl'] = $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl'; 
     1178 
     1179                // Nonblocking only works for SSL PHP 5.2.11+, might not work on Windows. 
     1180                // http://bugs.php.net/48182 
     1181                if( $r['ssl'] && ! $r['blocking'] && version_compare(PHP_VERSION, '5.2.11', '<') ) 
     1182                        return new WP_Error('http_request_failed', __('Not possible to do nonblocking request with SSL.')); 
     1183 
     1184                // Create socket context. You only have ssl and socket transports. Socket has few options, 
     1185                // none that matter for HTTP requests. SSL has quite a few and we set those later. 
     1186                $context = stream_context_create(); 
     1187 
     1188                $host = "tcp://".$arrURL['host'].':'.( isset($arrURL['port']) ? $arrURL['port'] : '80' ); 
     1189 
     1190                if ( $r['ssl'] && extension_loaded('openssl') && in_array( 'ssl', stream_get_transports() ) ) { 
     1191                        $host = "ssl://".$arrURL['host'].':'.( isset($arrURL['port']) ? $arrURL['port'] : '443' ); 
     1192 
     1193                        $is_local = isset($r['local']) && $r['local']; 
     1194                        $ssl_verify = isset($r['sslverify']) && $r['sslverify']; 
     1195                        if ( $is_local ) 
     1196                                $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify); 
     1197                        elseif ( ! $is_local ) 
     1198                                $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify); 
     1199 
     1200                        stream_context_set_option($context, 'ssl', 'verify_peer', $ssl_verify); 
     1201                        stream_context_set_option($context, 'ssl', 'verify_host', $ssl_verify); 
     1202                } 
     1203 
     1204                // This is the message body for the request, it includes the header and the body if available. 
     1205                // It works similar to Fsockopen, in that it doesn't handle HTTP protocol directly. 
     1206                $request_message = $this->_build_request_message($r, $url, $arrURL); 
     1207 
     1208                // Holds the error number. 
     1209                $error_num = 0; 
     1210 
     1211                // Holds the error string. 
     1212                $error_string = ''; 
     1213 
     1214                $proxy = new WP_HTTP_Proxy(); 
     1215 
     1216                $flags = STREAM_CLIENT_CONNECT; 
     1217                if ( ! $r['blocking'] ) 
     1218                        $flags = STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT; 
     1219 
     1220                // stream_socket_client only supports tcp and udp, change to tcp for HTTP protocol. 
     1221                if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) 
     1222                        $handle = stream_socket_client( $proxy->host().':'.$proxy->port(), $error_num, $error_string, $r['timeout'], $flags, $context ); 
     1223                else 
     1224                        $handle = stream_socket_client( $host, $error_num, $error_string, $r['timeout'], $flags, $context ); 
     1225 
     1226                if ( ! $handle ) 
     1227                        return new WP_Error('http_request_failed', sprintf(__('Could not open handle for stream_socket_client() to %s'), $url)); 
     1228 
     1229                $timeout = (int) floor( $r['timeout'] ); 
     1230                $utimeout = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000; 
     1231 
     1232                if ( ! $r['blocking'] ) { 
     1233                        stream_set_blocking($handle, 0); 
     1234                        $read = $except = null; 
     1235                        $write = array($handle); 
     1236                        while ( ! empty( $request_message ) ) { 
     1237                                $nonblocking = stream_select($read, $write, $except, $timeout, $utimeout); 
     1238 
     1239                                if ( $nonblocking === false ) 
     1240                                        return new WP_Error('http_request_failed', sprintf(__('Could not handle nonblocking request to %s'), $url)); 
     1241 
     1242                                // Short requests should complete after the first try, but longer ones will only 
     1243                                // send so much before kicking it back out. 
     1244                                $bytes_written = fwrite( $handle, $request_message, strlen($request_message) ); 
     1245 
     1246                                // Dare god I hope this works. May mess up with UTF8 strings, but the execution after will catch it. 
     1247                                if ( $bytes_written == strlen($request_message) ) 
     1248                                        break; 
     1249 
     1250                                $request_message = substr($request_message, $bytes_written); 
     1251                        } 
     1252 
     1253                        fclose($handle); 
     1254                        return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() ); 
     1255                } else { 
     1256                        // We don't use stream_set_timeout with stream_select(); 
     1257                        stream_set_timeout( $handle, $timeout, $utimeout ); 
     1258                } 
     1259                 
     1260                while ( ! empty( $request_message ) ) { 
     1261                        // Short requests should complete after the first try, but longer ones will only send so 
     1262                        // much before kicking it back out. 
     1263                        $bytes_written = fwrite( $handle, $request_message, strlen($request_message) ); 
     1264 
     1265                        if ( $bytes_written == strlen($request_message) ) 
     1266                                break; 
     1267 
     1268                        $request_message = substr($request_message, $bytes_written); 
     1269                } 
     1270 
     1271                $response = stream_get_contents($handle); 
     1272 
     1273                fclose($handle); 
     1274 
     1275                $process = WP_Http::processResponse($response); 
     1276                $arrHeaders = WP_Http::processHeaders($process['headers']); 
     1277 
     1278                // Is the response code within the 400 range? 
     1279                if ( (int) $arrHeaders['response']['code'] >= 400 && (int) $arrHeaders['response']['code'] < 500 ) 
     1280                        return new WP_Error('http_request_failed', $arrHeaders['response']['code'] . ': ' . $arrHeaders['response']['message']); 
     1281 
     1282                // If location is found, then assume redirect and redirect to location. 
     1283                if ( 'HEAD' != $r['method'] && isset($arrHeaders['headers']['location']) ) { 
     1284                        if ( $r['redirection']-- > 0 ) { 
     1285                                return $this->request($arrHeaders['headers']['location'], $r); 
     1286                        } else { 
     1287                                return new WP_Error('http_request_failed', __('Too many redirects.')); 
     1288                        } 
     1289                } 
     1290 
     1291                // If the body was chunk encoded, then decode it. 
     1292                if ( ! empty( $process['body'] ) && isset( $arrHeaders['headers']['transfer-encoding'] ) && 'chunked' == $arrHeaders['headers']['transfer-encoding'] ) 
     1293                        $process['body'] = WP_Http::chunkTransferDecode($process['body']); 
     1294 
     1295                if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($arrHeaders['headers']) ) 
     1296                        $process['body'] = WP_Http_Encoding::decompress( $process['body'] ); 
     1297 
     1298                return array('headers' => $arrHeaders['headers'], 'body' => $process['body'], 'response' => $arrHeaders['response'], 'cookies' => $arrHeaders['cookies']); 
     1299        } 
     1300 
     1301        /** 
     1302         * Builds the request message for sending to the URL. 
     1303         * 
     1304         * @access private 
     1305         * @since {unknown} 
     1306         * 
     1307         * @param array $r Request arguments. 
     1308         * @param string $url URL string. 
     1309         * @param array $arrURL Processed URL string. 
     1310         * @return string Full request message. 
     1311         */ 
     1312        function _build_request_message($r, $url, &$arrURL) { 
     1313                $proxy = new WP_HTTP_Proxy(); 
     1314 
     1315                // Create request headers and combine body. 
     1316                if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) //Some proxies require full URL in this field. 
     1317                        $requestPath = $url; 
     1318                else 
     1319                        $requestPath = $arrURL['path'] . ( isset($arrURL['query']) ? '?' . $arrURL['query'] : '' ); 
     1320 
     1321                if ( empty($requestPath) ) 
     1322                        $requestPath .= '/'; 
     1323 
     1324                $strHeaders = strtoupper($r['method']) . ' ' . $requestPath . ' HTTP/' . $r['httpversion'] . "\r\n"; 
     1325 
     1326                if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) 
     1327                        $strHeaders .= 'Host: ' . $arrURL['host'] . ':' . $arrURL['port'] . "\r\n"; 
     1328                else 
     1329                        $strHeaders .= 'Host: ' . $arrURL['host'] . "\r\n"; 
     1330 
     1331                if ( isset($r['user-agent']) ) 
     1332                        $strHeaders .= 'User-agent: ' . $r['user-agent'] . "\r\n"; 
     1333 
     1334                if ( is_array($r['headers']) ) { 
     1335                        foreach ( (array) $r['headers'] as $header => $headerValue ) 
     1336                                $strHeaders .= $header . ': ' . $headerValue . "\r\n"; 
     1337                } else { 
     1338                        $strHeaders .= $r['headers']; 
     1339                } 
     1340 
     1341                if ( $proxy->use_authentication() ) 
     1342                        $strHeaders .= $proxy->authentication_header() . "\r\n"; 
     1343 
     1344                $strHeaders .= "\r\n"; 
     1345 
     1346                if ( ! is_null($r['body']) ) 
     1347                        $strHeaders .= $r['body']; 
     1348 
     1349                return $strHeaders; 
     1350        } 
     1351 
     1352        /** 
     1353         * Whether this class can be used for retrieving an URL. 
     1354         * 
     1355         * @static 
     1356         * @access public 
     1357         * @since {unknown} 
     1358         * 
     1359         * @return boolean False means this class can not be used, true means it can. 
     1360         */ 
     1361        function test($args = array()) { 
     1362                if ( ! function_exists('stream_socket_client') ) 
     1363                        return false; 
     1364 
     1365                return apply_filters('use_socket_transport', true, $args); 
     1366        } 
     1367} 
     1368 
     1369/** 
    11131370 * HTTP request method uses HTTP extension to retrieve the url. 
    11141371 * 
    11151372 * Requires the HTTP extension to be installed. This would be the preferred transport since it can