Valider 78509e3c rédigé par cerdic's avatar cerdic
Parcourir les fichiers

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 c86d1f80
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+59 −17
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -265,6 +265,7 @@ function recuperer_lapage($url, $trans = false, $get = 'GET', $taille_max = _INC
		return false;
	}

	$result = '';
	// Sauf en fopen, envoyer le flux d'entree
	// et recuperer les en-tetes de reponses
	if ($fopen)
@@ -279,8 +280,13 @@ function recuperer_lapage($url, $trans = false, $get = 'GET', $taille_max = _INC
				spip_log("HTTP status $headers pour $url");
				return false;
			}
			elseif ($result = @file_get_contents($url))
				return array('', $result);
			$t = @parse_url($url);
			$host = $t['host'];
			if (!need_proxy($host)
				AND $result = @file_get_contents($url)){
				// on peuple les headers de vide et on continue
				$headers = array('');
			}
			else
				return false;
		}
@@ -301,8 +307,10 @@ function recuperer_lapage($url, $trans = false, $get = 'GET', $taille_max = _INC
		(_DIR_TMP . md5(uniqid(mt_rand())) . '.tmp.gz') : '';

#	spip_log("entete ($trans $copy $gz)\n$headers");
	if (!$result){
		$result = recuperer_body($f, $taille_max, $gz ? $gz : ($copy ? $trans : ''));
		fclose($f);
	}
	if (!$result)
		return array($headers, $result);

@@ -671,7 +679,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;
@@ -691,10 +700,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;
@@ -704,9 +722,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 = $GLOBALS['meta']["adresse_site"];

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