H2o: H2O.next.call(env) рдореЗрдВ рдмрдЧ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 20 рдЬрдире░ 2020  ┬╖  7рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: h2o/h2o

рдореИрдВ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ "рдмрдЧ" рд░рд┐рдкреЛрд░реНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд░рд┐рд╖реНрдХреГрдд рдХрд░рддрд╛ рд╣реВрдВ, рдХреНрдпреЛрдВрдХрд┐ рдЕрдм рдореИрдВрдиреЗ рдЗрд╕реЗ рдирд╡реАрдирддрдо рд╕реНрд░реЛрддреЛрдВ рдХреЗ рд╕рд╛рде рдлреЗрдбреЛрд░рд╛ рдХреЗ рддрд╣рдд рднреА рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рд╣реИред

рдЗрд╕ рдмрдЧ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП, рдЖрдк рдЗрд╕ 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"

рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ: рдореИрдВ dir1, dir2 рдФрд░ dir3 рдХреЗ рддрд╣рдд рдлрд╛рдЗрд▓реЛрдВ рддрдХ рдкрд╣реБрдВрдЪ рд╕рдХрддрд╛ рд╣реВрдВред рдФрд░ рдЬрдм рдореИрдВ http://<my-ip-address-here>:8080/dir0 рдЕрдиреБрд░реЛрдз рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ Google рд╣реЛрдордкреЗрдЬ рдорд┐рд▓рддрд╛ рд╣реИ (рд╕рд┐рд░реНрдл рдбреЗрдореЛ рдХреЗ рд▓рд┐рдП)ред

рд▓реЗрдХрд┐рди рдПрдХ рдФрд░ /path рд╕реЗрдЧрдореЗрдВрдЯ рдЬреЛрдбрд╝рдиреЗ рд╕реЗ H20.next.call(env) рдЯреВрдЯ рдЬрд╛рддрд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ HardnedBSD , FreeBSD рдХреЗ рд▓рд┐рдП

рдЯреВрдЯрд╛ рд╣реБрдЖ 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)
            # 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"

рдЕрдм рдореБрдЭреЗ рдПрдХ рдЖрдВрддрд░рд┐рдХ рд╕рд░реНрд╡рд░ рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИред рдФрд░ рдлреЗрдбреЛрд░рд╛ рдкрд░ рддреНрд░реБрдЯрд┐ рд▓реЙрдЧ рдХрд╣рддрд╛ рд╣реИ:

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

рдпрд╣ рдПрдХ рддрд╛рдЬрд╛ рдлреЗрдбреЛрд░рд╛ 31 рдкрд░ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ H2O рдХреЛ рд╕реНрд░реЛрдд рд╕реЗ b9989220bea9bda30f69083b66166c4c657bdf84 рдкрд░ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред

рд╕рднреА 7 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдЪреВрдВрдХрд┐ рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдиреЗ H2O.reprocess рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рд╕реБрдЭрд╛рд╡ рджрд┐рдпрд╛ рдерд╛, рдЕрдм рдореИрдВрдиреЗ рдЗрд╕ рд╡рд┐рдХрд▓реНрдк рдХреЛ рдЖрдЬрдорд╛рдпрд╛ рд╣реИред рд╕рдорд╛рди рдкрд░рд┐рдгрд╛рдо: рдЕрдзрд┐рдХ рдкрде-рдЦрдВрдб рдЬреЛрдбрд╝рдиреЗ рд╕реЗ 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"

рдЗрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд╕рд╛рде рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ http://test.local/wp-admin рдЦреЛрд▓рдиреЗ рд╕реЗ рдореБрдЭреЗ Google рд╣реЛрдордкреЗрдЬ рдорд┐рд▓рддрд╛ рд╣реИред

рд▓реЗрдХрд┐рди рдПрдХ рдФрд░ рдкрде рдЦрдВрдб рдЬреЛрдбрд╝рдирд╛, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдЕрддрд┐рд░рд┐рдХреНрдд /dir2 рдореБрдЭреЗ рдирд┐рдореНрди рддреНрд░реБрдЯрд┐ рджреЗрддрд╛ рд╣реИ:

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

рдХреНрдпрд╛ рдЕрдиреБрдордд рдкрде рдЦрдВрдбреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдкрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрддрдиреА рдХрдо рд╕реАрдорд╛ рд╣реИ ??? рдпрд╣ рдПрдХ рдмрдЧ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рд╕рдВрднрд╡рддрдГ H2O.next рдХреЗ рд╕рдорд╛рди рд╣реАред

рдЪреВрдВрдХрд┐ рджреЛрдиреЛрдВ, H2O.next рдФрд░ H20.reprocess рдЯреВрдЯреЗ рд╣реБрдП рдкреНрд░рддреАрдд рд╣реЛрддреЗ рд╣реИрдВ, рдореБрдЭреЗ рдПрдХ рдФрд░ рд╕рдорд╛рдзрд╛рди рддрд▓рд╛рд╢рдирд╛ рдкрдбрд╝рд╛ред рдореИрдВрдиреЗ @kazuho рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рдмрд╛рдж, mruby рдореЗрдВ рдПрдХ рд░рд┐рд╡рд░реНрд╕ рдкреНрд░реЙрдХреНрд╕реА рд╣реИрдВрдбрд▓рд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ред

рдореЗрд░реЗ рдкрд░реАрдХреНрд╖рдг рд╕рд░реНрд╡рд░ рдкрд░ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдореИрдВ рдЗрд╕реЗ рдЬрд▓реНрдж рд╣реА рдЙрддреНрдкрд╛рджрди рдореЗрдВ рддреИрдирд╛рдд рдХрд░реВрдВрдЧрд╛ред рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдХрд┐рд╕реА рдФрд░ рдХреЛ рдЙрдкрд░реНрдпреБрдХреНрдд рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдорд╛рди рд╕рдорд╕реНрдпрд╛рдУрдВ рдореЗрдВ рдЪрд▓рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗ:

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

рдЕрднреА рддрдХ рдХрд╛рдлреА рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИ:
H2O рдпрд╛ mruby рдореВрд▓ CONTENT_TYPE рд╣реЗрдбрд░ рдХреЛ HTTP_CONTENT_TYPE , рдЬреЛ рдПрдХ рд╡рд░реНрдбрдкреНрд░реЗрд╕ рдмреИрдХрдПрдВрдб рдХреЛ рддреЛрдбрд╝ рджреЗрддрд╛ рд╣реИ...

рдЙрджрд╛рд╣рд░рдг:
"CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"
рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ
"HTTP_CONTENT_TYPE"=>"application/x-www-form-urlencoded; charset=UTF-8"

рдХреНрдпрд╛ рдЗрд╕реЗ рдХреЗрд╡рд▓ CONTENT_TYPE рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рд╣реИ?

рдФрд░ рдпрд╣ рд╕рдм, рд╕рд┐рд░реНрдл рдЗрд╕рд▓рд┐рдП рдХрд┐ рдореИрдВ рдЕрдкрдиреЗ h2o.conf рдореЗрдВ рдПрдХ рдФрд░ /path рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛...

@utrenkner рджреЗрд░ рд╕реЗ рдЖрдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд╖рдорд╛ рдХрд░реЗрдВред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ https://github.com/h2o/h2o/pull/2254 рд╕рдорд╕реНрдпрд╛ рдХреЛ рдареАрдХ рдХрд░ рджреЗрдЧрд╛ред рдЙрд╕ рдкреАрдЖрд░ рдХреЗ рд╕рд╛рде H2O.next рдФрд░ H2O.reprocess рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ

H2O рдпрд╛ mruby рдореВрд▓ CONTENT_TYPE рд╣реЗрдбрд░ рдХреЛ HTTP_CONTENT_TYPE рдореЗрдВ рдмрджрд▓ рджреЗрддрд╛ рд╣реИ, рдЬреЛ рд╡рд░реНрдбрдкреНрд░реЗрд╕ рдмреИрдХрдПрдВрдб рдХреЛ рддреЛрдбрд╝ рджреЗрддрд╛ рд╣реИ...

рдореИрдВрдиреЗ рдПрдХ рд╣реА рдореГрдмреА рд╣реИрдВрдбрд▓рд░ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд▓реЗрдХрд┐рди рдЗрд╕реЗ рдкреБрди: рдкреЗрд╢ рдирд╣реАрдВ рдХрд░ рд╕рдХрд╛ред рдореЗрд░рд╛ рдорддрд▓рдм рд╣реИ, рдореИрдВрдиреЗ рдиреНрдпреВрдирддрдо рдЕрдкрд╕реНрдЯреНрд░реАрдо рд╕рд░реНрд╡рд░ ( echo -ne "HTTP/1.1 200 OK\r\n\r\n" | nc -l 9000 ) рдХреЛ рдЬрдиреНрдо рджрд┐рдпрд╛ рдФрд░ h2o рд╕реЗ рднреЗрдЬреЗ рдЧрдП рд╣реЗрдбрд░ рджреЗрдЦреЗрдВред рдЗрд╕рдореЗрдВ CONTENT_TYPE , рди рдХрд┐ HTTP_CONTENT_TYPE ред
BTW рдпрджрд┐ рдЖрдк рдЗрд╕ http_request рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЛ рд▓реЗрддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рд╣реЗрдбрд░ рд╣реИрд╢ рдХреБрдВрдЬрд┐рдпреЛрдВ рдореЗрдВ рдЕрдВрдбрд░рд╕реНрдХреЛрд░ рдХреЛ рд╣рд╛рдЗрдлрд╝рди рдореЗрдВ рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛: рдпрд╛рдиреА, рдЖрдкрдХреЛ HTTP_X_FOO рд╕реЗ X-FOO рдХрдирд╡рд░реНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рди рдХрд┐ X_FOO ред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЙрд╕ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдХрд╛рд░рдг рд╣реИ: рдЖрдкрдХрд╛ рд╕рд░реНрд╡рд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЗрд╕реЗ content-type рд╢реАрд░реНрд╖рд▓реЗрдЦ рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рдкрд╣рдЪрд╛рдирддрд╛ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЗрд▓рд╛рдЬ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рд╣реИред

@ i110 рдмрд╣реБрдд рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж! рдореИрдВ рдХрд▓ рдЖрдкрдХрд╛ рдкреИрдЪ рдЖрдЬрд╝рдорд╛рдЙрдВрдЧрд╛ред

рдФрд░ рдЙрдкрд░реЛрдХреНрдд рдореГрдмреА рд╣реИрдВрдбрд▓рд░ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рднреА рдзрдиреНрдпрд╡рд╛рджред рджрд░рдЕрд╕рд▓, рдореИрдВ рдЕрдВрдбрд░рд╕реНрдХреЛрд░ рдХреЛ рд╣рд╛рдЗрдлрд╝рди рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рднреВрд▓ рдЧрдпрд╛ рдерд╛ред рдЙрд╕ рдкрд░рд┐рд╡рд░реНрддрди рдХреЗ рд╕рд╛рде, рдпрд╣ рдЗрд░рд╛рджрд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ CONTENT_TYPE рд░рд╣рддрд╛ рд╣реИ CONTENT_TYPE !

@i110 рдмрд╣реБрдд-рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж! #2254 H2O.next рдФрд░ H2O.reprocess рджреЛрдиреЛрдВ рдХреЗ рд╕рд╛рде рдореЗрд░реА рд╕рдорд╕реНрдпрд╛рдУрдВ рдХрд╛ рд╕рдорд╛рдзрд╛рди рдХрд░рддрд╛ рд╣реИред рдореИрдВрдиреЗ h2o.conf рдореЗрдВ рдФрд░ рднреА рдЕрдзрд┐рдХ /path рд╕реЗрдЧрдореЗрдВрдЯ рдЬреЛрдбрд╝реЗ, рдмрд╕ рдпрд╣ рдЬрд╛рдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдФрд░, рд╣рд╛рдБ, рдпрд╣ рдХрд░рддрд╛ рд╣реИ!

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕