H2o: Error en H2O.next.call (env)

Creado en 20 ene. 2020  ·  7Comentarios  ·  Fuente: h2o/h2o

Vuelvo a archivar este problema como un informe de "error", porque ahora lo probé también en Fedora con las últimas fuentes.

Para la demostración de este error, puede utilizar este 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"

Esto funciona: puedo acceder a archivos en dir1, dir2 y dir3. Y cuando solicito http://<my-ip-address-here>:8080/dir0 obtengo la página de inicio de Google (solo para demostración).

Pero agregar incluso un segmento /path rompe H20.next.call (env) como se describe aquí para HardenedBSD, FreeBSD.

H2o.conf roto:

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"

Ahora obtengo un error interno del servidor. Y el registro de errores en Fedora dice:

[h2o_mruby] in request:/dir0:mruby raised: (eval):28: can't modify `SCRIPT_NAME` with `H2O.next`. Is `H2O.reprocess` what you want? (RuntimeError)

Esto está en un Fedora 31 nuevo, con H2O construido desde la fuente en b9989220bea9bda30f69083b66166c4c657bdf84 .

Todos 7 comentarios

Como el mensaje de error sugirió usar H2O.reprocess , ahora probé esta opción. El mismo resultado: agregar más segmentos de ruta bloquea el agua.

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"

Con esta configuración, abrir http://test.local/wp-admin en el navegador me da la página de inicio de Google.

Pero agregar un segmento de ruta más, por ejemplo, un /dir2 adicional me da el siguiente error:

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

¿Existe realmente un límite tan bajo en el número de segmentos de ruta permitidos? Esto debe ser un insecto. Posiblemente el mismo que el de H2O.next .

Dado que ambos, H2O.next y H20.reprocess parecen estar rotos, tuve que explorar otra solución. Implementé un controlador de proxy inverso en mruby, siguiendo el ejemplo de @kazuho .

En mi servidor de prueba esto funciona. Probablemente lo implemente en producción, pronto. Tal vez ayude a otra persona a encontrarse con los mismos problemas con los métodos mencionados anteriormente:

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]
}

Todavía no funciona del todo:
H2O o mruby convierte el encabezado CONTENT_TYPE en HTTP_CONTENT_TYPE , lo que rompe un backend de WordPress ...

Ejemplo:
"CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"
se convierte en
"HTTP_CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"

¿Hay alguna manera de forzarlo a usar solo CONTENT_TYPE ?

Y todo esto, solo porque quería agregar otro /path en mi h2o.conf ...

@utrenkner Perdón por llegar tarde. Espero que https://github.com/h2o/h2o/pull/2254 solucione el problema. Con ese PR H2O.next y H2O.reprocess funciona bien, creo

H2O o mruby convierte el encabezado CONTENT_TYPE original en HTTP_CONTENT_TYPE, lo que rompe un backend de WordPress ...

Probé el mismo controlador mruby pero no pude reproducirlo. Quiero decir, engendré un servidor ascendente mínimo ( echo -ne "HTTP/1.1 200 OK\r\n\r\n" | nc -l 9000 ) y veo los encabezados enviados desde h2o. Incluía CONTENT_TYPE , no HTTP_CONTENT_TYPE .
Por cierto, si adopta este enfoque http_request, debe convertir los guiones bajos en las claves hash del encabezado en guiones: es decir, debe convertir HTTP_X_FOO en X-FOO , no X_FOO . Supongo que esta es la causa de ese problema: la implementación de su servidor no lo reconoce como encabezado content-type , que debe tratarse especialmente en la mayoría de los casos.

@ i110 ¡ Muchas gracias! Probaré tu parche mañana.

Y también gracias por probar el controlador mruby anterior. De hecho, me olvidé por completo de cambiar el guión bajo en un guión. ¡Con ese cambio, funciona según lo previsto y CONTENT_TYPE permanece CONTENT_TYPE !

@ i110 ¡ Muchas gracias! # 2254 resuelve mis problemas con H2O.next y H2O.reprocess . Agregué aún más segmentos /path a h2o.conf, solo para verificar que realmente funciona. ¡Y sí, lo hace!

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

voiddeveloper picture voiddeveloper  ·  6Comentarios

kazuho picture kazuho  ·  7Comentarios

proyb6 picture proyb6  ·  5Comentarios

daniel-lucio picture daniel-lucio  ·  5Comentarios

paulpref picture paulpref  ·  5Comentarios