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

Dibuat pada 20 Jan 2020  ·  7Komentar  ·  Sumber: h2o/h2o

Saya refile masalah ini sebagai laporan "bug", karena sekarang saya mengujinya juga di bawah Fedora dengan sumber terbaru.

Untuk demonstrasi bug ini, Anda dapat menggunakan h2o.conf ini:

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"

Ini berfungsi: Saya dapat mengakses file di bawah dir1, dir2 dan dir3. Dan ketika saya meminta http://<my-ip-address-here>:8080/dir0 saya mendapatkan beranda Google (hanya untuk demo).

Tetapi menambahkan satu segmen /path merusak H20.next.call(env) seperti yang dijelaskan di sini untuk HardenedBSD, FreeBSD.

h2o.conf rusak:

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"

Saya sekarang mendapatkan Kesalahan Server Internal. Dan log kesalahan di Fedora mengatakan:

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

Ini ada di Fedora 31 baru, dengan H2O dibangun dari sumber di b9989220bea9bda30f69083b66166c4c657bdf84 .

Semua 7 komentar

Seperti yang disarankan oleh pesan kesalahan menggunakan H2O.reprocess Saya sekarang mencoba opsi ini. Hasil yang sama: Menambahkan lebih banyak segmen jalur menyebabkan crash 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"

Dengan konfigurasi ini membuka http://test.local/wp-admin di browser memberi saya beranda Google.

Tetapi menambahkan satu segmen jalur lagi, misalnya /dir2 memberi saya kesalahan berikut:

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

Apakah benar-benar ada batas rendah pada jumlah segmen jalur yang diizinkan??? Ini pasti bug. Mungkin sama dengan yang untuk H2O.next .

Karena keduanya, H2O.next dan H20.reprocess tampaknya rusak, saya harus mencari solusi lain. Saya menerapkan penangan proxy terbalik di mruby, mengikuti contoh @kazuho .

Di server pengujian saya ini berfungsi. Saya kemungkinan akan menyebarkannya dalam produksi, segera. Mungkin ini membantu orang lain yang mengalami masalah yang sama dengan metode yang disebutkan di atas:

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

Belum cukup berfungsi:
H2O atau mruby mengubah header CONTENT_TYPE menjadi HTTP_CONTENT_TYPE , yang merusak backend WordPress...

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

Apakah ada cara untuk memaksanya menggunakan hanya CONTENT_TYPE ?

Dan semua ini, hanya karena saya ingin menambahkan /path di h2o.conf saya...

@utrenkner Maaf terlambat. Saya harap https://github.com/h2o/h2o/pull/2254 akan memperbaiki masalah ini. Dengan PR itu H2O.next dan H2O.reprocess bekerja dengan baik menurut saya

H2O atau mruby mengubah header CONTENT_TYPE asli menjadi HTTP_CONTENT_TYPE, yang merusak backend WordPress...

Saya mencoba mruby handler yang sama tetapi tidak dapat mereproduksinya. Maksud saya, saya menelurkan server hulu minimal ( echo -ne "HTTP/1.1 200 OK\r\n\r\n" | nc -l 9000 ) dan melihat header yang dikirim dari h2o. Itu termasuk CONTENT_TYPE , bukan HTTP_CONTENT_TYPE .
BTW jika Anda mengambil pendekatan http_request ini, Anda harus mengonversi garis bawah di kunci hash header menjadi tanda hubung: yaitu, Anda harus mengonversi HTTP_X_FOO menjadi X-FOO , bukan X_FOO . Saya kira ini adalah penyebab masalah itu: implementasi server Anda tidak mengenalinya sebagai header content-type , yang harus diperlakukan secara khusus dalam banyak kasus.

@i110 Terima kasih banyak! Saya akan mencoba patch Anda, besok.

Dan juga terima kasih telah menguji penangan mruby di atas. Memang, saya benar-benar lupa tentang mengubah garis bawah menjadi tanda hubung. Dengan perubahan itu, itu berfungsi sebagaimana dimaksud dan CONTENT_TYPE tetap CONTENT_TYPE !

@i110 Terima kasih banyak! #2254 memecahkan masalah saya dengan H2O.next dan H2O.reprocess . Saya menambahkan lebih banyak lagi segmen /path ke h2o.conf, hanya untuk memeriksa apakah itu benar -

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

voiddeveloper picture voiddeveloper  ·  6Komentar

wujunjenny picture wujunjenny  ·  5Komentar

Ys88 picture Ys88  ·  5Komentar

chenbd picture chenbd  ·  3Komentar

utrenkner picture utrenkner  ·  3Komentar