Valider 85d0528c rédigé par cerdic's avatar cerdic
Parcourir les fichiers

Report de r21363 : Amelioration de la gestion du Proxy : gestion des echecs,...

Report de r21363 : Amelioration de la gestion du Proxy : gestion des echecs, et gestion du https via CONNECT

Quand la requête necessite un proxy et qu'elle echoue, il ne faut pas essayer de la relancer en direct via fopen() ou via file_get_contents() car cela produit un timeout sur le firewall éventuel

Pour faire une requête https à travers un proxy il faut en général passer par un CONNECT initial (https://en.wikipedia.org/wiki/HTTP_tunnel) ce qui n'était pas géré ici. On implémente donc ce dialogue.
Par soucis de compatibilité il ne sera pris en charge qu'en cas de
```define('_PROXY_HTTPS_VIA_CONNECT',true);```
dans le fichier mes_options.php. A voir si il faut rendre cette fonctionnalité activable par l'interface et/ou si elle doit être celle active par défaut.
parent b564d9ac
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+85 −36
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -295,13 +295,20 @@ function recuperer_url($url, $options = array()){
	if (!$fopen) {
		$res = recuperer_entetes_complets($handle, $options['if_modified_since']);
		if(!$res) {
			fclose($handle);
			$t = @parse_url($url);
			$host = $t['host'];
			// Chinoisierie inexplicable pour contrer
			// les actions liberticides de l'empire du milieu
			if ($res = @file_get_contents($url)){
				$result['status'] = 200;
				$result['page'] = $res;
				return $result;
			if (!need_proxy($host)
			  AND $res = @file_get_contents($url)){
				$res = array(
					'status' => 200,
					'page' => $res,
				);
			}
			else
				return false;
		}
		elseif ($res['location'] AND $options['follow_location']){
			$options['follow_location']--;
@@ -315,9 +322,14 @@ function recuperer_url($url, $options = array()){
			spip_log("HTTP status ".$res['status']." pour $url");
		}
		$result['status'] = $res['status'];
		if (isset($res['headers']))
			$result['headers'] = $res['headers'];
		if (isset($res['last_modified']))
			$result['last_modified'] = $res['last_modified'];
		if (isset($res['location']))
			$result['location'] = $res['location'];
		if (isset($res['page']))
			$result['page'] = $res['page'];
	}

	// on ne veut que les entetes
@@ -332,6 +344,7 @@ function recuperer_url($url, $options = array()){
	if (preg_match(",\bContent-Encoding: .*gzip,is", $result['headers']))
		$gz = (_DIR_TMP . md5(uniqid(mt_rand())) . '.tmp.gz');

	if (!$result['page']){
		$res = recuperer_body($handle, $options['taille_max'], $gz ? $gz : $copy);
		fclose($handle);
		if ($copy){
@@ -341,6 +354,9 @@ function recuperer_url($url, $options = array()){
		elseif($res) {
			$result['page'] = &$res;
			$result['length'] = strlen($result['page']);
	}
	if (!$result['page'])
		return $result;

	// Decompresser au besoin
	if ($gz){
@@ -353,7 +369,6 @@ function recuperer_url($url, $options = array()){
		include_spip('inc/charsets');
		$result['page'] = transcoder_page($result['page'], $result['headers']);
	}
	}

	return $result;
}
@@ -1010,7 +1025,8 @@ function init_http($method, $url, $refuse_gz = false, $referer = '', $datas = ""
	$f = lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $refuse_gz, $referer, $datas, $vers, $date);
	if (!$f){
		// fallback : fopen
		if (!_request('tester_proxy')){
		if (!need_proxy($host)
			AND !_request('tester_proxy')){
			$f = @fopen($url, "rb");
			spip_log("connexion vers $url par simple fopen");
			$fopen = true;
@@ -1059,10 +1075,19 @@ function lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $
	$http_proxy = need_proxy($host);
	if ($user) $user = urlencode($user[0]) . ":" . urlencode($user[1]);

	$connect = "";
	if ($http_proxy){
		if (defined('_PROXY_HTTPS_VIA_CONNECT') AND $scheme=="ssl"){
			$path_host = (!$user ? '' : "$user@") . $host . (($port!=80) ? ":$port" : "");
			$connect = "CONNECT " .$path_host." $vers\r\n"
				."Host: $path_host\r\n"
				."Proxy-Connection: Keep-Alive\r\n";
		}
		else {
			$path = (($scheme=='ssl') ? 'https://' : "$scheme://")
				. (!$user ? '' : "$user@")
				. "$host" . (($port!=80) ? ":$port" : "") . $path;
		}
		$t2 = @parse_url($http_proxy);
		$first_host = $t2['host'];
		if (!($port = $t2['port'])) $port = 80;
@@ -1072,9 +1097,34 @@ function lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $
	else
		$first_host = $noproxy . $host;

	if ($connect){
		$streamContext = stream_context_create(array('ssl' => array('verify_peer' => false, 'allow_self_signed' => true)));
		$f = @stream_socket_client("tcp://$first_host:$port", $nError, $sError, 10, STREAM_CLIENT_CONNECT, $streamContext);
		spip_log("Recuperer $path sur $first_host:$port par $f (via CONNECT)","connect");
		if (!$f) return false;
		stream_set_timeout($f, 10);

		fputs($f, $connect);
		fputs($f, "\r\n");
		$res = fread($f, 1024);
		if (!$res
		  OR !count($res = explode(' ',$res))
		  OR $res[1]!=='200'){
			spip_log("Echec CONNECT sur $first_host:$port","connect"._LOG_INFO_IMPORTANTE);
			fclose($f);
			return false;
		}
		// important, car sinon on lit trop vite et les donnees ne sont pas encore dispo
		stream_set_blocking($f, true);
		// envoyer le handshake
		stream_socket_enable_crypto($f, true,	STREAM_CRYPTO_METHOD_SSLv23_CLIENT);
		spip_log("OK CONNECT sur $first_host:$port","connect");
	}
	else {
		$f = @fsockopen($first_host, $port);
		spip_log("Recuperer $path sur $first_host:$port par $f");
		if (!$f) return false;
	}

	$site = isset($GLOBALS['meta']["adresse_site"]) ? $GLOBALS['meta']["adresse_site"] : '';

@@ -1094,4 +1144,3 @@ function lance_requete($method, $scheme, $user, $host, $path, $port, $noproxy, $
	return $f;
}
?>