Esempio n. 1
0
	public function execute() {
		wfProfileIn( __METHOD__ );

		parent::execute();

		if ( is_array( $this->postData ) ) {
			$this->postData = wfArrayToCgi( $this->postData );
		}

		if ( $this->parsedUrl['scheme'] != 'http' &&
			 $this->parsedUrl['scheme'] != 'https' ) {
			$this->status->fatal( 'http-invalid-scheme', $this->parsedUrl['scheme'] );
		}

		$this->reqHeaders['Accept'] = "*/*";
		if ( $this->method == 'POST' ) {
			// Required for HTTP 1.0 POSTs
			$this->reqHeaders['Content-Length'] = strlen( $this->postData );
			if ( !isset( $this->reqHeaders['Content-Type'] ) ) {
				$this->reqHeaders['Content-Type'] = "application/x-www-form-urlencoded";
			}
		}

		$options = array();
		if ( $this->proxy ) {
			$options['proxy'] = $this->urlToTCP( $this->proxy );
			$options['request_fulluri'] = true;
		}

		if ( !$this->followRedirects ) {
			$options['max_redirects'] = 0;
		} else {
			$options['max_redirects'] = $this->maxRedirects;
		}

		$options['method'] = $this->method;
		$options['header'] = implode( "\r\n", $this->getHeaderList() );
		// Note that at some future point we may want to support
		// HTTP/1.1, but we'd have to write support for chunking
		// in version of PHP < 5.3.1
		$options['protocol_version'] = "1.0";

		// This is how we tell PHP we want to deal with 404s (for example) ourselves.
		// Only works on 5.2.10+
		$options['ignore_errors'] = true;

		if ( $this->postData ) {
			$options['content'] = $this->postData;
		}

		$options['timeout'] = $this->timeout;

		if ( $this->sslVerifyHost ) {
			$options['CN_match'] = $this->parsedUrl['host'];
		}
		if ( $this->sslVerifyCert ) {
			$options['verify_peer'] = true;
		}

		if ( is_dir( $this->caInfo ) ) {
			$options['capath'] = $this->caInfo;
		} elseif ( is_file( $this->caInfo ) ) {
			$options['cafile'] = $this->caInfo;
		} elseif ( $this->caInfo ) {
			throw new MWException( "Invalid CA info passed: {$this->caInfo}" );
		}

		$scheme = $this->parsedUrl['scheme'];
		$context = stream_context_create( array( "$scheme" => $options ) );

		$this->headerList = array();
		$reqCount = 0;
		$url = $this->url;

		$result = array();

		do {
			$reqCount++;
			wfSuppressWarnings();
			$fh = fopen( $url, "r", false, $context );
			wfRestoreWarnings();

			if ( !$fh ) {
				break;
			}

			$result = stream_get_meta_data( $fh );
			$this->headerList = $result['wrapper_data'];
			$this->parseHeader();

			if ( !$this->followRedirects ) {
				break;
			}

			# Handle manual redirection
			if ( !$this->isRedirect() || $reqCount > $this->maxRedirects ) {
				break;
			}
			# Check security of URL
			$url = $this->getResponseHeader( "Location" );

			if ( !Http::isValidURI( $url ) ) {
				wfDebug( __METHOD__ . ": insecure redirection\n" );
				break;
			}
		} while ( true );

		$this->setStatus();

		if ( $fh === false ) {
			$this->status->fatal( 'http-request-error' );
			wfProfileOut( __METHOD__ );
			return $this->status;
		}

		if ( $result['timed_out'] ) {
			$this->status->fatal( 'http-timed-out', $this->url );
			wfProfileOut( __METHOD__ );
			return $this->status;
		}

		// If everything went OK, or we received some error code
		// get the response body content.
		if ( $this->status->isOK() || (int)$this->respStatus >= 300 ) {
			while ( !feof( $fh ) ) {
				$buf = fread( $fh, 8192 );

				if ( $buf === false ) {
					$this->status->fatal( 'http-read-error' );
					break;
				}

				if ( strlen( $buf ) ) {
					call_user_func( $this->callback, $fh, $buf );
				}
			}
		}
		fclose( $fh );

		wfProfileOut( __METHOD__ );

		return $this->status;
	}
Esempio n. 2
0
 public function execute()
 {
     parent::execute();
     if (is_array($this->postData)) {
         $this->postData = wfArrayToCgi($this->postData);
     }
     if ($this->parsedUrl['scheme'] != 'http' && $this->parsedUrl['scheme'] != 'https') {
         $this->status->fatal('http-invalid-scheme', $this->parsedUrl['scheme']);
     }
     $this->reqHeaders['Accept'] = "*/*";
     $this->reqHeaders['Connection'] = 'Close';
     if ($this->method == 'POST') {
         // Required for HTTP 1.0 POSTs
         $this->reqHeaders['Content-Length'] = strlen($this->postData);
         if (!isset($this->reqHeaders['Content-Type'])) {
             $this->reqHeaders['Content-Type'] = "application/x-www-form-urlencoded";
         }
     }
     // Set up PHP stream context
     $options = ['http' => ['method' => $this->method, 'header' => implode("\r\n", $this->getHeaderList()), 'protocol_version' => '1.1', 'max_redirects' => $this->followRedirects ? $this->maxRedirects : 0, 'ignore_errors' => true, 'timeout' => $this->timeout, 'curl_verify_ssl_host' => $this->sslVerifyHost ? 2 : 0, 'curl_verify_ssl_peer' => $this->sslVerifyCert], 'ssl' => ['verify_peer' => $this->sslVerifyCert, 'SNI_enabled' => true, 'ciphers' => 'HIGH:!SSLv2:!SSLv3:-ADH:-kDH:-kECDH:-DSS', 'disable_compression' => true]];
     if ($this->proxy) {
         $options['http']['proxy'] = $this->urlToTcp($this->proxy);
         $options['http']['request_fulluri'] = true;
     }
     if ($this->postData) {
         $options['http']['content'] = $this->postData;
     }
     if ($this->sslVerifyHost) {
         // PHP 5.6.0 deprecates CN_match, in favour of peer_name which
         // actually checks SubjectAltName properly.
         if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
             $options['ssl']['peer_name'] = $this->parsedUrl['host'];
         } else {
             $options['ssl']['CN_match'] = $this->parsedUrl['host'];
         }
     }
     $options['ssl'] += $this->getCertOptions();
     $context = stream_context_create($options);
     $this->headerList = [];
     $reqCount = 0;
     $url = $this->url;
     $result = [];
     if ($this->profiler) {
         $profileSection = $this->profiler->scopedProfileIn(__METHOD__ . '-' . $this->profileName);
     }
     do {
         $reqCount++;
         $this->fopenErrors = [];
         set_error_handler([$this, 'errorHandler']);
         $fh = fopen($url, "r", false, $context);
         restore_error_handler();
         if (!$fh) {
             // HACK for instant commons.
             // If we are contacting (commons|upload).wikimedia.org
             // try again with CN_match for en.wikipedia.org
             // as php does not handle SubjectAltName properly
             // prior to "peer_name" option in php 5.6
             if (isset($options['ssl']['CN_match']) && ($options['ssl']['CN_match'] === 'commons.wikimedia.org' || $options['ssl']['CN_match'] === 'upload.wikimedia.org')) {
                 $options['ssl']['CN_match'] = 'en.wikipedia.org';
                 $context = stream_context_create($options);
                 continue;
             }
             break;
         }
         $result = stream_get_meta_data($fh);
         $this->headerList = $result['wrapper_data'];
         $this->parseHeader();
         if (!$this->followRedirects) {
             break;
         }
         # Handle manual redirection
         if (!$this->isRedirect() || $reqCount > $this->maxRedirects) {
             break;
         }
         # Check security of URL
         $url = $this->getResponseHeader("Location");
         if (!Http::isValidURI($url)) {
             $this->logger->debug(__METHOD__ . ": insecure redirection\n");
             break;
         }
     } while (true);
     if ($this->profiler) {
         $this->profiler->scopedProfileOut($profileSection);
     }
     $this->setStatus();
     if ($fh === false) {
         if ($this->fopenErrors) {
             $this->logger->warning(__CLASS__ . ': error opening connection: {errstr1}', $this->fopenErrors);
         }
         $this->status->fatal('http-request-error');
         return $this->status;
     }
     if ($result['timed_out']) {
         $this->status->fatal('http-timed-out', $this->url);
         return $this->status;
     }
     // If everything went OK, or we received some error code
     // get the response body content.
     if ($this->status->isOK() || (int) $this->respStatus >= 300) {
         while (!feof($fh)) {
             $buf = fread($fh, 8192);
             if ($buf === false) {
                 $this->status->fatal('http-read-error');
                 break;
             }
             if (strlen($buf)) {
                 call_user_func($this->callback, $fh, $buf);
             }
         }
     }
     fclose($fh);
     return $this->status;
 }
Esempio n. 3
0
 public function execute()
 {
     wfProfileIn(__METHOD__);
     parent::execute();
     if (is_array($this->postData)) {
         $this->postData = wfArrayToCgi($this->postData);
     }
     if ($this->parsedUrl['scheme'] != 'http' && $this->parsedUrl['scheme'] != 'https') {
         $this->status->fatal('http-invalid-scheme', $this->parsedUrl['scheme']);
     }
     $this->reqHeaders['Accept'] = "*/*";
     $this->reqHeaders['Connection'] = 'Close';
     if ($this->method == 'POST') {
         // Required for HTTP 1.0 POSTs
         $this->reqHeaders['Content-Length'] = strlen($this->postData);
         if (!isset($this->reqHeaders['Content-Type'])) {
             $this->reqHeaders['Content-Type'] = "application/x-www-form-urlencoded";
         }
     }
     // Set up PHP stream context
     $options = array('http' => array('method' => $this->method, 'header' => implode("\r\n", $this->getHeaderList()), 'protocol_version' => '1.1', 'max_redirects' => $this->followRedirects ? $this->maxRedirects : 0, 'ignore_errors' => true, 'timeout' => $this->timeout, 'curl_verify_ssl_host' => $this->sslVerifyHost ? 2 : 0, 'curl_verify_ssl_peer' => $this->sslVerifyCert), 'ssl' => array('verify_peer' => $this->sslVerifyCert, 'SNI_enabled' => true));
     if ($this->proxy) {
         $options['http']['proxy'] = $this->urlToTCP($this->proxy);
         $options['http']['request_fulluri'] = true;
     }
     if ($this->postData) {
         $options['http']['content'] = $this->postData;
     }
     if ($this->sslVerifyHost) {
         $options['ssl']['CN_match'] = $this->parsedUrl['host'];
     }
     if (is_dir($this->caInfo)) {
         $options['ssl']['capath'] = $this->caInfo;
     } elseif (is_file($this->caInfo)) {
         $options['ssl']['cafile'] = $this->caInfo;
     } elseif ($this->caInfo) {
         throw new MWException("Invalid CA info passed: {$this->caInfo}");
     }
     $context = stream_context_create($options);
     $this->headerList = array();
     $reqCount = 0;
     $url = $this->url;
     $result = array();
     do {
         $reqCount++;
         wfSuppressWarnings();
         $fh = fopen($url, "r", false, $context);
         wfRestoreWarnings();
         if (!$fh) {
             break;
         }
         $result = stream_get_meta_data($fh);
         $this->headerList = $result['wrapper_data'];
         $this->parseHeader();
         if (!$this->followRedirects) {
             break;
         }
         # Handle manual redirection
         if (!$this->isRedirect() || $reqCount > $this->maxRedirects) {
             break;
         }
         # Check security of URL
         $url = $this->getResponseHeader("Location");
         if (!Http::isValidURI($url)) {
             wfDebug(__METHOD__ . ": insecure redirection\n");
             break;
         }
     } while (true);
     $this->setStatus();
     if ($fh === false) {
         $this->status->fatal('http-request-error');
         wfProfileOut(__METHOD__);
         return $this->status;
     }
     if ($result['timed_out']) {
         $this->status->fatal('http-timed-out', $this->url);
         wfProfileOut(__METHOD__);
         return $this->status;
     }
     // If everything went OK, or we received some error code
     // get the response body content.
     if ($this->status->isOK() || (int) $this->respStatus >= 300) {
         while (!feof($fh)) {
             $buf = fread($fh, 8192);
             if ($buf === false) {
                 $this->status->fatal('http-read-error');
                 break;
             }
             if (strlen($buf)) {
                 call_user_func($this->callback, $fh, $buf);
             }
         }
     }
     fclose($fh);
     wfProfileOut(__METHOD__);
     return $this->status;
 }
Esempio n. 4
0
 public function execute()
 {
     parent::execute();
     if (!$this->status->isOK()) {
         return $this->status;
     }
     $this->curlOptions[CURLOPT_PROXY] = $this->proxy;
     $this->curlOptions[CURLOPT_TIMEOUT] = $this->timeout;
     // Only supported in curl >= 7.16.2
     if (defined('CURLOPT_CONNECTTIMEOUT_MS')) {
         $this->curlOptions[CURLOPT_CONNECTTIMEOUT_MS] = $this->connectTimeout * 1000;
     }
     $this->curlOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
     $this->curlOptions[CURLOPT_WRITEFUNCTION] = $this->callback;
     $this->curlOptions[CURLOPT_HEADERFUNCTION] = [$this, "readHeader"];
     $this->curlOptions[CURLOPT_MAXREDIRS] = $this->maxRedirects;
     $this->curlOptions[CURLOPT_ENCODING] = "";
     # Enable compression
     $this->curlOptions[CURLOPT_USERAGENT] = $this->reqHeaders['User-Agent'];
     $this->curlOptions[CURLOPT_SSL_VERIFYHOST] = $this->sslVerifyHost ? 2 : 0;
     $this->curlOptions[CURLOPT_SSL_VERIFYPEER] = $this->sslVerifyCert;
     if ($this->caInfo) {
         $this->curlOptions[CURLOPT_CAINFO] = $this->caInfo;
     }
     if ($this->headersOnly) {
         $this->curlOptions[CURLOPT_NOBODY] = true;
         $this->curlOptions[CURLOPT_HEADER] = true;
     } elseif ($this->method == 'POST') {
         $this->curlOptions[CURLOPT_POST] = true;
         $postData = $this->postData;
         // Don't interpret POST parameters starting with '@' as file uploads, because this
         // makes it impossible to POST plain values starting with '@' (and causes security
         // issues potentially exposing the contents of local files).
         // The PHP manual says this option was introduced in PHP 5.5 defaults to true in PHP 5.6,
         // but we support lower versions, and the option doesn't exist in HHVM 5.6.99.
         if (defined('CURLOPT_SAFE_UPLOAD')) {
             $this->curlOptions[CURLOPT_SAFE_UPLOAD] = true;
         } elseif (is_array($postData)) {
             // In PHP 5.2 and later, '@' is interpreted as a file upload if POSTFIELDS
             // is an array, but not if it's a string. So convert $req['body'] to a string
             // for safety.
             $postData = wfArrayToCgi($postData);
         }
         $this->curlOptions[CURLOPT_POSTFIELDS] = $postData;
         // Suppress 'Expect: 100-continue' header, as some servers
         // will reject it with a 417 and Curl won't auto retry
         // with HTTP 1.0 fallback
         $this->reqHeaders['Expect'] = '';
     } else {
         $this->curlOptions[CURLOPT_CUSTOMREQUEST] = $this->method;
     }
     $this->curlOptions[CURLOPT_HTTPHEADER] = $this->getHeaderList();
     $curlHandle = curl_init($this->url);
     if (!curl_setopt_array($curlHandle, $this->curlOptions)) {
         throw new MWException("Error setting curl options.");
     }
     if ($this->followRedirects && $this->canFollowRedirects()) {
         MediaWiki\suppressWarnings();
         if (!curl_setopt($curlHandle, CURLOPT_FOLLOWLOCATION, true)) {
             $this->logger->debug(__METHOD__ . ": Couldn't set CURLOPT_FOLLOWLOCATION. " . "Probably open_basedir is set.\n");
             // Continue the processing. If it were in curl_setopt_array,
             // processing would have halted on its entry
         }
         MediaWiki\restoreWarnings();
     }
     if ($this->profiler) {
         $profileSection = $this->profiler->scopedProfileIn(__METHOD__ . '-' . $this->profileName);
     }
     $curlRes = curl_exec($curlHandle);
     if (curl_errno($curlHandle) == CURLE_OPERATION_TIMEOUTED) {
         $this->status->fatal('http-timed-out', $this->url);
     } elseif ($curlRes === false) {
         $this->status->fatal('http-curl-error', curl_error($curlHandle));
     } else {
         $this->headerList = explode("\r\n", $this->headerText);
     }
     curl_close($curlHandle);
     if ($this->profiler) {
         $this->profiler->scopedProfileOut($profileSection);
     }
     $this->parseHeader();
     $this->setStatus();
     return $this->status;
 }
Esempio n. 5
0
 public function execute()
 {
     parent::execute();
     // At least on Centos 4.8 with PHP 5.1.6, using max_redirects to follow redirects
     // causes a segfault
     $manuallyRedirect = version_compare(phpversion(), '5.1.7', '<');
     if ($this->parsedUrl['scheme'] != 'http' && $this->parsedUrl['scheme'] != 'https') {
         $this->status->fatal('http-invalid-scheme', $this->parsedUrl['scheme']);
     }
     $this->reqHeaders['Accept'] = "*/*";
     if ($this->method == 'POST') {
         // Required for HTTP 1.0 POSTs
         $this->reqHeaders['Content-Length'] = strlen($this->postData);
         $this->reqHeaders['Content-type'] = "application/x-www-form-urlencoded";
     }
     $options = array();
     if ($this->proxy && !$this->noProxy) {
         $options['proxy'] = $this->urlToTCP($this->proxy);
         $options['request_fulluri'] = true;
     }
     if (!$this->followRedirects || $manuallyRedirect) {
         $options['max_redirects'] = 0;
     } else {
         $options['max_redirects'] = $this->maxRedirects;
     }
     $options['method'] = $this->method;
     $options['header'] = implode("\r\n", $this->getHeaderList());
     // Note that at some future point we may want to support
     // HTTP/1.1, but we'd have to write support for chunking
     // in version of PHP < 5.3.1
     $options['protocol_version'] = "1.0";
     // This is how we tell PHP we want to deal with 404s (for example) ourselves.
     // Only works on 5.2.10+
     $options['ignore_errors'] = true;
     if ($this->postData) {
         $options['content'] = $this->postData;
     }
     $oldTimeout = false;
     if (version_compare('5.2.1', phpversion(), '>')) {
         $oldTimeout = ini_set('default_socket_timeout', $this->timeout);
     } else {
         $options['timeout'] = $this->timeout;
     }
     $context = stream_context_create(array('http' => $options));
     $this->headerList = array();
     $reqCount = 0;
     $url = $this->url;
     do {
         $reqCount++;
         wfSuppressWarnings();
         $fh = fopen($url, "r", false, $context);
         wfRestoreWarnings();
         if (!$fh) {
             break;
         }
         $result = stream_get_meta_data($fh);
         $this->headerList = $result['wrapper_data'];
         $this->parseHeader();
         if (!$manuallyRedirect || !$this->followRedirects) {
             break;
         }
         # Handle manual redirection
         if (!$this->isRedirect() || $reqCount > $this->maxRedirects) {
             break;
         }
         # Check security of URL
         $url = $this->getResponseHeader("Location");
         if (substr($url, 0, 7) !== 'http://') {
             wfDebug(__METHOD__ . ": insecure redirection\n");
             break;
         }
     } while (true);
     if ($oldTimeout !== false) {
         ini_set('default_socket_timeout', $oldTimeout);
     }
     $this->setStatus();
     if ($fh === false) {
         $this->status->fatal('http-request-error');
         return $this->status;
     }
     if ($result['timed_out']) {
         $this->status->fatal('http-timed-out', $this->url);
         return $this->status;
     }
     if ($this->status->isOK()) {
         while (!feof($fh)) {
             $buf = fread($fh, 8192);
             if ($buf === false) {
                 $this->status->fatal('http-read-error');
                 break;
             }
             if (strlen($buf)) {
                 call_user_func($this->callback, $fh, $buf);
             }
         }
     }
     fclose($fh);
     return $this->status;
 }