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.
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:
- no libraries provided as part of Rack is available (only the interface is compatible)
rack.input
is not available
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.
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.
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.
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 mrubymruby-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 mrubymruby-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