H2O

the optimized HTTP/1.x, HTTP/2 server
Powered by Oktavia

Configure > Mruby Directives

mruby is a lightweight implemenation 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
paths:
  "/":
    mruby.handler: |
      Proc.new do |env|
        [200, {'content-type' => 'text/plain'}, ["Hello world\n"]]
      end

It should be noted that as of H2O version 1.5.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.
paths:
  "/":
    mruby.handler: |
      lambda do |env|
        if /^192\.168\./.match(env["REMOTE_ADDR"])
          return [399, {}, []]
        end
        [403, {'content-type' => 'text/plain'}, ["access forbidden\n"]]
      end

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. Pushing asset files
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

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
paths:
  "/":
    mruby.handler: |
      Proc.new do |env|
        headers = {}
        if /\.(css|js)$/.match(env["PATH_INFO"])
          headers["cache-control"] = "max-age=86400"
        end
        [399, headers, []]
      end
    file.dir: /path/to/doc-root

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
paths:
  "/":
    mruby.handler: |
      Proc.new do |env|
        push_paths = []
        # push css and js when request is to dir root or HTML
        if /(\/|\.html)$/.match(env["PATH_INFO"])
          push_paths << "/css/style.css"
          push_paths << "/js/app.js"
        end
        [399, push_paths.empty? ? {} : {"link" => push_paths.map{|p| "<#{p}>; rel=preload"}.join("\n")}, []]
      end
    fastcgi.connect: ...

The following are the configuration directives of the mruby handler.

"mruby.handler"

Description:

Upon start-up evaluates given mruby expression, and uses the returned mruby object to handle the incoming requests.

Example. Hello-world in mruby
mruby.handler: |
  Proc.new do |env|
    [200, {'content-type' => 'text/plain'}, ["Hello world\n"]]
  end

Note that the provided expression is evaluated more than once (typically for every thread that accepts incoming connections).

Level:
path
See also:
mruby.handler-file

"mruby.handler-file"

Description:

Upon start-up evaluates given mruby file, and uses the returned mruby object to handle the incoming requests.

Example. Hello-world in mruby
mruby.handler-file: /path/to/my-mruby-handler.rb

Note that the provided expression is evaluated more than once (typically for every thread that accepts incoming connections).

Level:
path
See also:
mruby.handler