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(req["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 handlers can be used to set Link: rel=preload headers to the response to trigger HTTP/2 server push.

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

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