From be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 04:57:58 +0200 Subject: Adding upstream version 1.44.3. Signed-off-by: Daniel Baumann --- web/server/h2o/libh2o/srcdoc/configure/mruby.mt | 199 ++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 web/server/h2o/libh2o/srcdoc/configure/mruby.mt (limited to 'web/server/h2o/libh2o/srcdoc/configure/mruby.mt') diff --git a/web/server/h2o/libh2o/srcdoc/configure/mruby.mt b/web/server/h2o/libh2o/srcdoc/configure/mruby.mt new file mode 100644 index 00000000..99affa81 --- /dev/null +++ b/web/server/h2o/libh2o/srcdoc/configure/mruby.mt @@ -0,0 +1,199 @@ +? my $ctx = $main::context; +? $_mt->wrapper_file("wrapper.mt", "Configure", "Using Mruby")->(sub { + +

+mruby is a lightweight implementation of the Ruby programming language. +With H2O, users can implement their own request handling logic using mruby, either to generate responses or to fix-up the request / response. +

+ +

Rack-based Programming Interface

+ +

+The interface between the mruby program and the H2O server is based on Rack interface specification. +Below is a simple configuration that returns hello world. +

+ +{example}->('Hello-world in mruby', <<'EOT') +paths: + "/": + mruby.handler: | + Proc.new do |env| + [200, {'content-type' => 'text/plain'}, ["Hello world\n"]] + end +EOT +?> + +

+It should be noted that as of H2O version 1.7.0, there are limitations when compared to ordinary web application server with support for Rack such as Unicorn: +

+

+ +

+In addition to the Rack interface specification, H2O recognizes status code 399 which can be used to delegate request to the next handler. +The feature can be used to implement access control and response header modifiers. +

+ +

Access Control

+ +

+By using the 399 status code, it is possible to implement access control using mruby. +The example below restricts access to requests from 192.168. private address. +

+ +{example}->('Restricting access to 192.168.', <<'EOT') +paths: + "/": + mruby.handler: | + lambda do |env| + if /\A192\.168\./.match(env["REMOTE_ADDR"]) + return [399, {}, []] + end + [403, {'content-type' => 'text/plain'}, ["access forbidden\n"]] + end +EOT +?> + +

+Support for Basic Authentication is also provided by an mruby script. +

+ +

Delegating the Request

+ +

+When enabled using the reproxy directive, it is possible to delegate the request from the mruby handler to any other handler. +

+

+{example}->('Rewriting URL with delegation', <<'EOT') +paths: + "/": + mruby.handler: | + lambda do |env| + if /\/user\/([^\/]+)/.match(env["PATH_INFO"]) + return [307, {"x-reproxy-url" => "/user.php?user=#{$1}"}, []] + end + return [399, {}, []] + end +EOT +?> + +

Modifying the Response

+ +

+When the mruby handler returns status code 399, H2O delegates the request to the next handler while preserving the headers emitted by the handler. +The feature can be used to add extra headers to the response. +

+

+For example, the following example sets cache-control header for requests against .css and .js files. +

+ +{example}->('Setting cache-control header for certain types of files', <<'EOT') +paths: + "/": + mruby.handler: | + Proc.new do |env| + headers = {} + if /\.(css|js)\z/.match(env["PATH_INFO"]) + headers["cache-control"] = "max-age=86400" + end + [399, headers, []] + end + file.dir: /path/to/doc-root +EOT +?> + +

+Or in the example below, the handler triggers HTTP/2 server push with the use of Link: rel=preload headers, and then requests a FastCGI application to process the request. +

+ +{example}->('Pushing asset files', <<'EOT') +paths: + "/": + mruby.handler: | + Proc.new do |env| + push_paths = [] + # push css and js when request is to dir root or HTML + if /(\/|\.html)\z/.match(env["PATH_INFO"]) + push_paths << ["/css/style.css", "style"] + push_paths << ["/js/app.js", "script"] + end + [399, push_paths.empty? ? {} : {"link" => push_paths.map{|p| "<#{p[0]}>; rel=preload; as=#{p[1]}"}.join("\n")}, []] + end + fastcgi.connect: ... +EOT +?> + +

Using the HTTP Client

+ +

+Starting from version 1.7, a HTTP client API is provided. +HTTP requests issued through the API will be handled asynchronously; the client does not block the event loop of the HTTP server. +

+ +{example}->('Mruby handler returning the response of http://example.com', <<'EOT') +paths: + "/": + mruby.handler: | + Proc.new do |env| + req = http_request("http://example.com") + status, headers, body = req.join + [status, headers, body] + end +EOT +?> + +

+http_request is the method that issues a HTTP request. +

+

+The method takes two arguments. +First argument is the target URI. +Second argument is an optional hash; method (defaults to GET), header, body attributes are recognized. +

+

+The method returns a promise object. +When #join method of the promise is invoked, a three-argument array containing the status code, response headers, and the body is returned. +The response body is also a promise. +Applications can choose from three ways when dealing with the body: a) call #each method to receive the contents, b) call #join to retrieve the body as a string, c) return the object as the response body of the mruby handler. +

+

+The header and the body object passed to http_request should conform to the requirements laid out by the Rack specification for request header and request body. +The response header and the response body object returned by the #join method of the promise returned by http_request conforms to the requirements of the Rack specification. +

+

+Since the API provides an asynchronous HTTP client, it is possible to effectively issue multiple HTTP requests concurrently and merge them into a single response. +

+

+When HTTPS is used, servers are verified using the properties of proxy.ssl.cafile and proxy.ssl.verify-peer specified at the global level. +

+ +

Logging Arbitrary Variable

+ +

+In version 2.3, it is possible from mruby to set and log an arbitrary-named variable that is associated to a HTTP request. +A HTTP response header that starts with x-fallthru-set- is handled specially by the H2O server. Instead of sending the header downstream, the server accepts the value as a request environment variable, taking the suffix of the header name as the name of the variable. +

+

+This example shows how to read request data, parse json and then log data from mruby. +

+ +{example}->('Logging the content of a POST request via request environment variable', <<'EOT') +paths: + "/": + mruby.handler: | + Proc.new do |env| + input = env["rack.input"] ? env["rack.input"].read : '{"default": "true"}' + parsed_json = JSON.parse(input) + parsed_json["time"] = Time.now.to_i + logdata = parsed_json.to_s + [204, {"x-fallthru-set-POSTDATA" => logdata}, []] + end + access-log: + path: /path/to/access-log.json + escape: json + format: '{"POST": %{POSTDATA}e}' +EOT +?> + +? }) -- cgit v1.2.3