Je reclasse ce problème en tant que rapport de "bug", car maintenant je l'ai également testé sous Fedora avec les dernières sources.
Pour la démonstration de ce bogue, vous pouvez utiliser ce h2o.conf :
user: www
access-log: /var/log/h2o/h2o-access.log
error-log: /var/log/h2o/h2o-error.log
listen: 8080
hosts:
"<my-ip-address-here>:8080":
paths:
"/dir0":
mruby.handler: |
proc {|env|
resp = H2O.next.call(env)
resp
}
proxy.reverse.url: "https://www.google.com" # this URL is just for testing/demonstration
"/dir1":
file.dir: "/usr/local/www/data/testh2o/dir1"
"/dir2":
file.dir: "/usr/local/www/data/testh2o/dir2"
"/":
file.dir: "/usr/local/www/data/testh2o"
Cela fonctionne : je peux accéder aux fichiers sous dir1, dir2 et dir3. Et quand je demande http://<my-ip-address-here>:8080/dir0
j'obtiens la page d'accueil de Google (juste pour la démo).
Mais ajouter encore un segment /path
casse H20.next.call(env) comme décrit ici pour HardenedBSD, FreeBSD.
h2o.conf cassé :
user: www
access-log: /var/log/h2o/h2o-access.log
error-log: /var/log/h2o/h2o-error.log
listen: 8080
hosts:
"<my-ip-address-here>:8080":
paths:
"/dir0":
mruby.handler: |
proc {|env|
resp = H2O.next.call(env)
# In my production conf I have here code to look for a certain header field.
# If it finds it, this handler makes a http_request() to a certain URL on another server
# in order to trigger emptying a cache.
# This bug demo is independent of this code.
resp
}
proxy.reverse.url: "https://www.google.com" # this URL is just for testing/demonstration
"/dir1":
file.dir: "/usr/local/www/data/testh2o/dir1"
"/dir2":
file.dir: "/usr/local/www/data/testh2o/dir2"
"/dir3":
file.dir: "/usr/local/www/data/testh2o/dir3"
"/":
file.dir: "/usr/local/www/data/testh2o"
J'obtiens maintenant une erreur de serveur interne. Et le journal des erreurs sur Fedora dit :
[h2o_mruby] in request:/dir0:mruby raised: (eval):28: can't modify `SCRIPT_NAME` with `H2O.next`. Is `H2O.reprocess` what you want? (RuntimeError)
C'est sur une nouvelle Fedora 31, avec H2O construit à partir de la source à b9989220bea9bda30f69083b66166c4c657bdf84 .
Comme le message d'erreur suggérait d'utiliser H2O.reprocess
j'ai maintenant essayé cette option. Même résultat : l'ajout de plus de segments de chemin fait planter l'eau.
hosts:
test.local:
listen:
port: 80
host: 10.0.0.10
paths:
"/dir0":
file.dir: "/usr/local/www/data/testh2o/dir0"
"/dir1":
file.dir: "/usr/local/www/data/testh2o/dir1"
"/wp-admin":
mruby.handler: |
proc {|env|
env['SCRIPT_NAME'] = '/proxy-wp-admin'
resp = H2O.reprocess.call(env)
resp
}
"/proxy-wp-admin":
proxy.reverse.url: "https://www.google.com"
Avec cette configuration, l'ouverture de http://test.local/wp-admin
dans le navigateur me donne la page d'accueil de Google.
Mais l'ajout d'un segment de chemin supplémentaire, par exemple un /dir2
supplémentaire me donne l'erreur suivante :
Feb 4 17:12:11 web2 h2o[34490]: received fatal signal 11
Feb 4 17:12:11 web2 h2o[34490]: [34493] 0x4cf6a0 <???> at /usr/local/bin/h2o
Feb 4 17:12:11 web2 h2o[34490]: [34493] 0x8018c5946 <pthread_sigmask+0x536> at /lib/libthr.so.3
Feb 4 17:12:11 web2 h2o[34490]: [34493] 0x8018c4eb2 <pthread_getspecific+0xe12> at /lib/libthr.so.3
Y a-t-il vraiment une limite aussi basse sur le nombre de segments de chemin autorisés ??? Ce doit être un bug. Peut-être le même que celui de H2O.next
.
Étant donné que les deux, H2O.next
et H20.reprocess
semblent cassés, j'ai dû explorer une autre solution. J'ai implémenté un gestionnaire de proxy inverse dans mruby, en suivant l' exemple de @kazuho .
Sur mon serveur de test, cela fonctionne. Je vais probablement le déployer en production, bientôt. Peut-être que cela aide quelqu'un d'autre à rencontrer les mêmes problèmes avec les méthodes mentionnées ci-dessus :
proc {|env|
# copy headers
headers = {}
env.each do |key, value|
if /^HTTP_/.match(key)
headers[$'] = value
end
end
if env['CONTENT_TYPE']
headers['CONTENT_TYPE'] = env['CONTENT_TYPE']
end
# issue the request
input = env["rack.input"] ? env["rack.input"] : ""
if env['QUERY_STRING'].to_s != ''
uri = env['SCRIPT_NAME'] + env['PATH_INFO'] + '?' + env['QUERY_STRING']
else
uri = env['SCRIPT_NAME'] + env['PATH_INFO']
end
req = http_request(
"http://<backend-ip>#{uri}",
method: env["REQUEST_METHOD"],
headers: headers,
body: input,
)
# Extract status, headers and body, so that I can look into the headers
status, headers, body = req.join
# actual work done here, if a certain header is present
[status, headers, body]
}
Pas encore tout à fait fonctionnel :
H2O ou mruby transforme l'en-tête CONTENT_TYPE
en HTTP_CONTENT_TYPE
, ce qui casse un backend WordPress...
Exemple:
"CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"
devient
"HTTP_CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"
Existe-t-il un moyen de le forcer à n'utiliser que CONTENT_TYPE
?
Et tout ça, juste parce que je voulais ajouter un autre /path
dans mon h2o.conf...
@utrenkner Désolé d'être en retard. J'espère que https://github.com/h2o/h2o/pull/2254 résoudra le problème. Avec ce PR H2O.next
et H2O.reprocess
fonctionne bien je pense
H2O ou mruby transforme l'en-tête CONTENT_TYPE d'origine en HTTP_CONTENT_TYPE, ce qui casse un backend WordPress...
J'ai essayé le même gestionnaire mruby mais je n'ai pas pu le reproduire. Je veux dire, j'ai généré un serveur en amont minimal ( echo -ne "HTTP/1.1 200 OK\r\n\r\n" | nc -l 9000
) et je vois les en-têtes envoyés depuis h2o. Il comprenait CONTENT_TYPE
, pas HTTP_CONTENT_TYPE
.
BTW, si vous adoptez cette approche http_request, vous devez convertir les traits de soulignement dans les clés de hachage d'en-tête en tirets : c'est-à-dire que vous devez convertir HTTP_X_FOO
en X-FOO
, et non en X_FOO
. Je suppose que c'est la cause de ce problème : l'implémentation de votre serveur ne le reconnaît pas comme content-type
tête
@i110 Merci beaucoup ! J'essaierai ton patch demain.
Et merci également d'avoir testé le gestionnaire mruby ci-dessus. En effet, j'avais complètement oublié de changer le trait de soulignement en trait d'union. Avec ce changement, cela fonctionne comme prévu et CONTENT_TYPE
reste CONTENT_TYPE
!
@i110 Merci beaucoup ! #2254 résout mes problèmes avec à la fois H2O.next
et H2O.reprocess
. J'ai ajouté encore plus /path
segments vraiment . Et, oui, c'est le cas !