H2o: Fehler in H2O.next.call(env)

Erstellt am 20. Jan. 2020  ·  7Kommentare  ·  Quelle: h2o/h2o

Ich reiche dieses Problem als "Bug"-Bericht zurück, da ich es jetzt auch unter Fedora mit den neuesten Quellen getestet habe.

Zur Demonstration dieses Fehlers können Sie diese h2o.conf verwenden:

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"

Das funktioniert: Ich kann auf Dateien unter dir1, dir2 und dir3 zugreifen. Und wenn ich http://<my-ip-address-here>:8080/dir0 anfordere, bekomme ich die Google-Startseite (nur zur Demo).

Aber das Hinzufügen eines weiteren /path Segments unterbricht H20.next.call(env), wie hier für HardenedBSD, FreeBSD beschrieben.

h2o.conf defekt:

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"

Ich erhalte jetzt einen internen Serverfehler. Und das Fehlerprotokoll auf Fedora sagt:

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

Dies ist auf einem frischen Fedora 31, mit H2O aus der Quelle unter b9989220bea9bda30f69083b66166c4c657bdf84 gebaut .

Alle 7 Kommentare

Wie in der Fehlermeldung vorgeschlagen, H2O.reprocess ich diese Option jetzt ausprobiert. Gleiches Ergebnis: Das Hinzufügen weiterer Pfadsegmente führt zum Absturz von 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"

Mit dieser Konfiguration bekomme ich beim Öffnen von http://test.local/wp-admin im Browser die Google-Startseite.

Aber wenn ich ein weiteres Pfadsegment hinzufüge, zB ein zusätzliches /dir2 bekomme ich den folgenden Fehler:

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

Gibt es wirklich eine so niedrige Grenze für die Anzahl der erlaubten Pfadsegmente??? Das muss ein Bug sein. Möglicherweise das gleiche wie für H2O.next .

Da sowohl H2O.next als auch H20.reprocess kaputt zu sein scheinen, musste ich eine andere Lösung suchen. Ich implementierte einen Reverse - Proxy - Handler in mruby nach @kazuho ‚s Beispiel .

Auf meinem Testserver funktioniert das. Ich werde es wahrscheinlich bald in der Produktion einsetzen. Vielleicht hilft es jemandem, der mit den oben genannten Methoden auf die gleichen Probleme stößt:

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

Funktioniert noch nicht ganz:
H2O oder mruby wandelt den ursprünglichen CONTENT_TYPE Header in HTTP_CONTENT_TYPE , was ein WordPress-Backend zerstört...

Beispiel:
"CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"
wird
"HTTP_CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"

Gibt es eine Möglichkeit, es zu erzwingen, nur CONTENT_TYPE ?

Und das alles nur, weil ich meiner h2o.conf noch weitere /path hinzufügen wollte...

@utrenkner Entschuldigung für die Verspätung. Ich hoffe, https://github.com/h2o/h2o/pull/2254 wird das Problem beheben. Damit funktioniert PR H2O.next und H2O.reprocess gut, denke ich

H2O oder mruby wandelt den ursprünglichen CONTENT_TYPE-Header in HTTP_CONTENT_TYPE um, was ein WordPress-Backend zerstört...

Ich habe den gleichen mruby-Handler ausprobiert, konnte ihn aber nicht reproduzieren. Ich meine, ich habe einen minimalen Upstream-Server ( echo -ne "HTTP/1.1 200 OK\r\n\r\n" | nc -l 9000 ) erzeugt und sehe die von h2o gesendeten Header. Es enthielt CONTENT_TYPE , nicht HTTP_CONTENT_TYPE .
Übrigens, wenn Sie diesen http_request-Ansatz wählen, müssen Sie Unterstriche in Header-Hash-Schlüsseln in Bindestriche umwandeln: das heißt, Sie müssen HTTP_X_FOO in X-FOO umwandeln, nicht X_FOO . Ich denke, dies ist die Ursache für dieses Problem: Ihre Serverimplementierung erkennt es nicht als content-type Header, der in den meisten Fällen speziell behandelt werden muss.

@i110 Vielen, vielen Dank! Ich werde deinen Patch morgen ausprobieren.

Und auch vielen Dank, dass Sie den obigen mruby-Handler getestet haben. Tatsächlich habe ich ganz vergessen, den Unterstrich in einen Bindestrich zu ändern. Mit dieser Änderung funktioniert es wie beabsichtigt und CONTENT_TYPE bleibt CONTENT_TYPE !

@i110 Vielen Dank! #2254 löst meine Probleme mit H2O.next und H2O.reprocess . Ich habe der h2o.conf noch mehr /path Segmente hinzugefügt, nur um zu überprüfen, ob es wirklich funktioniert. Und ja, das tut es!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

ahupowerdns picture ahupowerdns  ·  8Kommentare

utrenkner picture utrenkner  ·  8Kommentare

voiddeveloper picture voiddeveloper  ·  6Kommentare

Jxck picture Jxck  ·  7Kommentare

concatime picture concatime  ·  3Kommentare