<p>h2o renvoie 304 au lieu de 200 en lien avec php-fpm</p>

Créé le 18 juil. 2017  ·  5Commentaires  ·  Source: h2o/h2o

Cela me rend fou, mais finalement je peux au moins décrire le problème :
J'ai une installation du CMS TYPO3 en cours d'exécution dans une prison FreeBSD. Tout semble fonctionner correctement, sauf que dans le backend, une certaine URL est renvoyée avec un 304 au lieu de 200. Et donc une ancienne version du contenu est chargée.

Apache (v. 2.4.27 avec mod_php) et Nginx (v. 1.12.1 avec php-fpm) renvoient la nouvelle page avec HTTP Status 200. Surtout ce dernier est intéressant, car il utilise le même php-fpm via le socket UNIX que le h2o. Je peux même arrêter h2o et démarrer nginx et nginx sert la nouvelle version correcte. Et dans l'autre sens, je peux arrêter nginx, démarrer h2o et obtenir un 304 à la place.

Est-ce que quelqu'un a une idée, quelle pourrait être la raison de cette différence?

Voici les en-têtes HTTP, lorsque je force le rechargement de l'URL depuis h2o (CTRL + SHIFT + R):

http://testserver.local/typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit

GET /typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit HTTP/1.1
Host: testserver.local
User-Agent: Mozilla/5.0 (X11; FreeBSD i386; rv:43.0) Gecko/20100101 Firefox/43.0 SeaMonkey/2.40
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: be_typo_user=9dc68c1e0a89687f525a2ae44b410ca2; PHPSESSID=bk7hs9h6vqbae93t64bv0n3b93; phpMyAdmin=bk7hs9h6vqbae93t64bv0n3b93
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache

HTTP/1.1 200 OK
Date: Tue, 18 Jul 2017 12:50:28 GMT
Connection: keep-alive
Server: h2o/2.2.2
X-Powered-By: PHP/5.6.31
Expires: 0
Last-Modified: Tue, 18 Jul 2017 12:50:28 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
x-frame-options: SAMEORIGIN
Content-Type: text/html;charset=utf-8
Content-Encoding: gzip
Vary: accept-encoding
Accept-Ranges: none
Transfer-Encoding: chunked

Notez que tous les en-têtes liés au cache indiquent que cette page ne doit pas être mise en cache !

Et ici h2o lors du rechargement normal (STRG + R) répond avec le mauvais 304 :

http://testserver.local/typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit

GET /typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit HTTP/1.1
Host: testserver.local
User-Agent: Mozilla/5.0 (X11; FreeBSD i386; rv:43.0) Gecko/20100101 Firefox/43.0 SeaMonkey/2.40
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: be_typo_user=9dc68c1e0a89687f525a2ae44b410ca2; PHPSESSID=bk7hs9h6vqbae93t64bv0n3b93; phpMyAdmin=bk7hs9h6vqbae93t64bv0n3b93
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
If-Modified-Since: Tue, 18 Jul 2017 12:50:28 GMT
Cache-Control: max-age=0

HTTP/1.1 304 Not Modified
Date: Tue, 18 Jul 2017 12:51:24 GMT
Connection: keep-alive
Server: h2o/2.2.2
Etag: "58f63dd6-603"
Vary: accept-encoding

Nginx et Apache répondent toujours par un 200, comme ceci :

http://testserver.local/typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit

GET /typo3/alt_doc.php?returnUrl=%2Ftypo3conf%2Fext%2Ftemplavoila%2Fmod1%2Findex.php%3Fid%3D38347%23ccfa36ed4fe4ea9ae5540ab0356ea4897&edit[tt_content][104987]=edit HTTP/1.1
Host: testserver.local
User-Agent: Mozilla/5.0 (X11; FreeBSD i386; rv:43.0) Gecko/20100101 Firefox/43.0 SeaMonkey/2.40
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: be_typo_user=9dc68c1e0a89687f525a2ae44b410ca2; PHPSESSID=bk7hs9h6vqbae93t64bv0n3b93; phpMyAdmin=bk7hs9h6vqbae93t64bv0n3b93
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
If-Modified-Since: Tue, 18 Jul 2017 12:48:18 GMT
Cache-Control: max-age=0

HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Tue, 18 Jul 2017 12:49:32 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.6.31
Expires: 0
Last-Modified: Tue, 18 Jul 2017 12:49:32 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
x-frame-options: SAMEORIGIN

J'ai essayé différents navigateurs (Firefox et Chromium), différents en-têtes de mise en cache, HTTP/1 et HTTP/2... le résultat est toujours le même.

Est-ce une sorte de bogue dans h2o? Ou un certain paramètre ou une variable d'environnement pourrait-il ne pas être passé à php-fpm dans h2o mais dans Nginx et Apache ?

Commentaire le plus utile

Ah belle trouvaille. Il semble que le simple fait de déplacer la gestion dynamique plus tôt dans le fichier entraînerait le comportement attendu :

diff --git a/lib/handler/file.c b/lib/handler/file.c
index adc95f07..c2c35cf2 100644
--- a/lib/handler/file.c
+++ b/lib/handler/file.c
@@ -619,6 +619,13 @@ static int serve_with_generator(struct st_h2o_sendfile_generator_t *generator, h
         method_type = METHOD_IS_OTHER;
     }

+    /* obtain mime type */
+    if (mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) {
+        do_close(&generator->super, req);
+        return delegate_dynamic_request(req, req->path_normalized.len, rpath, rpath_len, mime_type);
+    }
+    assert(mime_type->type == H2O_MIMEMAP_TYPE_MIMETYPE);
+
     /* if-non-match and if-modified-since */
     if ((if_none_match_header_index = h2o_find_header(&req->headers, H2O_TOKEN_IF_NONE_MATCH, SIZE_MAX)) != -1) {
         h2o_iovec_t *if_none_match = &req->headers.entries[if_none_match_header_index].value;
@@ -636,13 +643,6 @@ static int serve_with_generator(struct st_h2o_sendfile_generator_t *generator, h
         }
     }

-    /* obtain mime type */
-    if (mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) {
-        do_close(&generator->super, req);
-        return delegate_dynamic_request(req, req->path_normalized.len, rpath, rpath_len, mime_type);
-    }
-    assert(mime_type->type == H2O_MIMEMAP_TYPE_MIMETYPE);
-
     /* only allow GET or POST for static files */
     if (method_type == METHOD_IS_OTHER) {
         do_close(&generator->super, req);

@kazuho Qu'en pensez-vous ? Intuitivement, il semble que nous devrions toujours invoquer le gestionnaire cgi lorsque le contenu est dynamique ?

Tous les 5 commentaires

J'ai encore testé ce problème - cette fois avec cURL : lorsqu'un en-tête If-Modified-Since est fourni par le navigateur et que c'est au cours des 3 derniers mois, j'obtiens un 304. Lorsque je ne fournis aucun en-tête If-Modified-Since ou un avec une date de plus de 3 mois, j'obtiens le bon 200.

Cela m'amène à la question : ces trois mois sont-ils codés en dur dans h2o ? Comment pourrais-je contourner ce problème ? Par exemple, est-il possible de supprimer l'en-tête If-Modified-Since de cette requête spécifique, avant que h2o ne fasse réellement quelque chose avec la requête ?

On a trouvé un détail de plus. J'ai capturé le trafic fastcgi sur le socket UNIX ( en utilisant socat comme décrit ici ).

Lors de la fourniture d'un en-tête If-Modified-Since avec une durée inférieure à 3 mois, h2o ne transmet même pas cette demande à php-fpm. Il répond simplement au navigateur en envoyant le 304. Ceci est différent lors de l'utilisation de Nginx. Là, chaque requête est transmise au serveur php-fpm. Il semble donc vraiment que le problème réside dans la façon dont h2o gère cette demande.

J'ai pu identifier le Bug ! Le problème se pose, car h2o ignore que le contenu est dynamique et vérifie simplement l'heure de la dernière modification du fichier PHP. Si l'heure de modification du fichier était au moins 1 seconde après l'heure donnée par l'en-tête If-Modified-Since , h2o retournait 200, et 304 sinon.

Je suppose que ce bogue se trouve dans /lib/handler/file.c (Lignes 629-637).

Trouvé une solution rapide temporaire.

Ah belle trouvaille. Il semble que le simple fait de déplacer la gestion dynamique plus tôt dans le fichier entraînerait le comportement attendu :

diff --git a/lib/handler/file.c b/lib/handler/file.c
index adc95f07..c2c35cf2 100644
--- a/lib/handler/file.c
+++ b/lib/handler/file.c
@@ -619,6 +619,13 @@ static int serve_with_generator(struct st_h2o_sendfile_generator_t *generator, h
         method_type = METHOD_IS_OTHER;
     }

+    /* obtain mime type */
+    if (mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) {
+        do_close(&generator->super, req);
+        return delegate_dynamic_request(req, req->path_normalized.len, rpath, rpath_len, mime_type);
+    }
+    assert(mime_type->type == H2O_MIMEMAP_TYPE_MIMETYPE);
+
     /* if-non-match and if-modified-since */
     if ((if_none_match_header_index = h2o_find_header(&req->headers, H2O_TOKEN_IF_NONE_MATCH, SIZE_MAX)) != -1) {
         h2o_iovec_t *if_none_match = &req->headers.entries[if_none_match_header_index].value;
@@ -636,13 +643,6 @@ static int serve_with_generator(struct st_h2o_sendfile_generator_t *generator, h
         }
     }

-    /* obtain mime type */
-    if (mime_type->type == H2O_MIMEMAP_TYPE_DYNAMIC) {
-        do_close(&generator->super, req);
-        return delegate_dynamic_request(req, req->path_normalized.len, rpath, rpath_len, mime_type);
-    }
-    assert(mime_type->type == H2O_MIMEMAP_TYPE_MIMETYPE);
-
     /* only allow GET or POST for static files */
     if (method_type == METHOD_IS_OTHER) {
         do_close(&generator->super, req);

@kazuho Qu'en pensez-vous ? Intuitivement, il semble que nous devrions toujours invoquer le gestionnaire cgi lorsque le contenu est dynamique ?

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

utrenkner picture utrenkner  ·  7Commentaires

Ys88 picture Ys88  ·  5Commentaires

utrenkner picture utrenkner  ·  8Commentaires

ndac-todoroki picture ndac-todoroki  ·  5Commentaires

taosx picture taosx  ·  6Commentaires