H2o: Bug em H2O.next.call (env)

Criado em 20 jan. 2020  ·  7Comentários  ·  Fonte: h2o/h2o

Reenvio esse problema como um relatório de "bug", porque agora testei também no Fedora com as fontes mais recentes.

Para demonstração desse bug, você pode usar 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"

Isso funciona: posso acessar arquivos em dir1, dir2 e dir3. E quando eu solicito http://<my-ip-address-here>:8080/dir0 eu obtenho a página inicial do Google (apenas para demonstração).

Mas adicionar mais um segmento /path quebra H20.next.call (env) conforme descrito aqui para HardenedBSD, FreeBSD.

H2o.conf quebrado:

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"

Agora recebo um erro interno do servidor. E o log de erros no Fedora diz:

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

Este é um Fedora 31 novo, com H2O construído a partir da fonte em b9989220bea9bda30f69083b66166c4c657bdf84 .

Todos 7 comentários

Como a mensagem de erro sugeria o uso de H2O.reprocess , agora tentei esta opção. Mesmo resultado: adicionar mais segmentos de caminho trava h2o.

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"

Com essa configuração, abrir http://test.local/wp-admin no navegador me dá a página inicial do Google.

Mas adicionar mais um segmento de caminho, por exemplo, um /dir2 me dá o seguinte erro:

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 um limite tão baixo no número de segmentos de caminho permitidos ?? Deve ser um bug. Possivelmente o mesmo de H2O.next .

Já que ambos, H2O.next e H20.reprocess parecem quebrados, tive que explorar outra solução. Implementei um manipulador de proxy reverso no mruby, seguindo o exemplo de @kazuho .

No meu servidor de teste isso funciona. Provavelmente irei implantá-lo em produção em breve. Talvez ajude alguém a ter os mesmos problemas com os métodos mencionados acima:

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

Ainda não está funcionando bem:
H2O ou mruby transforma o cabeçalho CONTENT_TYPE em HTTP_CONTENT_TYPE , que quebra um back-end do WordPress ...

Exemplo:
"CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"
torna-se
"HTTP_CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"

Existe uma maneira de forçá-lo a usar apenas CONTENT_TYPE ?

E tudo isso, só porque eu queria adicionar outro /path ao meu h2o.conf ...

@utrenkner Desculpe pelo atraso. Espero que https://github.com/h2o/h2o/pull/2254 corrija o problema. Com aquele PR H2O.next e H2O.reprocess funciona bem, eu acho

H2O ou mruby transforma o cabeçalho CONTENT_TYPE original em HTTP_CONTENT_TYPE, que quebra um back-end do WordPress ...

Tentei o mesmo gerenciador mruby, mas não consegui reproduzi-lo. Quer dizer, eu gerei o servidor upstream mínimo ( echo -ne "HTTP/1.1 200 OK\r\n\r\n" | nc -l 9000 ) e vejo os cabeçalhos enviados de h2o. Incluía CONTENT_TYPE , não HTTP_CONTENT_TYPE .
BTW, se você adotar essa abordagem http_request, terá que converter sublinhados nas chaves hash do cabeçalho em hifens: ou seja, deverá converter HTTP_X_FOO em X-FOO , não X_FOO . Acho que esta é a causa do problema: a implementação do seu servidor não o reconhece como content-type header, que deve ser tratado de maneira especial na maioria dos casos.

@ i110 Muito obrigado! Vou experimentar o seu patch, amanhã.

E também obrigado por testar o manipulador mruby acima. Na verdade, esqueci completamente de transformar o sublinhado em um hífen. Com essa mudança, funciona como pretendido e CONTENT_TYPE permanece CONTENT_TYPE !

@ i110 Muito obrigado! # 2254 resolve meus problemas com H2O.next e H2O.reprocess . Eu adicionei ainda mais segmentos /path ao h2o.conf, apenas para verificar se ele realmente funciona. E, sim, é verdade!

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

voiddeveloper picture voiddeveloper  ·  6Comentários

utrenkner picture utrenkner  ·  3Comentários

basbebe picture basbebe  ·  3Comentários

proyb6 picture proyb6  ·  5Comentários

Ys88 picture Ys88  ·  5Comentários