diff --git a/ecrire/public.php b/ecrire/public.php
index 38bf96424d0c1d1b3e4cc9cd32ecbd315ce424b4..1b0133078663086366415882e0358b0e4031be71 100644
--- a/ecrire/public.php
+++ b/ecrire/public.php
@@ -178,7 +178,7 @@ if ($GLOBALS['_INC_PUBLIC']>0) {
 
 	// 1. Cas d'une page contenant uniquement du HTML :
 	if ($page['process_ins'] == 'html') {
-		foreach($page['entetes'] as $k => $v) @header("$k: $v");
+		envoyer_entetes($page['entetes']);
 	}
 
 	// 2. Cas d'une page contenant du PHP :
@@ -189,7 +189,7 @@ if ($GLOBALS['_INC_PUBLIC']>0) {
 		// Si la retention du flux de sortie est impossible
 		// envoi des entetes
 		if (!$flag_ob) {
-			foreach($page['entetes'] as $k => $v) @header("$k: $v");
+			envoyer_entetes($page['entetes']);
 			xml_hack($page, true);
 			eval('?' . '>' . $page['texte']);
 			$page['texte'] = '';
@@ -206,7 +206,7 @@ if ($GLOBALS['_INC_PUBLIC']>0) {
 			xml_hack($page);
 			ob_end_clean();
 
-			foreach($page['entetes'] as $k => $v) @header("$k: $v");
+			envoyer_entetes($page['entetes']);
 			// en cas d'erreur lors du eval,
 			// la memoriser dans le tableau des erreurs
 			// On ne revient pas ici si le nb d'erreurs > 4
diff --git a/ecrire/public/assembler.php b/ecrire/public/assembler.php
index 648ce45dc9a76361b17e1c9107d63df28fd04681..1447327e1146e0e6014726a25191be94bb81e231 100644
--- a/ecrire/public/assembler.php
+++ b/ecrire/public/assembler.php
@@ -110,6 +110,14 @@ function public_assembler_dist($fond, $connect='') {
 	return assembler_page ($fond, $connect);
 }
 
+// Envoyer les entetes, en retenant ceux qui sont a usage interne
+// et demarrent par X-Spip-...
+function envoyer_entetes($entetes) {
+	foreach ($entetes as $k => $v)
+	#	if (strncmp($k, 'X-Spip-', 7))
+			@header("$k: $v");
+}
+
 
 //
 // calcule la page et les entetes
diff --git a/ecrire/public/balises.php b/ecrire/public/balises.php
index 97b6fbe4cf70d85aaa3d795367ad76dd77cd062d..4fde6d5150dcf6717f201e0e261bb48cb25f31f0 100644
--- a/ecrire/public/balises.php
+++ b/ecrire/public/balises.php
@@ -947,6 +947,10 @@ function balise_HTTP_HEADER_dist($p) {
 // #CACHE{24*3600}
 // parametre(s) supplementaire(s) :
 // #CACHE{24*3600, cache-client} autorise gestion du IF_MODIFIED_SINCE
+// #CACHE{24*3600, statique} ne respecte pas l'invalidation par modif de la base
+//  (mais s'invalide tout de meme a l'expiration du delai)
+//  par defaut cache-client => statique
+//  cf. ecrire/public/cacher.php
 // http://doc.spip.org/@balise_CACHE_dist
 function balise_CACHE_dist($p) {
 	$duree = valeur_numerique($p->param[0][1][0]->texte);
@@ -965,14 +969,24 @@ function balise_CACHE_dist($p) {
 		.'?php header("Pragma: no-cache"); ?'
 		.'>\'';
 
-	// cas #CACHE{360, cache-client}
-	if (isset($p->param[0][2])) {
-		$second = ($p->param[0][2][0]->texte);
-		if ($second == 'cache-client'
-		AND $duree > 0)
+	// recuperer les parametres suivants
+	$i = 1;
+	while (isset($p->param[0][++$i])) {
+		$pa = ($p->param[0][$i][0]->texte);
+
+		if ($pa == 'cache-client'
+		AND $duree > 0) {
 			$p->code .= '.\'<'.'?php header("Cache-Control: max-age='
 				. $duree
 				. '"); ?'.'>\'';
+			// il semble logique, si on cache-client, de ne pas invalider
+			$pa = 'statique';
+		}
+
+		if ($pa == 'statique'
+		AND $duree > 0)
+			$p->code .= '.\'<'.'?php header("X-Spip-Statique: oui"); ?'.'>\'';
+
 	}
 
 	$p->interdire_scripts = false;
diff --git a/ecrire/public/cacher.php b/ecrire/public/cacher.php
index 364a66ad3b8013febc1ab88f52715c00ed308ba1..d41d0f3c79d3a41e28bc6e0c4bb5186a8e395b8d 100644
--- a/ecrire/public/cacher.php
+++ b/ecrire/public/cacher.php
@@ -95,20 +95,26 @@ function cache_valide(&$page, $date) {
 
 	if (!$page) return 1;
 
-	// Cache invalide par la meta 'derniere_modif'
-	if ($GLOBALS['derniere_modif_invalide']
-	AND $date < $GLOBALS['meta']['derniere_modif'])
-		return 1;
+	// #CACHE{n,statique} => on n'invalide pas avec derniere_modif
+	// cf. ecrire/public/balises.php, balise_CACHE_dist()
+	if ($page['entetes']['X-Spip-Statique'] !== 'oui') {
+
+		// Cache invalide par la meta 'derniere_modif'
+		if ($GLOBALS['derniere_modif_invalide']
+		AND $date < $GLOBALS['meta']['derniere_modif'])
+			return 1;
+
+		// Apparition d'un nouvel article post-date ?
+		if ($GLOBALS['meta']['post_dates'] == 'non'
+		AND isset($GLOBALS['meta']['date_prochain_postdate'])
+		AND time() > $GLOBALS['meta']['date_prochain_postdate']) {
+			spip_log('Un article post-date invalide le cache');
+			include_spip('inc/rubriques');
+			ecrire_meta('derniere_modif', time());
+			calculer_prochain_postdate();
+			return 1;
+		}
 
-	// Apparition d'un nouvel article post-date ?
-	if ($GLOBALS['meta']['post_dates'] == 'non'
-	AND isset($GLOBALS['meta']['date_prochain_postdate'])
-	AND time() > $GLOBALS['meta']['date_prochain_postdate']) {
-		spip_log('Un article post-date invalide le cache');
-		include_spip('inc/rubriques');
-		ecrire_meta('derniere_modif', time());
-		calculer_prochain_postdate();
-		return 1;
 	}
 
 	// Sinon comparer l'age du fichier a sa duree de cache