wp/wp-includes/Requests/Transport/fsockopen.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
    60 
    60 
    61 		$url_parts = parse_url($url);
    61 		$url_parts = parse_url($url);
    62 		if (empty($url_parts)) {
    62 		if (empty($url_parts)) {
    63 			throw new Requests_Exception('Invalid URL.', 'invalidurl', $url);
    63 			throw new Requests_Exception('Invalid URL.', 'invalidurl', $url);
    64 		}
    64 		}
    65 		$host = $url_parts['host'];
    65 		$host                     = $url_parts['host'];
    66 		$context = stream_context_create();
    66 		$context                  = stream_context_create();
    67 		$verifyname = false;
    67 		$verifyname               = false;
    68 		$case_insensitive_headers = new Requests_Utility_CaseInsensitiveDictionary($headers);
    68 		$case_insensitive_headers = new Requests_Utility_CaseInsensitiveDictionary($headers);
    69 
    69 
    70 		// HTTPS support
    70 		// HTTPS support
    71 		if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
    71 		if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
    72 			$remote_socket = 'ssl://' . $host;
    72 			$remote_socket = 'ssl://' . $host;
    73 			if (!isset($url_parts['port'])) {
    73 			if (!isset($url_parts['port'])) {
    74 				$url_parts['port'] = 443;
    74 				$url_parts['port'] = 443;
    75 			}
    75 			}
    76 
    76 
    77 			$context_options = array(
    77 			$context_options = array(
    78 				'verify_peer' => true,
    78 				'verify_peer'       => true,
    79 				// 'CN_match' => $host,
    79 				'capture_peer_cert' => true,
    80 				'capture_peer_cert' => true
       
    81 			);
    80 			);
    82 			$verifyname = true;
    81 			$verifyname      = true;
    83 
    82 
    84 			// SNI, if enabled (OpenSSL >=0.9.8j)
    83 			// SNI, if enabled (OpenSSL >=0.9.8j)
       
    84 			// phpcs:ignore PHPCompatibility.Constants.NewConstants.openssl_tlsext_server_nameFound
    85 			if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) {
    85 			if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) {
    86 				$context_options['SNI_enabled'] = true;
    86 				$context_options['SNI_enabled'] = true;
    87 				if (isset($options['verifyname']) && $options['verifyname'] === false) {
    87 				if (isset($options['verifyname']) && $options['verifyname'] === false) {
    88 					$context_options['SNI_enabled'] = false;
    88 					$context_options['SNI_enabled'] = false;
    89 				}
    89 				}
    90 			}
    90 			}
    91 
    91 
    92 			if (isset($options['verify'])) {
    92 			if (isset($options['verify'])) {
    93 				if ($options['verify'] === false) {
    93 				if ($options['verify'] === false) {
    94 					$context_options['verify_peer'] = false;
    94 					$context_options['verify_peer']      = false;
       
    95 					$context_options['verify_peer_name'] = false;
       
    96 					$verifyname                          = false;
    95 				}
    97 				}
    96 				elseif (is_string($options['verify'])) {
    98 				elseif (is_string($options['verify'])) {
    97 					$context_options['cafile'] = $options['verify'];
    99 					$context_options['cafile'] = $options['verify'];
    98 				}
   100 				}
    99 			}
   101 			}
   100 
   102 
   101 			if (isset($options['verifyname']) && $options['verifyname'] === false) {
   103 			if (isset($options['verifyname']) && $options['verifyname'] === false) {
   102 				$context_options['verify_peer_name'] = false;
   104 				$context_options['verify_peer_name'] = false;
   103 				$verifyname = false;
   105 				$verifyname                          = false;
   104 			}
   106 			}
   105 
   107 
   106 			stream_context_set_option($context, array('ssl' => $context_options));
   108 			stream_context_set_option($context, array('ssl' => $context_options));
   107 		}
   109 		}
   108 		else {
   110 		else {
   114 		if (!isset($url_parts['port'])) {
   116 		if (!isset($url_parts['port'])) {
   115 			$url_parts['port'] = 80;
   117 			$url_parts['port'] = 80;
   116 		}
   118 		}
   117 		$remote_socket .= ':' . $url_parts['port'];
   119 		$remote_socket .= ':' . $url_parts['port'];
   118 
   120 
       
   121 		// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
   119 		set_error_handler(array($this, 'connect_error_handler'), E_WARNING | E_NOTICE);
   122 		set_error_handler(array($this, 'connect_error_handler'), E_WARNING | E_NOTICE);
   120 
   123 
   121 		$options['hooks']->dispatch('fsockopen.remote_socket', array(&$remote_socket));
   124 		$options['hooks']->dispatch('fsockopen.remote_socket', array(&$remote_socket));
   122 
   125 
   123 		$socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context);
   126 		$socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context);
   148 		}
   151 		}
   149 
   152 
   150 		$options['hooks']->dispatch('fsockopen.remote_host_path', array(&$path, $url));
   153 		$options['hooks']->dispatch('fsockopen.remote_host_path', array(&$path, $url));
   151 
   154 
   152 		$request_body = '';
   155 		$request_body = '';
   153 		$out = sprintf("%s %s HTTP/%.1F\r\n", $options['type'], $path, $options['protocol_version']);
   156 		$out          = sprintf("%s %s HTTP/%.1F\r\n", $options['type'], $path, $options['protocol_version']);
   154 
   157 
   155 		if ($options['type'] !== Requests::TRACE) {
   158 		if ($options['type'] !== Requests::TRACE) {
   156 			if (is_array($data)) {
   159 			if (is_array($data)) {
   157 				$request_body = http_build_query($data, null, '&');
   160 				$request_body = http_build_query($data, '', '&');
   158 			}
   161 			}
   159 			else {
   162 			else {
   160 				$request_body = $data;
   163 				$request_body = $data;
   161 			}
   164 			}
   162 
   165 
   163 			if (!empty($data)) {
   166 			// Always include Content-length on POST requests to prevent
       
   167 			// 411 errors from some servers when the body is empty.
       
   168 			if (!empty($data) || $options['type'] === Requests::POST) {
   164 				if (!isset($case_insensitive_headers['Content-Length'])) {
   169 				if (!isset($case_insensitive_headers['Content-Length'])) {
   165 					$headers['Content-Length'] = strlen($request_body);
   170 					$headers['Content-Length'] = strlen($request_body);
   166 				}
   171 				}
   167 
   172 
   168 				if (!isset($case_insensitive_headers['Content-Type'])) {
   173 				if (!isset($case_insensitive_headers['Content-Type'])) {
   172 		}
   177 		}
   173 
   178 
   174 		if (!isset($case_insensitive_headers['Host'])) {
   179 		if (!isset($case_insensitive_headers['Host'])) {
   175 			$out .= sprintf('Host: %s', $url_parts['host']);
   180 			$out .= sprintf('Host: %s', $url_parts['host']);
   176 
   181 
   177 			if (( 'http' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 80 ) || ( 'https' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 443 )) {
   182 			if ((strtolower($url_parts['scheme']) === 'http' && $url_parts['port'] !== 80) || (strtolower($url_parts['scheme']) === 'https' && $url_parts['port'] !== 443)) {
   178 				$out .= ':' . $url_parts['port'];
   183 				$out .= ':' . $url_parts['port'];
   179 			}
   184 			}
   180 			$out .= "\r\n";
   185 			$out .= "\r\n";
   181 		}
   186 		}
   182 
   187 
   218 			$options['hooks']->dispatch('fsockopen.after_request', array(&$fake_headers));
   223 			$options['hooks']->dispatch('fsockopen.after_request', array(&$fake_headers));
   219 			return '';
   224 			return '';
   220 		}
   225 		}
   221 
   226 
   222 		$timeout_sec = (int) floor($options['timeout']);
   227 		$timeout_sec = (int) floor($options['timeout']);
   223 		if ($timeout_sec == $options['timeout']) {
   228 		if ($timeout_sec === $options['timeout']) {
   224 			$timeout_msec = 0;
   229 			$timeout_msec = 0;
   225 		}
   230 		}
   226 		else {
   231 		else {
   227 			$timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS;
   232 			$timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS;
   228 		}
   233 		}
   229 		stream_set_timeout($socket, $timeout_sec, $timeout_msec);
   234 		stream_set_timeout($socket, $timeout_sec, $timeout_msec);
   230 
   235 
   231 		$response = $body = $headers = '';
   236 		$response   = '';
       
   237 		$body       = '';
       
   238 		$headers    = '';
   232 		$this->info = stream_get_meta_data($socket);
   239 		$this->info = stream_get_meta_data($socket);
   233 		$size = 0;
   240 		$size       = 0;
   234 		$doingbody = false;
   241 		$doingbody  = false;
   235 		$download = false;
   242 		$download   = false;
   236 		if ($options['filename']) {
   243 		if ($options['filename']) {
   237 			$download = fopen($options['filename'], 'wb');
   244 			$download = fopen($options['filename'], 'wb');
   238 		}
   245 		}
   239 
   246 
   240 		while (!feof($socket)) {
   247 		while (!feof($socket)) {
   246 			$block = fread($socket, Requests::BUFFER_SIZE);
   253 			$block = fread($socket, Requests::BUFFER_SIZE);
   247 			if (!$doingbody) {
   254 			if (!$doingbody) {
   248 				$response .= $block;
   255 				$response .= $block;
   249 				if (strpos($response, "\r\n\r\n")) {
   256 				if (strpos($response, "\r\n\r\n")) {
   250 					list($headers, $block) = explode("\r\n\r\n", $response, 2);
   257 					list($headers, $block) = explode("\r\n\r\n", $response, 2);
   251 					$doingbody = true;
   258 					$doingbody             = true;
   252 				}
   259 				}
   253 			}
   260 			}
   254 
   261 
   255 			// Are we in body mode now?
   262 			// Are we in body mode now?
   256 			if ($doingbody) {
   263 			if ($doingbody) {
   262 						continue;
   269 						continue;
   263 					}
   270 					}
   264 					if (($size + $data_length) > $this->max_bytes) {
   271 					if (($size + $data_length) > $this->max_bytes) {
   265 						// Limit the length
   272 						// Limit the length
   266 						$limited_length = ($this->max_bytes - $size);
   273 						$limited_length = ($this->max_bytes - $size);
   267 						$block = substr($block, 0, $limited_length);
   274 						$block          = substr($block, 0, $limited_length);
   268 					}
   275 					}
   269 				}
   276 				}
   270 
   277 
   271 				$size += strlen($block);
   278 				$size += strlen($block);
   272 				if ($download) {
   279 				if ($download) {
   298 	 * @param array $options Global options, see {@see Requests::response()} for documentation
   305 	 * @param array $options Global options, see {@see Requests::response()} for documentation
   299 	 * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
   306 	 * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
   300 	 */
   307 	 */
   301 	public function request_multiple($requests, $options) {
   308 	public function request_multiple($requests, $options) {
   302 		$responses = array();
   309 		$responses = array();
   303 		$class = get_class($this);
   310 		$class     = get_class($this);
   304 		foreach ($requests as $id => $request) {
   311 		foreach ($requests as $id => $request) {
   305 			try {
   312 			try {
   306 				$handler = new $class();
   313 				$handler        = new $class();
   307 				$responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']);
   314 				$responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']);
   308 
   315 
   309 				$request['options']['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$id], $request));
   316 				$request['options']['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$id], $request));
   310 			}
   317 			}
   311 			catch (Requests_Exception $e) {
   318 			catch (Requests_Exception $e) {
   351 		if (!empty($data)) {
   358 		if (!empty($data)) {
   352 			if (empty($url_parts['query'])) {
   359 			if (empty($url_parts['query'])) {
   353 				$url_parts['query'] = '';
   360 				$url_parts['query'] = '';
   354 			}
   361 			}
   355 
   362 
   356 			$url_parts['query'] .= '&' . http_build_query($data, null, '&');
   363 			$url_parts['query'] .= '&' . http_build_query($data, '', '&');
   357 			$url_parts['query'] = trim($url_parts['query'], '&');
   364 			$url_parts['query']  = trim($url_parts['query'], '&');
   358 		}
   365 		}
   359 		if (isset($url_parts['path'])) {
   366 		if (isset($url_parts['path'])) {
   360 			if (isset($url_parts['query'])) {
   367 			if (isset($url_parts['query'])) {
   361 				$get = $url_parts['path'] . '?' . $url_parts['query'];
   368 				$get = $url_parts['path'] . '?' . $url_parts['query'];
   362 			}
   369 			}